]> sourceware.org Git - newlib-cygwin.git/blob - winsup/cygwin/path.cc
* Makefile.in: Only build testsuite directory on first 'make check'.
[newlib-cygwin.git] / winsup / cygwin / path.cc
1 /* path.cc: path support.
2
3 Copyright 1996, 1997, 1998, 1999, 2000, 2001 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 <wingdi.h>
61 #include <winuser.h>
62 #include <winnls.h>
63 #include <winnetwk.h>
64 #include <sys/cygwin.h>
65 #include <cygwin/version.h>
66 #include "cygerrno.h"
67 #include "perprocess.h"
68 #include "security.h"
69 #include "fhandler.h"
70 #include "path.h"
71 #include "sync.h"
72 #include "sigproc.h"
73 #include "pinfo.h"
74 #include "dtable.h"
75 #include "cygheap.h"
76 #include "shared_info.h"
77 #include "registry.h"
78 #include <assert.h>
79 #include "shortcut.h"
80
81 #ifdef _MT_SAFE
82 #define iteration _reent_winsup ()->_iteration
83 #define available_drives _reent_winsup ()->available_drives
84 #else
85 static int iteration;
86 static DWORD available_drives;
87 #endif
88
89 static int normalize_win32_path (const char *src, char *dst);
90 static void slashify (const char *src, char *dst, int trailing_slash_p);
91 static void backslashify (const char *src, char *dst, int trailing_slash_p);
92
93 struct symlink_info
94 {
95 char contents[MAX_PATH + 4];
96 char *ext_here;
97 int extn;
98 unsigned pflags;
99 DWORD fileattr;
100 int is_symlink;
101 bool ext_tacked_on;
102 int error;
103 BOOL case_clash;
104 int check (char *path, const suffix_info *suffixes, unsigned opt);
105 BOOL case_check (char *path);
106 };
107
108 int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */
109
110 #define CYGWIN_REGNAME (cygheap->cygwin_regname ?: CYGWIN_INFO_CYGWIN_REGISTRY_NAME)
111
112 /* Determine if path prefix matches current cygdrive */
113 #define iscygdrive(path) \
114 (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
115
116 #define iscygdrive_device(path) \
117 (iscygdrive(path) && isalpha(path[mount_table->cygdrive_len]) && \
118 (isdirsep(path[mount_table->cygdrive_len + 1]) || \
119 !path[mount_table->cygdrive_len + 1]))
120
121 /* Return non-zero if PATH1 is a prefix of PATH2.
122 Both are assumed to be of the same path style and / vs \ usage.
123 Neither may be "".
124 LEN1 = strlen (PATH1). It's passed because often it's already known.
125
126 Examples:
127 /foo/ is a prefix of /foo <-- may seem odd, but desired
128 /foo is a prefix of /foo/
129 / is a prefix of /foo/bar
130 / is not a prefix of foo/bar
131 foo/ is a prefix foo/bar
132 /foo is not a prefix of /foobar
133 */
134
135 int
136 path_prefix_p (const char *path1, const char *path2, int len1)
137 {
138 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
139 if (len1 > 0 && SLASH_P (path1[len1 - 1]))
140 len1--;
141
142 if (len1 == 0)
143 return SLASH_P (path2[0]) && !SLASH_P (path2[1]);
144
145 if (!pathnmatch (path1, path2, len1))
146 return 0;
147
148 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
149 }
150
151 /* Return non-zero if paths match in first len chars.
152 Check is dependent of the case sensitivity setting. */
153 int
154 pathnmatch (const char *path1, const char *path2, int len)
155 {
156 return pcheck_case == PCHECK_STRICT ? !strncmp (path1, path2, len)
157 : strncasematch (path1, path2, len);
158 }
159
160 /* Return non-zero if paths match. Check is dependent of the case
161 sensitivity setting. */
162 int
163 pathmatch (const char *path1, const char *path2)
164 {
165 return pcheck_case == PCHECK_STRICT ? !strcmp (path1, path2)
166 : strcasematch (path1, path2);
167 }
168
169 /* Normalize a POSIX path.
170 \'s are converted to /'s in the process.
171 All duplicate /'s, except for 2 leading /'s, are deleted.
172 The result is 0 for success, or an errno error value. */
173
174 #define isslash(c) ((c) == '/')
175
176 int
177 normalize_posix_path (const char *src, char *dst)
178 {
179 const char *src_start = src;
180 char *dst_start = dst;
181
182 syscall_printf ("src %s", src);
183 if (isdrive (src) || strpbrk (src, "\\:"))
184 {
185 cygwin_conv_to_full_posix_path (src, dst);
186 return 0;
187 }
188 if (!isslash (src[0]))
189 {
190 if (!cygheap->cwd.get (dst))
191 return get_errno ();
192 dst = strchr (dst, '\0');
193 if (*src == '.')
194 {
195 if (dst == dst_start + 1 && *dst_start == '/')
196 --dst;
197 goto sawdot;
198 }
199 if (dst > dst_start && !isslash (dst[-1]))
200 *dst++ = '/';
201 }
202 /* Two leading /'s? If so, preserve them. */
203 else if (isslash (src[1]))
204 {
205 *dst++ = '/';
206 *dst++ = '/';
207 src += 2;
208 if (isslash (*src))
209 { /* Starts with three or more slashes - reset. */
210 dst = dst_start;
211 *dst++ = '/';
212 src = src_start + 1;
213 }
214 else if (src[0] == '.' && isslash (src[1]))
215 {
216 *dst++ = '.';
217 *dst++ = '/';
218 src += 2;
219 }
220 }
221 else
222 *dst = '\0';
223
224 while (*src)
225 {
226 /* Strip runs of /'s. */
227 if (!isslash (*src))
228 *dst++ = *src++;
229 else
230 {
231 while (*++src)
232 {
233 if (isslash (*src))
234 continue;
235
236 if (*src != '.')
237 break;
238
239 sawdot:
240 if (src[1] != '.')
241 {
242 if (!src[1])
243 {
244 if (dst == dst_start)
245 *dst++ = '/';
246 goto done;
247 }
248 if (!isslash (src[1]))
249 break;
250 }
251 else if (src[2] && !isslash (src[2]))
252 break;
253 else
254 {
255 while (dst > dst_start && !isslash (*--dst))
256 continue;
257 src++;
258 }
259 }
260
261 *dst++ = '/';
262 }
263 if ((dst - dst_start) >= MAX_PATH)
264 {
265 debug_printf ("ENAMETOOLONG = normalize_posix_path (%s)", src);
266 return ENAMETOOLONG;
267 }
268 }
269
270 done:
271 *dst = '\0';
272 if (--dst > dst_start && isslash (*dst))
273 *dst = '\0';
274
275 debug_printf ("%s = normalize_posix_path (%s)", dst_start, src_start);
276 return 0;
277 }
278
279 inline void
280 path_conv::add_ext_from_sym (symlink_info &sym)
281 {
282 if (sym.ext_here && *sym.ext_here)
283 {
284 known_suffix = path + sym.extn;
285 if (sym.ext_tacked_on)
286 strcpy (known_suffix, sym.ext_here);
287 }
288 }
289
290 static void __stdcall mkrelpath (char *dst) __attribute__ ((regparm (2)));
291 static void __stdcall
292 mkrelpath (char *path)
293 {
294 char cwd_win32[MAX_PATH];
295 if (!cygheap->cwd.get (cwd_win32, 0))
296 return;
297
298 unsigned cwdlen = strlen (cwd_win32);
299 if (!path_prefix_p (cwd_win32, path, cwdlen))
300 return;
301
302 size_t n = strlen (path);
303 if (n < cwdlen)
304 return;
305
306 char *tail = path;
307 if (n == cwdlen)
308 tail += cwdlen;
309 else
310 tail += isdirsep (cwd_win32[cwdlen - 1]) ? cwdlen : cwdlen + 1;
311
312 memmove (path, tail, strlen (tail) + 1);
313 if (!*path)
314 strcpy (path, ".");
315 }
316
317 void
318 path_conv::update_fs_info (const char* win32_path)
319 {
320 char tmp_buf [MAX_PATH];
321 strncpy (tmp_buf, win32_path, MAX_PATH);
322
323 if (!rootdir (tmp_buf))
324 {
325 debug_printf ("Cannot get root component of path %s", win32_path);
326 root_dir [0] = fs_name [0] = '\0';
327 fs_flags = fs_serial = 0;
328 sym_opt = 0;
329 return;
330 }
331
332 if (strcmp (tmp_buf, root_dir) != 0)
333 {
334 strncpy (root_dir, tmp_buf, MAX_PATH);
335 drive_type = GetDriveType (root_dir);
336 if (drive_type == DRIVE_REMOTE || (drive_type == DRIVE_UNKNOWN && (root_dir[0] == '\\' && root_dir[1] == '\\')))
337 is_remote_drive = 1;
338 else
339 is_remote_drive = 0;
340
341 if (!GetVolumeInformation (root_dir, NULL, 0, &fs_serial, NULL, &fs_flags,
342 fs_name, sizeof (fs_name)))
343 {
344 debug_printf ("Cannot get volume information (%s), %E", root_dir);
345 fs_name [0] = '\0';
346 fs_flags = fs_serial = 0;
347 sym_opt = 0;
348 }
349 else
350 {
351 /* FIXME: Samba by default returns "NTFS" in file system name, but
352 * doesn't support Extended Attributes. If there's some fast way to
353 * distinguish between samba and real ntfs, it should be implemented
354 * here.
355 */
356 sym_opt = (!is_remote_drive && strcmp (fs_name, "NTFS") == 0) ? PC_CHECK_EA : 0;
357 }
358 }
359 }
360
361 /* Convert an arbitrary path SRC to a pure Win32 path, suitable for
362 passing to Win32 API routines.
363
364 If an error occurs, `error' is set to the errno value.
365 Otherwise it is set to 0.
366
367 follow_mode values:
368 SYMLINK_FOLLOW - convert to PATH symlink points to
369 SYMLINK_NOFOLLOW - convert to PATH of symlink itself
370 SYMLINK_IGNORE - do not check PATH for symlinks
371 SYMLINK_CONTENTS - just return symlink contents
372 */
373
374 void
375 path_conv::check (const char *src, unsigned opt,
376 const suffix_info *suffixes)
377 {
378 /* This array is used when expanding symlinks. It is MAX_PATH * 2
379 in length so that we can hold the expanded symlink plus a
380 trailer. */
381 char path_copy[MAX_PATH + 3];
382 char tmp_buf[2 * MAX_PATH + 3];
383 symlink_info sym;
384 bool need_directory = 0;
385 bool saw_symlinks = 0;
386 int is_relpath;
387 sigframe thisframe (mainthread);
388
389 #if 0
390 static path_conv last_path_conv;
391 static char last_src[MAX_PATH + 1];
392
393 if (*last_src && strcmp (last_src, src) == 0)
394 {
395 *this = last_path_conv;
396 return;
397 }
398 #endif
399
400 int loop = 0;
401 path_flags = 0;
402 known_suffix = NULL;
403 fileattr = (DWORD) -1;
404 case_clash = FALSE;
405 devn = unit = 0;
406 root_dir[0] = '\0';
407 fs_name[0] = '\0';
408 fs_flags = fs_serial = 0;
409 sym_opt = 0;
410 drive_type = 0;
411 is_remote_drive = 0;
412
413 if (!(opt & PC_NULLEMPTY))
414 error = 0;
415 else if ((error = check_null_empty_str (src)))
416 return;
417
418 /* This loop handles symlink expansion. */
419 for (;;)
420 {
421 MALLOC_CHECK;
422 assert (src);
423
424 char *p = strrchr (src, '\0');
425 /* Detect if the user was looking for a directory. We have to strip the
426 trailing slash initially and add it back on at the end due to Windows
427 brain damage. */
428 if (--p > src)
429 {
430 if (isdirsep (*p))
431 need_directory = 1;
432 else if (--p > src && p[1] == '.' && isdirsep (*p))
433 need_directory = 1;
434 }
435
436 is_relpath = !isabspath (src);
437 error = normalize_posix_path (src, path_copy);
438 if (error)
439 return;
440
441 char *tail = strchr (path_copy, '\0'); // Point to end of copy
442 char *path_end = tail;
443 tail[1] = '\0';
444
445 /* Scan path_copy from right to left looking either for a symlink
446 or an actual existing file. If an existing file is found, just
447 return. If a symlink is found exit the for loop.
448 Also: be careful to preserve the errno returned from
449 symlink.check as the caller may need it. */
450 /* FIXME: Do we have to worry about multiple \'s here? */
451 int component = 0; // Number of translated components
452 sym.contents[0] = '\0';
453
454 for (;;)
455 {
456 const suffix_info *suff;
457 char pathbuf[MAX_PATH];
458 char *full_path;
459
460 /* Don't allow symlink.check to set anything in the path_conv
461 class if we're working on an inner component of the path */
462 if (component)
463 {
464 suff = NULL;
465 sym.pflags = 0;
466 full_path = pathbuf;
467 }
468 else
469 {
470 suff = suffixes;
471 sym.pflags = path_flags;
472 full_path = this->path;
473 }
474
475 /* Convert to native path spec sans symbolic link info. */
476 error = mount_table->conv_to_win32_path (path_copy, full_path, devn,
477 unit, &sym.pflags, 1);
478
479 if (error)
480 return;
481
482 /* devn should not be a device. If it is, then stop parsing now. */
483 if (devn != FH_BAD)
484 {
485 if (component)
486 {
487 error = ENOTDIR;
488 return;
489 }
490 fileattr = 0;
491 goto out; /* Found a device. Stop parsing. */
492 }
493
494 update_fs_info (full_path);
495
496 /* Eat trailing slashes */
497 char *dostail = strchr (full_path, '\0');
498
499 /* If path is only a drivename, Windows interprets it as the current working
500 directory on this drive instead of the root dir which is what we want. So
501 we need the trailing backslash in this case. */
502 while (dostail > full_path + 3 && (*--dostail == '\\'))
503 *tail = '\0';
504
505 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
506 {
507 full_path[2] = '\\';
508 full_path[3] = '\0';
509 }
510
511 if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED)
512 {
513 fileattr = GetFileAttributesA (full_path);
514 goto out;
515 }
516
517 int len = sym.check (full_path, suff, opt | sym_opt);
518
519 if (sym.case_clash)
520 {
521 if (pcheck_case == PCHECK_STRICT)
522 {
523 case_clash = TRUE;
524 error = ENOENT;
525 goto out;
526 }
527 /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered
528 if the last component is concerned. This allows functions
529 which shall create files to avoid overriding already existing
530 files with another case. */
531 if (!component)
532 case_clash = TRUE;
533 }
534
535 if (!(opt & PC_SYM_IGNORE))
536 {
537 if (!component)
538 path_flags = sym.pflags;
539
540 /* If symlink.check found an existing non-symlink file, then
541 it sets the appropriate flag. It also sets any suffix found
542 into `ext_here'. */
543 if (!sym.is_symlink && sym.fileattr != (DWORD) -1)
544 {
545 error = sym.error;
546 if (component == 0)
547 {
548 fileattr = sym.fileattr;
549 add_ext_from_sym (sym);
550 }
551 if (pcheck_case == PCHECK_RELAXED)
552 goto out; // file found
553 /* Avoid further symlink evaluation. Only case checks are
554 done now. */
555 opt |= PC_SYM_IGNORE;
556 }
557 /* Found a symlink if len > 0. If component == 0, then the
558 src path itself was a symlink. If !follow_mode then
559 we're done. Otherwise we have to insert the path found
560 into the full path that we are building and perform all of
561 these operations again on the newly derived path. */
562 else if (len > 0)
563 {
564 saw_symlinks = 1;
565 if (component == 0 && !need_directory && !(opt & PC_SYM_FOLLOW))
566 {
567 set_symlink (); // last component of path is a symlink.
568 fileattr = sym.fileattr;
569 if (opt & PC_SYM_CONTENTS)
570 {
571 strcpy (path, sym.contents);
572 goto out;
573 }
574 add_ext_from_sym (sym);
575 if (pcheck_case == PCHECK_RELAXED)
576 goto out;
577 /* Avoid further symlink evaluation. Only case checks are
578 done now. */
579 opt |= PC_SYM_IGNORE;
580 }
581 else
582 break;
583 }
584 /* No existing file found. */
585 }
586
587 /* Find the "tail" of the path, e.g. in '/for/bar/baz',
588 /baz is the tail. */
589 char *newtail = strrchr (path_copy, '/');
590 if (tail != path_end)
591 *tail = '/';
592
593 /* Exit loop if there is no tail or we are at the
594 beginning of a UNC path */
595 if (!newtail || newtail == path_copy || (newtail == path_copy + 1 && newtail[-1] == '/'))
596 goto out; // all done
597
598 tail = newtail;
599
600 /* Haven't found an existing pathname component yet.
601 Pinch off the tail and try again. */
602 *tail = '\0';
603 component++;
604 }
605
606 /* Arrive here if above loop detected a symlink. */
607 if (++loop > MAX_LINK_DEPTH)
608 {
609 error = ELOOP; // Eep.
610 return;
611 }
612
613 MALLOC_CHECK;
614
615 /* The tail is pointing at a null pointer. Increment it and get the length.
616 If the tail was empty then this increment will end up pointing to the extra
617 \0 added to path_copy above. */
618 int taillen = strlen (++tail);
619 int buflen = strlen (sym.contents);
620 if (buflen + taillen > MAX_PATH)
621 {
622 error = ENAMETOOLONG;
623 strcpy (path, "::ENAMETOOLONG::");
624 return;
625 }
626
627 /* Strip off current directory component since this is the part that refers
628 to the symbolic link. */
629 if ((p = strrchr (path_copy, '/')) == NULL)
630 p = path_copy;
631 else if (p == path_copy)
632 p++;
633 *p = '\0';
634
635 char *headptr;
636 if (isabspath (sym.contents))
637 headptr = tmp_buf; /* absolute path */
638 else
639 {
640 /* Copy the first part of the path and point to the end. */
641 strcpy (tmp_buf, path_copy);
642 headptr = strchr (tmp_buf, '\0');
643 }
644
645 /* See if we need to separate first part + symlink contents with a / */
646 if (headptr > tmp_buf && headptr[-1] != '/')
647 *headptr++ = '/';
648
649 /* Copy the symlink contents to the end of tmp_buf.
650 Convert slashes. FIXME? */
651 for (p = sym.contents; *p; p++)
652 *headptr++ = *p == '\\' ? '/' : *p;
653
654 /* Copy any tail component */
655 if (tail >= path_end)
656 *headptr = '\0';
657 else
658 {
659 *headptr++ = '/';
660 strcpy (headptr, tail);
661 }
662
663 /* Now evaluate everything all over again. */
664 src = tmp_buf;
665 }
666
667 if (!(opt & PC_SYM_CONTENTS))
668 add_ext_from_sym (sym);
669
670 out:
671 /* Deal with Windows stupidity which considers filename\. to be valid
672 even when "filename" is not a directory. */
673 if (!need_directory || error)
674 /* nothing to do */;
675 else if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
676 path_flags &= ~PATH_SYMLINK;
677 else
678 {
679 debug_printf ("%s is a non-directory", path);
680 error = ENOTDIR;
681 return;
682 }
683
684 if (devn == FH_BAD)
685 {
686 update_fs_info (path);
687 if (!fs_name[0])
688 {
689 set_has_acls (FALSE);
690 set_has_buggy_open (FALSE);
691 }
692 else
693 {
694 set_isdisk ();
695 debug_printf ("root_dir(%s), this->path(%s), set_has_acls(%d)",
696 root_dir, this->path, fs_flags & FS_PERSISTENT_ACLS);
697 if (!allow_smbntsec && is_remote_drive)
698 set_has_acls (FALSE);
699 else
700 set_has_acls (fs_flags & FS_PERSISTENT_ACLS);
701 /* Known file systems with buggy open calls. Further explanation
702 in fhandler.cc (fhandler_disk_file::open). */
703 set_has_buggy_open (strcmp (fs_name, "SUNWNFS") == 0);
704 }
705 }
706 #if 0
707 if (issocket ())
708 devn = FH_SOCKET;
709 #endif
710
711 if (!(opt & PC_FULL))
712 {
713 if (is_relpath)
714 mkrelpath (this->path);
715 if (need_directory)
716 {
717 char n = strlen (this->path);
718 /* Do not add trailing \ to UNC device names like \\.\a: */
719 if (this->path[n - 1] != '\\' &&
720 (strncmp (this->path, "\\\\.\\", 4) != 0 ||
721 !strncasematch (this->path + 4, "unc\\", 4)))
722 {
723 this->path[n] = '\\';
724 this->path[n + 1] = '\0';
725 }
726 }
727 }
728
729 if (saw_symlinks)
730 set_has_symlinks ();
731
732 if (!error && !(path_flags & (PATH_ALL_EXEC | PATH_NOTEXEC)))
733 {
734 const char *p = strchr (path, '\0') - 4;
735 if (p >= path &&
736 (strcasematch (".exe", p) ||
737 strcasematch (".bat", p) ||
738 strcasematch (".com", p)))
739 path_flags |= PATH_EXEC;
740 }
741
742 #if 0
743 if (!error)
744 {
745 last_path_conv = *this;
746 strcpy (last_src, src);
747 }
748 #endif
749 }
750
751 static __inline int
752 digits (const char *name)
753 {
754 char *p;
755 int n = strtol(name, &p, 10);
756
757 return p > name && !*p ? n : -1;
758 }
759
760 const char *windows_device_names[] NO_COPY =
761 {
762 NULL,
763 "\\dev\\console",
764 "conin",
765 "conout",
766 "\\dev\\ttym",
767 "\\dev\\tty%d",
768 "\\dev\\ptym",
769 "\\\\.\\com%d",
770 "\\dev\\pipe",
771 "\\dev\\piper",
772 "\\dev\\pipew",
773 "\\dev\\socket",
774 "\\dev\\windows",
775
776 NULL, NULL, NULL,
777
778 "\\dev\\disk",
779 "\\dev\\fd%d",
780 "\\dev\\st%d",
781 "nul",
782 "\\dev\\zero",
783 "\\dev\\%srandom",
784 "\\dev\\mem",
785 "\\dev\\clipboard",
786 "\\dev\\dsp"
787 };
788
789 #define deveq(s) (strcasematch (name, (s)))
790 #define deveqn(s, n) (strncasematch (name, (s), (n)))
791 #define wdeveq(s) (strcasematch (w32_path, (s)))
792 #define wdeveqn(s, n) (strncasematch (w32_path, (s), (n)))
793 #define udeveq(s) (strcasematch (unix_path, (s)))
794 #define udeveqn(s, n) (strncasematch (unix_path, (s), (n)))
795
796 static int __stdcall
797 get_devn (const char *name, int &unit)
798 {
799 int devn = FH_BAD;
800 name += 5;
801 if (deveq ("tty"))
802 {
803 if (real_tty_attached (myself))
804 {
805 unit = myself->ctty;
806 devn = FH_TTYS;
807 }
808 else if (myself->ctty > 0)
809 devn = FH_CONSOLE;
810 }
811 else if (deveqn ("tty", 3) && (unit = digits (name + 3)) >= 0)
812 devn = FH_TTYS;
813 else if (deveq ("ttym"))
814 devn = FH_TTYM;
815 else if (deveq ("ptmx"))
816 devn = FH_PTYM;
817 else if (deveq ("windows"))
818 devn = FH_WINDOWS;
819 else if (deveq ("dsp"))
820 devn = FH_OSS_DSP;
821 else if (deveq ("conin"))
822 devn = FH_CONIN;
823 else if (deveq ("conout"))
824 devn = FH_CONOUT;
825 else if (deveq ("null"))
826 devn = FH_NULL;
827 else if (deveq ("zero"))
828 devn = FH_ZERO;
829 else if (deveq ("random") || deveq ("urandom"))
830 {
831 devn = FH_RANDOM;
832 unit = 8 + (deveqn ("u", 1) ? 1 : 0); /* Keep unit Linux conformant */
833 }
834 else if (deveq ("mem"))
835 {
836 devn = FH_MEM;
837 unit = 1;
838 }
839 else if (deveq ("clipboard"))
840 devn = FH_CLIPBOARD;
841 else if (deveq ("port"))
842 {
843 devn = FH_MEM;
844 unit = 4;
845 }
846 else if (deveqn ("com", 3) && (unit = digits (name + 3)) >= 0)
847 devn = FH_SERIAL;
848 else if (deveqn ("ttyS", 4) && (unit = digits (name + 4)) >= 0)
849 devn = FH_SERIAL;
850 else if (deveq ("pipe") || deveq ("piper") || deveq ("pipew"))
851 devn = FH_PIPE;
852 else if (deveq ("tcp") || deveq ("udp") || deveq ("streamsocket")
853 || deveq ("dgsocket"))
854 devn = FH_SOCKET;
855
856 return devn;
857 }
858
859 /*
860 major minor POSIX filename NT filename
861 ----- ----- -------------- -------------------------
862 FH_TAPE 0 /dev/st0 \device\tape0
863 FH_TAPE 1 /dev/st1 \device\tape1
864 ...
865 FH_TAPE 128 /dev/nst0 \device\tape0
866 FH_TAPE 129 /dev/nst1 \device\tape1
867 ...
868
869 FH_FLOPPY 0 /dev/fd0 \device\floppy0
870 FH_FLOPPY 1 /dev/fd1 \device\floppy1
871 ...
872
873 FH_FLOPPY 16 /dev/scd0 \device\cdrom0
874 FH_FLOPPY 17 /dev/scd0 \device\cdrom1
875 ...
876
877 FH_FLOPPY 32 /dev/sda \device\harddisk0\partition0
878 FH_FLOPPY 33 /dev/sda1 \device\harddisk0\partition1
879 ...
880 FH_FLOPPY 47 /dev/sda15 \device\harddisk0\partition15
881
882 FH_FLOPPY 48 /dev/sdb \device\harddisk1\partition0
883 FH_FLOPPY 33 /dev/sdb1 \device\harddisk1\partition1
884 ...
885 FH_FLOPPY 208 /dev/sdl \device\harddisk11\partition0
886 ...
887 FH_FLOPPY 223 /dev/sdl15 \device\harddisk11\partition15
888
889 The following are needed to maintain backward compatibility with
890 the old Win32 partitioning scheme on W2K/XP.
891
892 FH_FLOPPY 224 from mount tab \\.\A:
893 ...
894 FH_FLOPPY 250 from mount tab \\.\Z:
895 */
896 static int
897 get_raw_device_number (const char *name, const char *w32_path, int &unit)
898 {
899 DWORD devn = FH_BAD;
900
901 if (!w32_path) /* New approach using fixed device names. */
902 {
903 if (deveqn ("st", 2))
904 {
905 unit = digits (name + 2);
906 if (unit >= 0 && unit < 128)
907 devn = FH_TAPE;
908 }
909 else if (deveqn ("nst", 3))
910 {
911 unit = digits (name + 3) + 128;
912 if (unit >= 128 && unit < 256)
913 devn = FH_TAPE;
914 }
915 else if (deveqn ("fd", 2))
916 {
917 unit = digits (name + 2);
918 if (unit >= 0 && unit < 16)
919 devn = FH_FLOPPY;
920 }
921 else if (deveqn ("scd", 3))
922 {
923 unit = digits (name + 3) + 16;
924 if (unit >= 16 && unit < 32)
925 devn = FH_FLOPPY;
926 }
927 else if (deveqn ("sd", 2) && isalpha (name[2]))
928 {
929 unit = (cyg_tolower (name[2]) - 'a') * 16 + 32;
930 if (unit >= 32 && unit < 224)
931 if (!name[3])
932 devn = FH_FLOPPY;
933 else
934 {
935 int d = digits (name + 3);
936 if (d >= 1 && d < 16)
937 {
938 unit += d;
939 devn = FH_FLOPPY;
940 }
941 }
942 }
943 }
944 else /* Backward compatible checking of mount table device mapping. */
945 {
946 if (wdeveqn ("tape", 4))
947 {
948 unit = digits (w32_path + 4);
949 /* Norewind tape devices have leading n in name. */
950 if (deveqn ("n", 1))
951 unit += 128;
952 devn = FH_TAPE;
953 }
954 else if (wdeveqn ("physicaldrive", 13))
955 {
956 unit = digits (w32_path + 13) * 16 + 32;
957 devn = FH_FLOPPY;
958 }
959 else if (isdrive (w32_path))
960 {
961 unit = cyg_tolower (w32_path[0]) - 'a' + 224;
962 devn = FH_FLOPPY;
963 }
964 }
965 return devn;
966 }
967
968 static int __stdcall get_device_number (const char *unix_path,
969 const char *w32_path, int &unit)
970 __attribute__ ((regparm(3)));
971 static int __stdcall
972 get_device_number (const char *unix_path, const char *w32_path, int &unit)
973 {
974 DWORD devn = FH_BAD;
975 unit = 0;
976
977 if (*unix_path == '/' && udeveqn ("/dev/", 5))
978 {
979 devn = get_devn (unix_path, unit);
980 if (devn == FH_BAD && *w32_path == '\\' && wdeveqn ("\\dev\\", 5))
981 devn = get_devn (w32_path, unit);
982 if (devn == FH_BAD && udeveqn ("com", 3)
983 && (unit = digits (unix_path + 3)) >= 0)
984 devn = FH_SERIAL;
985 if (devn == FH_BAD && wdeveqn ("\\\\.\\", 4))
986 devn = get_raw_device_number (unix_path + 5, w32_path + 4, unit);
987 if (devn == FH_BAD)
988 devn = get_raw_device_number (unix_path + 5, NULL, unit);
989 }
990 return devn;
991 }
992
993 /* Return TRUE if src_path is a Win32 device name, filling out the device
994 name in win32_path */
995
996 static BOOL
997 win32_device_name (const char *src_path, char *win32_path,
998 DWORD &devn, int &unit)
999 {
1000 const char *devfmt;
1001
1002 devn = get_device_number (src_path, win32_path, unit);
1003
1004 if (devn == FH_BAD)
1005 return FALSE;
1006
1007 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
1008 return FALSE;
1009 switch (devn)
1010 {
1011 case FH_RANDOM:
1012 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
1013 break;
1014 case FH_TAPE:
1015 __small_sprintf (win32_path, "\\Device\\Tape%d", unit % 128);
1016 break;
1017 case FH_FLOPPY:
1018 if (unit < 16)
1019 __small_sprintf (win32_path, "\\Device\\Floppy%d", unit);
1020 else if (unit < 32)
1021 __small_sprintf (win32_path, "\\Device\\CdRom%d", unit - 16);
1022 else if (unit < 224)
1023 __small_sprintf (win32_path, "\\Device\\Harddisk%d\\Partition%d",
1024 (unit - 32) / 16, unit % 16);
1025 else
1026 __small_sprintf (win32_path, "\\DosDevices\\%c:", unit - 224 + 'A');
1027 break;
1028 default:
1029 __small_sprintf (win32_path, devfmt, unit);
1030 break;
1031 }
1032 return TRUE;
1033 }
1034
1035 /* Normalize a Win32 path.
1036 /'s are converted to \'s in the process.
1037 All duplicate \'s, except for 2 leading \'s, are deleted.
1038
1039 The result is 0 for success, or an errno error value.
1040 FIXME: A lot of this should be mergeable with the POSIX critter. */
1041 static int
1042 normalize_win32_path (const char *src, char *dst)
1043 {
1044 const char *src_start = src;
1045 char *dst_start = dst;
1046 char *dst_root_start = dst;
1047 bool beg_src_slash = isdirsep (src[0]);
1048
1049 if (beg_src_slash && isdirsep (src[1]))
1050 {
1051 *dst++ = '\\';
1052 src++;
1053 if (src[1] == '.' && isdirsep (src[2]))
1054 {
1055 *dst++ = '\\';
1056 *dst++ = '.';
1057 src += 2;
1058 }
1059 }
1060 else if (strchr (src, ':') == NULL && *src != '/')
1061 {
1062 if (!cygheap->cwd.get (dst, 0))
1063 return get_errno ();
1064 if (beg_src_slash)
1065 {
1066 if (dst[1] == ':')
1067 dst[2] = '\0';
1068 else if (slash_unc_prefix_p (dst))
1069 {
1070 char *p = strpbrk (dst + 2, "\\/");
1071 if (p && (p = strpbrk (p + 1, "\\/")))
1072 *p = '\0';
1073 }
1074 }
1075 if (strlen (dst) + 1 + strlen (src) >= MAX_PATH)
1076 {
1077 debug_printf ("ENAMETOOLONG = normalize_win32_path (%s)", src);
1078 return ENAMETOOLONG;
1079 }
1080 dst += strlen (dst);
1081 if (!beg_src_slash)
1082 *dst++ = '\\';
1083 }
1084
1085 while (*src)
1086 {
1087 /* Strip duplicate /'s. */
1088 if (SLASH_P (src[0]) && SLASH_P (src[1]))
1089 src++;
1090 /* Ignore "./". */
1091 else if (src[0] == '.' && SLASH_P (src[1])
1092 && (src == src_start || SLASH_P (src[-1])))
1093 src += 2;
1094
1095 /* Backup if "..". */
1096 else if (src[0] == '.' && src[1] == '.'
1097 /* dst must be greater than dst_start */
1098 && dst[-1] == '\\'
1099 && (SLASH_P (src[2]) || src[2] == 0))
1100 {
1101 /* Back up over /, but not if it's the first one. */
1102 if (dst > dst_root_start + 1)
1103 dst--;
1104 /* Now back up to the next /. */
1105 while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
1106 dst--;
1107 src += 2;
1108 if (SLASH_P (*src))
1109 src++;
1110 }
1111 /* Otherwise, add char to result. */
1112 else
1113 {
1114 if (*src == '/')
1115 *dst++ = '\\';
1116 else
1117 *dst++ = *src;
1118 ++src;
1119 }
1120 if ((dst - dst_start) >= MAX_PATH)
1121 return ENAMETOOLONG;
1122 }
1123 *dst = 0;
1124 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
1125 return 0;
1126 }
1127
1128 /* Various utilities. */
1129
1130 /* slashify: Convert all back slashes in src path to forward slashes
1131 in dst path. Add a trailing slash to dst when trailing_slash_p arg
1132 is set to 1. */
1133
1134 static void
1135 slashify (const char *src, char *dst, int trailing_slash_p)
1136 {
1137 const char *start = src;
1138
1139 while (*src)
1140 {
1141 if (*src == '\\')
1142 *dst++ = '/';
1143 else
1144 *dst++ = *src;
1145 ++src;
1146 }
1147 if (trailing_slash_p
1148 && src > start
1149 && !isdirsep (src[-1]))
1150 *dst++ = '/';
1151 *dst++ = 0;
1152 }
1153
1154 /* backslashify: Convert all forward slashes in src path to back slashes
1155 in dst path. Add a trailing slash to dst when trailing_slash_p arg
1156 is set to 1. */
1157
1158 static void
1159 backslashify (const char *src, char *dst, int trailing_slash_p)
1160 {
1161 const char *start = src;
1162
1163 while (*src)
1164 {
1165 if (*src == '/')
1166 *dst++ = '\\';
1167 else
1168 *dst++ = *src;
1169 ++src;
1170 }
1171 if (trailing_slash_p
1172 && src > start
1173 && !isdirsep (src[-1]))
1174 *dst++ = '\\';
1175 *dst++ = 0;
1176 }
1177
1178 /* nofinalslash: Remove trailing / and \ from SRC (except for the
1179 first one). It is ok for src == dst. */
1180
1181 void __stdcall
1182 nofinalslash (const char *src, char *dst)
1183 {
1184 int len = strlen (src);
1185 if (src != dst)
1186 memcpy (dst, src, len + 1);
1187 while (len > 1 && SLASH_P (dst[--len]))
1188 dst[len] = '\0';
1189 }
1190
1191 /* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
1192
1193 int __stdcall
1194 slash_unc_prefix_p (const char *path)
1195 {
1196 char *p = NULL;
1197 int ret = (isdirsep (path[0])
1198 && isdirsep (path[1])
1199 && isalpha (path[2])
1200 && path[3] != 0
1201 && !isdirsep (path[3])
1202 && ((p = strpbrk(path + 3, "\\/")) != NULL));
1203 if (!ret || p == NULL)
1204 return ret;
1205 return ret && isalnum (p[1]);
1206 }
1207
1208 /* conv_path_list: Convert a list of path names to/from Win32/POSIX.
1209
1210 SRC is not a const char * because we temporarily modify it to ease
1211 the implementation.
1212
1213 I believe Win32 always has '.' in $PATH. POSIX obviously doesn't.
1214 We certainly don't want to handle that here, but it is something for
1215 the caller to think about. */
1216
1217 static void
1218 conv_path_list (const char *src, char *dst, int to_posix_p)
1219 {
1220 char *s;
1221 char *d = dst;
1222 char src_delim = to_posix_p ? ';' : ':';
1223 char dst_delim = to_posix_p ? ':' : ';';
1224 int (*conv_fn) (const char *, char *) = (to_posix_p
1225 ? cygwin_conv_to_posix_path
1226 : cygwin_conv_to_win32_path);
1227
1228 do
1229 {
1230 s = strchr (src, src_delim);
1231 if (s)
1232 {
1233 *s = 0;
1234 (*conv_fn) (src[0] != 0 ? src : ".", d);
1235 d += strlen (d);
1236 *d++ = dst_delim;
1237 *s = src_delim;
1238 src = s + 1;
1239 }
1240 else
1241 {
1242 /* Last one. */
1243 (*conv_fn) (src[0] != 0 ? src : ".", d);
1244 }
1245 }
1246 while (s != NULL);
1247 }
1248
1249 /* init: Initialize the mount table. */
1250
1251 void
1252 mount_info::init ()
1253 {
1254 nmounts = 0;
1255 had_to_create_mount_areas = 0;
1256
1257 /* Fetch the mount table and cygdrive-related information from
1258 the registry. */
1259 from_registry ();
1260 }
1261
1262 /* conv_to_win32_path: Ensure src_path is a pure Win32 path and store
1263 the result in win32_path.
1264
1265 If win32_path != NULL, the relative path, if possible to keep, is
1266 stored in win32_path. If the relative path isn't possible to keep,
1267 the full path is stored.
1268
1269 If full_win32_path != NULL, the full path is stored there.
1270
1271 The result is zero for success, or an errno value.
1272
1273 {,full_}win32_path must have sufficient space (i.e. MAX_PATH bytes). */
1274
1275 int
1276 mount_info::conv_to_win32_path (const char *src_path, char *dst,
1277 DWORD &devn, int &unit, unsigned *flags,
1278 bool no_normalize)
1279 {
1280 while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter)
1281 {
1282 init ();
1283 sys_mount_table_counter++;
1284 }
1285 int src_path_len = strlen (src_path);
1286 MALLOC_CHECK;
1287 unsigned dummy_flags;
1288 int chroot_ok = !cygheap->root.exists ();
1289
1290 devn = FH_BAD;
1291 unit = 0;
1292
1293 if (!flags)
1294 flags = &dummy_flags;
1295
1296 *flags = 0;
1297 debug_printf ("conv_to_win32_path (%s)", src_path);
1298
1299 if (src_path_len >= MAX_PATH)
1300 {
1301 debug_printf ("ENAMETOOLONG = conv_to_win32_path (%s)", src_path);
1302 return ENAMETOOLONG;
1303 }
1304
1305 int i, rc;
1306 mount_item *mi = NULL; /* initialized to avoid compiler warning */
1307 char pathbuf[MAX_PATH];
1308
1309 if (dst == NULL)
1310 goto out; /* Sanity check. */
1311
1312 /* An MS-DOS spec has either a : or a \. If this is found, short
1313 circuit most of the rest of this function. */
1314 if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path))
1315 {
1316 debug_printf ("%s already win32", src_path);
1317 rc = normalize_win32_path (src_path, dst);
1318 if (rc)
1319 {
1320 debug_printf ("normalize_win32_path failed, rc %d", rc);
1321 return rc;
1322 }
1323
1324 *flags = set_flags_from_win32_path (dst);
1325 goto out;
1326 }
1327
1328 /* Normalize the path, taking out ../../ stuff, we need to do this
1329 so that we can move from one mounted directory to another with relative
1330 stuff.
1331
1332 eg mounting c:/foo /foo
1333 d:/bar /bar
1334
1335 cd /bar
1336 ls ../foo
1337
1338 should look in c:/foo, not d:/foo.
1339
1340 We do this by first getting an absolute UNIX-style path and then
1341 converting it to a DOS-style path, looking up the appropriate drive
1342 in the mount table. */
1343
1344 if (no_normalize)
1345 strcpy (pathbuf, src_path);
1346 else
1347 {
1348 rc = normalize_posix_path (src_path, pathbuf);
1349
1350 if (rc)
1351 {
1352 debug_printf ("%d = conv_to_win32_path (%s)", rc, src_path);
1353 *flags = 0;
1354 return rc;
1355 }
1356 }
1357
1358 /* See if this is a cygwin "device" */
1359 if (win32_device_name (pathbuf, dst, devn, unit))
1360 {
1361 *flags = MOUNT_BINARY; /* FIXME: Is this a sensible default for devices? */
1362 rc = 0;
1363 goto out_no_chroot_check;
1364 }
1365
1366 /* Check if the cygdrive prefix was specified. If so, just strip
1367 off the prefix and transform it into an MS-DOS path. */
1368 MALLOC_CHECK;
1369 if (iscygdrive_device (pathbuf))
1370 {
1371 if (!cygdrive_win32_path (pathbuf, dst, 0))
1372 return ENOENT;
1373 *flags = cygdrive_flags;
1374 goto out;
1375 }
1376
1377 int chrooted_path_len;
1378 chrooted_path_len = 0;
1379 /* Check the mount table for prefix matches. */
1380 for (i = 0; i < nmounts; i++)
1381 {
1382 const char *path;
1383 int len;
1384
1385 mi = mount + posix_sorted[i];
1386 if (!cygheap->root.exists ()
1387 || (mi->posix_pathlen == 1 && mi->posix_path[0] == '/'))
1388 {
1389 path = mi->posix_path;
1390 len = mi->posix_pathlen;
1391 }
1392 else if (cygheap->root.posix_ok (mi->posix_path))
1393 {
1394 path = cygheap->root.unchroot (mi->posix_path);
1395 chrooted_path_len = len = strlen (path);
1396 }
1397 else
1398 {
1399 chrooted_path_len = 0;
1400 continue;
1401 }
1402
1403 if (path_prefix_p (path, pathbuf, len))
1404 break;
1405 }
1406
1407 if (i >= nmounts)
1408 {
1409 backslashify (pathbuf, dst, 0); /* just convert */
1410 *flags = 0;
1411 }
1412 else
1413 {
1414 int n;
1415 const char *native_path;
1416 int posix_pathlen;
1417 if (chroot_ok || chrooted_path_len || mi->posix_pathlen != 1
1418 || mi->posix_path[0] != '/')
1419 {
1420 n = mi->native_pathlen;
1421 native_path = mi->native_path;
1422 posix_pathlen = chrooted_path_len ?: mi->posix_pathlen;
1423 chroot_ok = 1;
1424 }
1425 else
1426 {
1427 n = cygheap->root.native_length ();
1428 native_path = cygheap->root.native_path ();
1429 posix_pathlen = mi->posix_pathlen;
1430 chroot_ok = 1;
1431 }
1432 memcpy (dst, native_path, n + 1);
1433 const char *p = pathbuf + posix_pathlen;
1434 if (*p == '/')
1435 /* nothing */;
1436 else if ((isdrive (dst) && !dst[2]) || *p)
1437 dst[n++] = '\\';
1438 strcpy (dst + n, p);
1439 backslashify (dst, dst, 0);
1440 *flags = mi->flags;
1441 }
1442
1443 win32_device_name (src_path, dst, devn, unit);
1444
1445 out:
1446 MALLOC_CHECK;
1447 if (chroot_ok || cygheap->root.ischroot_native (dst))
1448 rc = 0;
1449 else
1450 {
1451 debug_printf ("attempt to access outside of chroot '%s = %s'",
1452 cygheap->root.posix_path (), cygheap->root.native_path ());
1453 rc = ENOENT;
1454 }
1455
1456 out_no_chroot_check:
1457 debug_printf ("src_path %s, dst %s, flags %p, rc %d", src_path, dst, *flags, rc);
1458 return rc;
1459 }
1460
1461 /* cygdrive_posix_path: Build POSIX path used as the
1462 mount point for cygdrives created when there is no other way to
1463 obtain a POSIX path from a Win32 one. */
1464
1465 void
1466 mount_info::cygdrive_posix_path (const char *src, char *dst, int trailing_slash_p)
1467 {
1468 int len = cygdrive_len;
1469
1470 memcpy (dst, cygdrive, len + 1);
1471
1472 /* Now finish the path off with the drive letter to be used.
1473 The cygdrive prefix always ends with a trailing slash so
1474 the drive letter is added after the path. */
1475 dst[len++] = cyg_tolower (src[0]);
1476 if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1477 dst[len++] = '\000';
1478 else
1479 {
1480 int n;
1481 dst[len++] = '/';
1482 if (SLASH_P (src[2]))
1483 n = 3;
1484 else
1485 n = 2;
1486 strcpy (dst + len, src + n);
1487 }
1488 slashify (dst, dst, trailing_slash_p);
1489 }
1490
1491 int
1492 mount_info::cygdrive_win32_path (const char *src, char *dst, int trailing_slash_p)
1493 {
1494 const char *p = src + cygdrive_len;
1495 if (!isalpha (*p) || (!isdirsep (p[1]) && p[1]))
1496 return 0;
1497 dst[0] = *p;
1498 dst[1] = ':';
1499 strcpy (dst + 2, p + 1);
1500 backslashify (dst, dst, trailing_slash_p || !dst[2]);
1501 debug_printf ("src '%s', dst '%s'", src, dst);
1502 return 1;
1503 }
1504
1505 /* conv_to_posix_path: Ensure src_path is a POSIX path.
1506
1507 The result is zero for success, or an errno value.
1508 posix_path must have sufficient space (i.e. MAX_PATH bytes).
1509 If keep_rel_p is non-zero, relative paths stay that way. */
1510
1511 int
1512 mount_info::conv_to_posix_path (const char *src_path, char *posix_path,
1513 int keep_rel_p)
1514 {
1515 int src_path_len = strlen (src_path);
1516 int relative_path_p = !isabspath (src_path);
1517 int trailing_slash_p;
1518
1519 if (src_path_len <= 1)
1520 trailing_slash_p = 0;
1521 else
1522 {
1523 const char *lastchar = src_path + src_path_len - 1;
1524 trailing_slash_p = SLASH_P (*lastchar) && lastchar[-1] != ':';
1525 }
1526
1527 debug_printf ("conv_to_posix_path (%s, %s, %s)", src_path,
1528 keep_rel_p ? "keep-rel" : "no-keep-rel",
1529 trailing_slash_p ? "add-slash" : "no-add-slash");
1530 MALLOC_CHECK;
1531
1532 if (src_path_len >= MAX_PATH)
1533 {
1534 debug_printf ("ENAMETOOLONG");
1535 return ENAMETOOLONG;
1536 }
1537
1538 /* FIXME: For now, if the path is relative and it's supposed to stay
1539 that way, skip mount table processing. */
1540
1541 if (keep_rel_p && relative_path_p)
1542 {
1543 slashify (src_path, posix_path, 0);
1544 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1545 return 0;
1546 }
1547
1548 char pathbuf[MAX_PATH];
1549 int rc = normalize_win32_path (src_path, pathbuf);
1550 if (rc != 0)
1551 {
1552 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1553 return rc;
1554 }
1555
1556 int pathbuflen = strlen (pathbuf);
1557 for (int i = 0; i < nmounts; ++i)
1558 {
1559 mount_item &mi = mount[native_sorted[i]];
1560 if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1561 continue;
1562
1563 if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path))
1564 continue;
1565
1566 /* SRC_PATH is in the mount table. */
1567 int nextchar;
1568 const char *p = pathbuf + mi.native_pathlen;
1569
1570 if (!*p || !p[1])
1571 nextchar = 0;
1572 else if (isdirsep (*p))
1573 nextchar = -1;
1574 else
1575 nextchar = 1;
1576
1577 int addslash = nextchar > 0 ? 1 : 0;
1578 if ((mi.posix_pathlen + (pathbuflen - mi.native_pathlen) + addslash) >= MAX_PATH)
1579 return ENAMETOOLONG;
1580 strcpy (posix_path, mi.posix_path);
1581 if (addslash)
1582 strcat (posix_path, "/");
1583 if (nextchar)
1584 slashify (p,
1585 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
1586 trailing_slash_p);
1587
1588 if (cygheap->root.exists ())
1589 {
1590 const char *p = cygheap->root.unchroot (posix_path);
1591 memmove (posix_path, p, strlen (p) + 1);
1592 }
1593 goto out;
1594 }
1595
1596 if (!cygheap->root.exists ())
1597 /* nothing */;
1598 else if (cygheap->root.ischroot_native (pathbuf))
1599 {
1600 const char *p = pathbuf + cygheap->root.native_length ();
1601 if (*p)
1602 slashify (p, posix_path, trailing_slash_p);
1603 else
1604 {
1605 posix_path[0] = '/';
1606 posix_path[1] = '\0';
1607 }
1608 }
1609 else
1610 return ENOENT;
1611
1612 /* Not in the database. This should [theoretically] only happen if either
1613 the path begins with //, or / isn't mounted, or the path has a drive
1614 letter not covered by the mount table. If it's a relative path then the
1615 caller must want an absolute path (otherwise we would have returned
1616 above). So we always return an absolute path at this point. */
1617 if (isdrive (pathbuf))
1618 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1619 else
1620 {
1621 /* The use of src_path and not pathbuf here is intentional.
1622 We couldn't translate the path, so just ensure no \'s are present. */
1623 slashify (src_path, posix_path, trailing_slash_p);
1624 }
1625
1626 out:
1627 debug_printf ("%s = conv_to_posix_path (%s)", posix_path, src_path);
1628 MALLOC_CHECK;
1629 return 0;
1630 }
1631
1632 /* Return flags associated with a mount point given the win32 path. */
1633
1634 unsigned
1635 mount_info::set_flags_from_win32_path (const char *p)
1636 {
1637 for (int i = 0; i < nmounts; i++)
1638 {
1639 mount_item &mi = mount[native_sorted[i]];
1640 if (path_prefix_p (mi.native_path, p, mi.native_pathlen))
1641 return mi.flags;
1642 }
1643 return 0;
1644 }
1645
1646 /* read_mounts: Given a specific regkey, read mounts from under its
1647 key. */
1648
1649 void
1650 mount_info::read_mounts (reg_key& r)
1651 {
1652 char posix_path[MAX_PATH];
1653 HKEY key = r.get_key ();
1654 DWORD i, posix_path_size;
1655 int res;
1656
1657 /* Loop through subkeys */
1658 /* FIXME: we would like to not check MAX_MOUNTS but the heap in the
1659 shared area is currently statically allocated so we can't have an
1660 arbitrarily large number of mounts. */
1661 for (i = 0; ; i++)
1662 {
1663 char native_path[MAX_PATH];
1664 int mount_flags;
1665
1666 posix_path_size = MAX_PATH;
1667 /* FIXME: if maximum posix_path_size is 256, we're going to
1668 run into problems if we ever try to store a mount point that's
1669 over 256 but is under MAX_PATH. */
1670 res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1671 NULL, NULL, NULL);
1672
1673 if (res == ERROR_NO_MORE_ITEMS)
1674 break;
1675 else if (res != ERROR_SUCCESS)
1676 {
1677 debug_printf ("RegEnumKeyEx failed, error %d!\n", res);
1678 break;
1679 }
1680
1681 /* Get a reg_key based on i. */
1682 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1683
1684 /* Fetch info from the subkey. */
1685 subkey.get_string ("native", native_path, sizeof (native_path), "");
1686 mount_flags = subkey.get_int ("flags", 0);
1687
1688 /* Add mount_item corresponding to registry mount point. */
1689 res = mount_table->add_item (native_path, posix_path, mount_flags, FALSE);
1690 if (res && get_errno () == EMFILE)
1691 break; /* The number of entries exceeds MAX_MOUNTS */
1692 }
1693 }
1694
1695 /* from_registry: Build the entire mount table from the registry. Also,
1696 read in cygdrive-related information from its registry location. */
1697
1698 void
1699 mount_info::from_registry ()
1700 {
1701 /* Use current mount areas if either user or system mount areas
1702 already exist. Otherwise, import old mounts. */
1703
1704 reg_key r;
1705
1706 /* Retrieve cygdrive-related information. */
1707 read_cygdrive_info_from_registry ();
1708
1709 nmounts = 0;
1710
1711 /* First read mounts from user's table. */
1712 read_mounts (r);
1713
1714 /* Then read mounts from system-wide mount table. */
1715 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1716 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1717 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1718 NULL);
1719 read_mounts (r1);
1720
1721 /* If we had to create both user and system mount areas, import
1722 old mounts. */
1723 if (had_to_create_mount_areas == 2)
1724 import_v1_mounts ();
1725 }
1726
1727 /* add_reg_mount: Add mount item to registry. Return zero on success,
1728 non-zero on failure. */
1729 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1730
1731 int
1732 mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1733 {
1734 int res = 0;
1735
1736 /* Add the mount to the right registry location, depending on
1737 whether MOUNT_SYSTEM is set in the mount flags. */
1738 if (!(mountflags & MOUNT_SYSTEM)) /* current_user mount */
1739 {
1740 /* reg_key for user mounts in HKEY_CURRENT_USER. */
1741 reg_key reg_user;
1742
1743 /* Start by deleting existing mount if one exists. */
1744 res = reg_user.kill (posix_path);
1745 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1746 goto err;
1747
1748 /* Create the new mount. */
1749 reg_key subkey = reg_key (reg_user.get_key (),
1750 KEY_ALL_ACCESS,
1751 posix_path, NULL);
1752 res = subkey.set_string ("native", native_path);
1753 if (res != ERROR_SUCCESS)
1754 goto err;
1755 res = subkey.set_int ("flags", mountflags);
1756 }
1757 else /* local_machine mount */
1758 {
1759 /* reg_key for system mounts in HKEY_LOCAL_MACHINE. */
1760 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1761 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1762 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1763 NULL);
1764
1765 /* Start by deleting existing mount if one exists. */
1766 res = reg_sys.kill (posix_path);
1767 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1768 goto err;
1769
1770 /* Create the new mount. */
1771 reg_key subkey = reg_key (reg_sys.get_key (),
1772 KEY_ALL_ACCESS,
1773 posix_path, NULL);
1774 res = subkey.set_string ("native", native_path);
1775 if (res != ERROR_SUCCESS)
1776 goto err;
1777 res = subkey.set_int ("flags", mountflags);
1778
1779 sys_mount_table_counter++;
1780 cygwin_shared->sys_mount_table_counter++;
1781 }
1782
1783 return 0; /* Success */
1784 err:
1785 __seterrno_from_win_error (res);
1786 return -1;
1787 }
1788
1789 /* del_reg_mount: delete mount item from registry indicated in flags.
1790 Return zero on success, non-zero on failure.*/
1791 /* FIXME: Need a mutex to avoid collisions with other tasks. */
1792
1793 int
1794 mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1795 {
1796 int res;
1797
1798 if (!(flags & MOUNT_SYSTEM)) /* Delete from user registry */
1799 {
1800 reg_key reg_user (KEY_ALL_ACCESS,
1801 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
1802 res = reg_user.kill (posix_path);
1803 }
1804 else /* Delete from system registry */
1805 {
1806 sys_mount_table_counter++;
1807 cygwin_shared->sys_mount_table_counter++;
1808 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
1809 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1810 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1811 NULL);
1812 res = reg_sys.kill (posix_path);
1813 }
1814
1815 if (res != ERROR_SUCCESS)
1816 {
1817 __seterrno_from_win_error (res);
1818 return -1;
1819 }
1820
1821 return 0; /* Success */
1822 }
1823
1824 /* read_cygdrive_info_from_registry: Read the default prefix and flags
1825 to use when creating cygdrives from the special user registry
1826 location used to store cygdrive information. */
1827
1828 void
1829 mount_info::read_cygdrive_info_from_registry ()
1830 {
1831 /* reg_key for user path prefix in HKEY_CURRENT_USER. */
1832 reg_key r;
1833
1834 if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
1835 "") != 0)
1836 {
1837 /* Didn't find the user path prefix so check the system path prefix. */
1838
1839 /* reg_key for system path prefix in HKEY_LOCAL_MACHINE. */
1840 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1841 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1842 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1843 NULL);
1844
1845 if (r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
1846 "") != 0)
1847 {
1848 /* Didn't find either so write the default to the registry and use it.
1849 NOTE: We are writing and using the user path prefix. */
1850 write_cygdrive_info_to_registry (CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX,
1851 MOUNT_AUTO);
1852 }
1853 else
1854 {
1855 /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
1856 error. */
1857 cygdrive_flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
1858 slashify (cygdrive, cygdrive, 1);
1859 cygdrive_len = strlen(cygdrive);
1860 }
1861 }
1862 else
1863 {
1864 /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
1865 error. */
1866 cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
1867 slashify (cygdrive, cygdrive, 1);
1868 cygdrive_len = strlen(cygdrive);
1869 }
1870 }
1871
1872 /* write_cygdrive_info_to_registry: Write the default prefix and flags
1873 to use when creating cygdrives to the special user registry
1874 location used to store cygdrive information. */
1875
1876 int
1877 mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1878 {
1879 /* Determine whether to modify user or system cygdrive path prefix. */
1880 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1881
1882 if (flags & MOUNT_SYSTEM)
1883 {
1884 sys_mount_table_counter++;
1885 cygwin_shared->sys_mount_table_counter++;
1886 }
1887
1888 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1889 HKEY_LOCAL_MACHINE. */
1890 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1891 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1892 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1893 NULL);
1894
1895 /* Verify cygdrive prefix starts with a forward slash and if there's
1896 another character, it's not a slash. */
1897 if ((cygdrive_prefix == NULL) || (*cygdrive_prefix == 0) ||
1898 (!isslash (cygdrive_prefix[0])) ||
1899 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1900 {
1901 set_errno (EINVAL);
1902 return -1;
1903 }
1904
1905 char hold_cygdrive_prefix[strlen (cygdrive_prefix) + 1];
1906 /* Ensure that there is never a final slash */
1907 nofinalslash (cygdrive_prefix, hold_cygdrive_prefix);
1908
1909 int res;
1910 res = r.set_string (CYGWIN_INFO_CYGDRIVE_PREFIX, hold_cygdrive_prefix);
1911 if (res != ERROR_SUCCESS)
1912 {
1913 __seterrno_from_win_error (res);
1914 return -1;
1915 }
1916 r.set_int (CYGWIN_INFO_CYGDRIVE_FLAGS, flags);
1917
1918 /* This also needs to go in the in-memory copy of "cygdrive", but only if
1919 appropriate:
1920 1. setting user path prefix, or
1921 2. overwriting (a previous) system path prefix */
1922 if (!(flags & MOUNT_SYSTEM) || (mount_table->cygdrive_flags & MOUNT_SYSTEM))
1923 {
1924 slashify (cygdrive_prefix, mount_table->cygdrive, 1);
1925 mount_table->cygdrive_flags = flags;
1926 mount_table->cygdrive_len = strlen(mount_table->cygdrive);
1927 }
1928
1929 return 0;
1930 }
1931
1932 int
1933 mount_info::remove_cygdrive_info_from_registry (const char *cygdrive_prefix, unsigned flags)
1934 {
1935 /* Determine whether to modify user or system cygdrive path prefix. */
1936 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1937
1938 if (flags & MOUNT_SYSTEM)
1939 {
1940 sys_mount_table_counter++;
1941 cygwin_shared->sys_mount_table_counter++;
1942 }
1943
1944 /* reg_key for user path prefix in HKEY_CURRENT_USER or system path prefix in
1945 HKEY_LOCAL_MACHINE. */
1946 reg_key r (top, KEY_ALL_ACCESS, "SOFTWARE",
1947 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1948 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1949 NULL);
1950
1951 /* Delete cygdrive prefix and flags. */
1952 int res = r.killvalue (CYGWIN_INFO_CYGDRIVE_PREFIX);
1953 int res2 = r.killvalue (CYGWIN_INFO_CYGDRIVE_FLAGS);
1954
1955 /* Reinitialize the cygdrive path prefix to reflect to removal from the
1956 registry. */
1957 read_cygdrive_info_from_registry ();
1958
1959 return (res != ERROR_SUCCESS) ? res : res2;
1960 }
1961
1962 int
1963 mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
1964 char* system_flags)
1965 {
1966 /* Get the user path prefix from HKEY_CURRENT_USER. */
1967 reg_key r;
1968 int res = r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, user, MAX_PATH, "");
1969
1970 /* Get the user flags, if appropriate */
1971 if (res == ERROR_SUCCESS)
1972 {
1973 int flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
1974 strcpy (user_flags, (flags & MOUNT_BINARY) ? "binmode" : "textmode");
1975 }
1976
1977 /* Get the system path prefix from HKEY_LOCAL_MACHINE. */
1978 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
1979 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1980 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1981 NULL);
1982 int res2 = r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, system, MAX_PATH, "");
1983
1984 /* Get the system flags, if appropriate */
1985 if (res2 == ERROR_SUCCESS)
1986 {
1987 int flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
1988 strcpy (system_flags, (flags & MOUNT_BINARY) ? "binmode" : "textmode");
1989 }
1990
1991 return (res != ERROR_SUCCESS) ? res : res2;
1992 }
1993
1994 static mount_item *mounts_for_sort;
1995
1996 /* sort_by_posix_name: qsort callback to sort the mount entries. Sort
1997 user mounts ahead of system mounts to the same POSIX path. */
1998 /* FIXME: should the user should be able to choose whether to
1999 prefer user or system mounts??? */
2000 static int
2001 sort_by_posix_name (const void *a, const void *b)
2002 {
2003 mount_item *ap = mounts_for_sort + (*((int*) a));
2004 mount_item *bp = mounts_for_sort + (*((int*) b));
2005
2006 /* Base weighting on longest posix path first so that the most
2007 obvious path will be chosen. */
2008 size_t alen = strlen (ap->posix_path);
2009 size_t blen = strlen (bp->posix_path);
2010
2011 int res = blen - alen;
2012
2013 if (res)
2014 return res; /* Path lengths differed */
2015
2016 /* The two paths were the same length, so just determine normal
2017 lexical sorted order. */
2018 res = strcmp (ap->posix_path, bp->posix_path);
2019
2020 if (res == 0)
2021 {
2022 /* need to select between user and system mount to same POSIX path */
2023 if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */
2024 return 1;
2025 else
2026 return -1;
2027 }
2028
2029 return res;
2030 }
2031
2032 /* sort_by_native_name: qsort callback to sort the mount entries. Sort
2033 user mounts ahead of system mounts to the same POSIX path. */
2034 /* FIXME: should the user should be able to choose whether to
2035 prefer user or system mounts??? */
2036 static int
2037 sort_by_native_name (const void *a, const void *b)
2038 {
2039 mount_item *ap = mounts_for_sort + (*((int*) a));
2040 mount_item *bp = mounts_for_sort + (*((int*) b));
2041
2042 /* Base weighting on longest win32 path first so that the most
2043 obvious path will be chosen. */
2044 size_t alen = strlen (ap->native_path);
2045 size_t blen = strlen (bp->native_path);
2046
2047 int res = blen - alen;
2048
2049 if (res)
2050 return res; /* Path lengths differed */
2051
2052 /* The two paths were the same length, so just determine normal
2053 lexical sorted order. */
2054 res = strcmp (ap->native_path, bp->native_path);
2055
2056 if (res == 0)
2057 {
2058 /* need to select between user and system mount to same POSIX path */
2059 if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */
2060 return 1;
2061 else
2062 return -1;
2063 }
2064
2065 return res;
2066 }
2067
2068 void
2069 mount_info::sort ()
2070 {
2071 for (int i = 0; i < nmounts; i++)
2072 native_sorted[i] = posix_sorted[i] = i;
2073 /* Sort them into reverse length order, otherwise we won't
2074 be able to look for /foo in /. */
2075 mounts_for_sort = mount; /* ouch. */
2076 qsort (posix_sorted, nmounts, sizeof (posix_sorted[0]), sort_by_posix_name);
2077 qsort (native_sorted, nmounts, sizeof (native_sorted[0]), sort_by_native_name);
2078 }
2079
2080 /* Add an entry to the mount table.
2081 Returns 0 on success, -1 on failure and errno is set.
2082
2083 This is where all argument validation is done. It may not make sense to
2084 do this when called internally, but it's cleaner to keep it all here. */
2085
2086 int
2087 mount_info::add_item (const char *native, const char *posix, unsigned mountflags, int reg_p)
2088 {
2089 /* Something's wrong if either path is NULL or empty, or if it's
2090 not a UNC or absolute path. */
2091
2092 if ((native == NULL) || (*native == 0) ||
2093 (posix == NULL) || (*posix == 0) ||
2094 !isabspath (native) || !isabspath (posix) ||
2095 slash_unc_prefix_p (posix) || isdrive (posix))
2096 {
2097 set_errno (EINVAL);
2098 return -1;
2099 }
2100
2101 /* Make sure both paths do not end in /. */
2102 char nativetmp[MAX_PATH];
2103 char posixtmp[MAX_PATH];
2104
2105 backslashify (native, nativetmp, 0);
2106 nofinalslash (nativetmp, nativetmp);
2107
2108 slashify (posix, posixtmp, 0);
2109 nofinalslash (posixtmp, posixtmp);
2110
2111 debug_printf ("%s[%s], %s[%s], %p",
2112 native, nativetmp, posix, posixtmp, mountflags);
2113
2114 /* Duplicate /'s in path are an error. */
2115 for (char *p = posixtmp + 1; *p; ++p)
2116 {
2117 if (p[-1] == '/' && p[0] == '/')
2118 {
2119 set_errno (EINVAL);
2120 return -1;
2121 }
2122 }
2123
2124 /* Write over an existing mount item with the same POSIX path if
2125 it exists and is from the same registry area. */
2126 int i;
2127 for (i = 0; i < nmounts; i++)
2128 {
2129 if (strcasematch (mount[i].posix_path, posixtmp) &&
2130 (mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
2131 break;
2132 }
2133
2134 if (i == nmounts && nmounts == MAX_MOUNTS)
2135 {
2136 set_errno (EMFILE);
2137 return -1;
2138 }
2139
2140 if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
2141 return -1;
2142
2143 if (i == nmounts)
2144 nmounts++;
2145 mount[i].init (nativetmp, posixtmp, mountflags);
2146 sort ();
2147
2148 return 0;
2149 }
2150
2151 /* Delete a mount table entry where path is either a Win32 or POSIX
2152 path. Since the mount table is really just a table of aliases,
2153 deleting / is ok (although running without a slash mount is
2154 strongly discouraged because some programs may run erratically
2155 without one). If MOUNT_SYSTEM is set in flags, remove from system
2156 registry, otherwise remove the user registry mount.
2157 */
2158
2159 int
2160 mount_info::del_item (const char *path, unsigned flags, int reg_p)
2161 {
2162 char pathtmp[MAX_PATH];
2163 int posix_path_p = FALSE;
2164
2165 /* Something's wrong if path is NULL or empty. */
2166 if (path == NULL || *path == 0 || !isabspath (path))
2167 {
2168 set_errno (EINVAL);
2169 return -1;
2170 }
2171
2172 if (slash_unc_prefix_p (path) || strpbrk (path, ":\\"))
2173 backslashify (path, pathtmp, 0);
2174 else
2175 {
2176 slashify (path, pathtmp, 0);
2177 posix_path_p = TRUE;
2178 }
2179 nofinalslash (pathtmp, pathtmp);
2180
2181 if (reg_p && posix_path_p &&
2182 del_reg_mount (pathtmp, flags) &&
2183 del_reg_mount (path, flags)) /* for old irregular entries */
2184 return -1;
2185
2186 for (int i = 0; i < nmounts; i++)
2187 {
2188 int ent = native_sorted[i]; /* in the same order as getmntent() */
2189 if (((posix_path_p)
2190 ? strcasematch (mount[ent].posix_path, pathtmp)
2191 : strcasematch (mount[ent].native_path, pathtmp)) &&
2192 (mount[ent].flags & MOUNT_SYSTEM) == (flags & MOUNT_SYSTEM))
2193 {
2194 if (!posix_path_p &&
2195 reg_p && del_reg_mount (mount[ent].posix_path, flags))
2196 return -1;
2197
2198 nmounts--; /* One less mount table entry */
2199 /* Fill in the hole if not at the end of the table */
2200 if (ent < nmounts)
2201 memmove (mount + ent, mount + ent + 1,
2202 sizeof (mount[ent]) * (nmounts - ent));
2203 sort (); /* Resort the table */
2204 return 0;
2205 }
2206 }
2207 set_errno (EINVAL);
2208 return -1;
2209 }
2210
2211 /* read_v1_mounts: Given a reg_key to an old mount table registry area,
2212 read in the mounts. The "which" arg contains zero if we're reading
2213 the user area and MOUNT_SYSTEM if we're reading the system area.
2214 This way we can store the mounts read in the appropriate place when
2215 they are written back to the new registry layout. */
2216
2217 void
2218 mount_info::read_v1_mounts (reg_key r, unsigned which)
2219 {
2220 unsigned mountflags = 0;
2221
2222 /* MAX_MOUNTS was 30 when we stopped using the v1 layout */
2223 for (int i = 0; i < 30; i++)
2224 {
2225 char key_name[10];
2226 char win32path[MAX_PATH];
2227 char unixpath[MAX_PATH];
2228
2229 __small_sprintf (key_name, "%02x", i);
2230
2231 reg_key k (r.get_key (), KEY_ALL_ACCESS, key_name, NULL);
2232
2233 /* The registry names are historical but useful so are left alone. */
2234 k.get_string ("native", win32path, sizeof (win32path), "");
2235 k.get_string ("unix", unixpath, sizeof (unixpath), "");
2236
2237 /* Does this entry contain something? */
2238 if (*win32path != 0)
2239 {
2240 mountflags = 0;
2241
2242 if (k.get_int ("fbinary", 0))
2243 mountflags |= MOUNT_BINARY;
2244
2245 /* Or in zero or MOUNT_SYSTEM depending on which table
2246 we're reading. */
2247 mountflags |= which;
2248
2249 int res = mount_table->add_item (win32path, unixpath, mountflags, TRUE);
2250 if (res && get_errno () == EMFILE)
2251 break; /* The number of entries exceeds MAX_MOUNTS */
2252 }
2253 }
2254 }
2255
2256 /* import_v1_mounts: If v1 mounts are present, load them and write
2257 the new entries to the new registry area. */
2258
2259 void
2260 mount_info::import_v1_mounts ()
2261 {
2262 reg_key r (HKEY_CURRENT_USER, KEY_ALL_ACCESS,
2263 "SOFTWARE",
2264 "Cygnus Solutions",
2265 "CYGWIN.DLL setup",
2266 "b15.0",
2267 "mounts",
2268 NULL);
2269
2270 nmounts = 0;
2271
2272 /* First read mounts from user's table. */
2273 read_v1_mounts (r, 0);
2274
2275 /* Then read mounts from system-wide mount table. */
2276 reg_key r1 (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS,
2277 "SOFTWARE",
2278 "Cygnus Solutions",
2279 "CYGWIN.DLL setup",
2280 "b15.0",
2281 "mounts",
2282 NULL);
2283 read_v1_mounts (r1, MOUNT_SYSTEM);
2284 }
2285
2286 /************************* mount_item class ****************************/
2287
2288 static mntent *
2289 fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
2290 {
2291 #ifdef _MT_SAFE
2292 struct mntent &ret=_reent_winsup()->mntbuf;
2293 #else
2294 static NO_COPY struct mntent ret;
2295 #endif
2296
2297 /* Remove drivenum from list if we see a x: style path */
2298 if (strlen (native_path) == 2 && native_path[1] == ':')
2299 {
2300 int drivenum = tolower (native_path[0]) - 'a';
2301 if (drivenum >= 0 && drivenum <= 31)
2302 available_drives &= ~(1 << drivenum);
2303 }
2304
2305 /* Pass back pointers to mount_table strings reserved for use by
2306 getmntent rather than pointers to strings in the internal mount
2307 table because the mount table might change, causing weird effects
2308 from the getmntent user's point of view. */
2309
2310 strcpy (_reent_winsup ()->mnt_fsname, native_path);
2311 ret.mnt_fsname = _reent_winsup ()->mnt_fsname;
2312 strcpy (_reent_winsup ()->mnt_dir, posix_path);
2313 ret.mnt_dir = _reent_winsup ()->mnt_dir;
2314
2315 if (!(flags & MOUNT_SYSTEM)) /* user mount */
2316 strcpy (_reent_winsup ()->mnt_type, (char *) "user");
2317 else /* system mount */
2318 strcpy (_reent_winsup ()->mnt_type, (char *) "system");
2319
2320 ret.mnt_type = _reent_winsup ()->mnt_type;
2321
2322 /* mnt_opts is a string that details mount params such as
2323 binary or textmode, or exec. We don't print
2324 `silent' here; it's a magic internal thing. */
2325
2326 if (!(flags & MOUNT_BINARY))
2327 strcpy (_reent_winsup ()->mnt_opts, (char *) "textmode");
2328 else
2329 strcpy (_reent_winsup ()->mnt_opts, (char *) "binmode");
2330
2331 if (flags & MOUNT_CYGWIN_EXEC)
2332 strcat (_reent_winsup ()->mnt_opts, (char *) ",cygexec");
2333 else if (flags & MOUNT_EXEC)
2334 strcat (_reent_winsup ()->mnt_opts, (char *) ",exec");
2335
2336 if ((flags & MOUNT_AUTO)) /* cygdrive */
2337 strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount");
2338
2339 ret.mnt_opts = _reent_winsup ()->mnt_opts;
2340
2341 ret.mnt_freq = 1;
2342 ret.mnt_passno = 1;
2343 return &ret;
2344 }
2345
2346 struct mntent *
2347 mount_item::getmntent ()
2348 {
2349 return fillout_mntent (native_path, posix_path, flags);
2350 }
2351
2352 static struct mntent *
2353 cygdrive_getmntent ()
2354 {
2355 char native_path[4];
2356 char posix_path[MAX_PATH];
2357 DWORD mask = 1, drive = 'a';
2358 struct mntent *ret = NULL;
2359
2360 while (available_drives)
2361 {
2362 for (/* nothing */; drive <= 'z'; mask <<= 1, drive++)
2363 if (available_drives & mask)
2364 break;
2365
2366 __small_sprintf (native_path, "%c:\\", drive);
2367 if (GetDriveType (native_path) == DRIVE_REMOVABLE ||
2368 GetFileAttributes (native_path) == (DWORD) -1)
2369 {
2370 available_drives &= ~mask;
2371 continue;
2372 }
2373 native_path[2] = '\0';
2374 __small_sprintf (posix_path, "%s%c", mount_table->cygdrive, drive);
2375 ret = fillout_mntent (native_path, posix_path, mount_table->cygdrive_flags);
2376 break;
2377 }
2378
2379 return ret;
2380 }
2381
2382 struct mntent *
2383 mount_info::getmntent (int x)
2384 {
2385 if (x < 0 || x >= nmounts)
2386 return cygdrive_getmntent ();
2387
2388 return mount[native_sorted[x]].getmntent ();
2389 }
2390
2391 /* Fill in the fields of a mount table entry. */
2392
2393 void
2394 mount_item::init (const char *native, const char *posix, unsigned mountflags)
2395 {
2396 strcpy ((char *) native_path, native);
2397 strcpy ((char *) posix_path, posix);
2398
2399 native_pathlen = strlen (native_path);
2400 posix_pathlen = strlen (posix_path);
2401
2402 flags = mountflags;
2403 }
2404
2405 /********************** Mount System Calls **************************/
2406
2407 /* Mount table system calls.
2408 Note that these are exported to the application. */
2409
2410 /* mount: Add a mount to the mount table in memory and to the registry
2411 that will cause paths under win32_path to be translated to paths
2412 under posix_path. */
2413
2414 extern "C" int
2415 mount (const char *win32_path, const char *posix_path, unsigned flags)
2416 {
2417 int res = -1;
2418
2419 if (flags & MOUNT_AUTO) /* normal mount */
2420 {
2421 /* When flags include MOUNT_AUTO, take this to mean that
2422 we actually want to change the cygdrive prefix and flags
2423 without actually mounting anything. */
2424 res = mount_table->write_cygdrive_info_to_registry (posix_path, flags);
2425 win32_path = NULL;
2426 }
2427 else
2428 res = mount_table->add_item (win32_path, posix_path, flags, TRUE);
2429
2430 syscall_printf ("%d = mount (%s, %s, %p)", res, win32_path, posix_path, flags);
2431 return res;
2432 }
2433
2434 /* umount: The standard umount call only has a path parameter. Since
2435 it is not possible for this call to specify whether to remove the
2436 mount from the user or global mount registry table, assume the user
2437 table. */
2438
2439 extern "C" int
2440 umount (const char *path)
2441 {
2442 return cygwin_umount (path, 0);
2443 }
2444
2445 /* cygwin_umount: This is like umount but takes an additional flags
2446 parameter that specifies whether to umount from the user or system-wide
2447 registry area. */
2448
2449 extern "C" int
2450 cygwin_umount (const char *path, unsigned flags)
2451 {
2452 int res = -1;
2453
2454 if (flags & MOUNT_AUTO)
2455 {
2456 /* When flags include MOUNT_AUTO, take this to mean that we actually want
2457 to remove the cygdrive prefix and flags without actually unmounting
2458 anything. */
2459 res = mount_table->remove_cygdrive_info_from_registry (path, flags);
2460 }
2461 else
2462 {
2463 res = mount_table->del_item (path, flags, TRUE);
2464 }
2465
2466 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
2467 return res;
2468 }
2469
2470 extern "C" FILE *
2471 setmntent (const char *filep, const char *)
2472 {
2473 iteration = 0;
2474 available_drives = GetLogicalDrives ();
2475 return (FILE *) filep;
2476 }
2477
2478 extern "C" struct mntent *
2479 getmntent (FILE *)
2480 {
2481 return mount_table->getmntent (iteration++);
2482 }
2483
2484 extern "C" int
2485 endmntent (FILE *)
2486 {
2487 return 1;
2488 }
2489
2490 /********************** Symbolic Link Support **************************/
2491
2492 /* Read symlink from Extended Attribute */
2493 int
2494 get_symlink_ea (const char* frompath, char* buf, int buf_size)
2495 {
2496 int res = NTReadEA (frompath, SYMLINK_EA_NAME, buf, buf_size);
2497 if (res == 0)
2498 debug_printf ("Cannot read symlink from EA");
2499 return (res - 1);
2500 }
2501
2502 /* Save symlink to Extended Attribute */
2503 BOOL
2504 set_symlink_ea (const char* frompath, const char* topath)
2505 {
2506 if (!NTWriteEA (frompath, SYMLINK_EA_NAME, topath, strlen (topath) + 1))
2507 {
2508 debug_printf ("Cannot save symlink in EA");
2509 return FALSE;
2510 }
2511 return TRUE;
2512 }
2513
2514 /* Create a symlink from FROMPATH to TOPATH. */
2515
2516 /* If TRUE create symlinks as Windows shortcuts, if FALSE create symlinks
2517 as normal files with magic number and system bit set. */
2518 int allow_winsymlinks = TRUE;
2519
2520 extern "C" int
2521 symlink (const char *topath, const char *frompath)
2522 {
2523 HANDLE h;
2524 int res = -1;
2525 path_conv win32_path, win32_topath;
2526 char from[MAX_PATH + 5];
2527 char cwd[MAX_PATH + 1], *cp = NULL, c = 0;
2528 char w32topath[MAX_PATH + 1];
2529 DWORD written;
2530 SECURITY_ATTRIBUTES sa = sec_none_nih;
2531
2532 /* POSIX says that empty 'frompath' is invalid input whlie empty
2533 'topath' is valid -- it's symlink resolver job to verify if
2534 symlink contents point to existing filesystem object */
2535 if (check_null_empty_str_errno (topath) == EFAULT ||
2536 check_null_empty_str_errno (frompath))
2537 goto done;
2538
2539 if (strlen (topath) >= MAX_PATH)
2540 {
2541 set_errno (ENAMETOOLONG);
2542 goto done;
2543 }
2544
2545 win32_path.check (frompath, PC_SYM_NOFOLLOW);
2546 if (allow_winsymlinks && !win32_path.error)
2547 {
2548 strcpy (from, frompath);
2549 strcat (from, ".lnk");
2550 win32_path.check (from, PC_SYM_NOFOLLOW);
2551 }
2552
2553 if (win32_path.error)
2554 {
2555 set_errno (win32_path.case_clash ? ECASECLASH : win32_path.error);
2556 goto done;
2557 }
2558
2559 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2560
2561 if (win32_path.is_device () || win32_path.exists ())
2562 {
2563 set_errno (EEXIST);
2564 goto done;
2565 }
2566
2567 if (allow_winsymlinks)
2568 {
2569 if (!isabspath (topath))
2570 {
2571 getcwd (cwd, MAX_PATH + 1);
2572 if ((cp = strrchr (from, '/')) || (cp = strrchr (from, '\\')))
2573 {
2574 c = *cp;
2575 *cp = '\0';
2576 chdir (from);
2577 }
2578 backslashify (topath, w32topath, 0);
2579 }
2580 if (!cp || GetFileAttributes (w32topath) == (DWORD)-1)
2581 {
2582 win32_topath.check (topath, PC_SYM_NOFOLLOW);
2583 if (!cp || win32_topath.error != ENOENT)
2584 strcpy (w32topath, win32_topath);
2585 }
2586 if (cp)
2587 {
2588 *cp = c;
2589 chdir (cwd);
2590 }
2591 }
2592
2593 if (allow_ntsec && win32_path.has_acls ())
2594 set_security_attribute (S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO,
2595 &sa, alloca (4096), 4096);
2596
2597 h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sa,
2598 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2599 if (h == INVALID_HANDLE_VALUE)
2600 __seterrno ();
2601 else
2602 {
2603 BOOL success;
2604
2605 if (allow_winsymlinks)
2606 {
2607 create_shortcut_header ();
2608 /* Don't change the datatypes of `len' and `win_len' since
2609 their sizeof is used when writing. */
2610 unsigned short len = strlen (topath);
2611 unsigned short win_len = strlen (w32topath);
2612 success = WriteFile (h, shortcut_header, SHORTCUT_HDR_SIZE,
2613 &written, NULL)
2614 && written == SHORTCUT_HDR_SIZE
2615 && WriteFile (h, &len, sizeof len, &written, NULL)
2616 && written == sizeof len
2617 && WriteFile (h, topath, len, &written, NULL)
2618 && written == len
2619 && WriteFile (h, &win_len, sizeof win_len, &written, NULL)
2620 && written == sizeof win_len
2621 && WriteFile (h, w32topath, win_len, &written, NULL)
2622 && written == win_len;
2623 }
2624 else
2625 {
2626 /* This is the old technique creating a symlink. */
2627 char buf[sizeof (SYMLINK_COOKIE) + MAX_PATH + 10];
2628
2629 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2630 DWORD len = strlen (buf) + 1;
2631
2632 /* Note that the terminating nul is written. */
2633 success = WriteFile (h, buf, len, &written, NULL)
2634 || written != len;
2635
2636 }
2637 if (success)
2638 {
2639 CloseHandle (h);
2640 if (!allow_ntsec && allow_ntea)
2641 set_file_attribute (win32_path.has_acls (),
2642 win32_path.get_win32 (),
2643 S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
2644 SetFileAttributesA (win32_path.get_win32 (),
2645 allow_winsymlinks ? FILE_ATTRIBUTE_READONLY
2646 : FILE_ATTRIBUTE_SYSTEM);
2647 if (win32_path.fs_fast_ea ())
2648 set_symlink_ea (win32_path, topath);
2649 res = 0;
2650 }
2651 else
2652 {
2653 __seterrno ();
2654 CloseHandle (h);
2655 DeleteFileA (win32_path.get_win32 ());
2656 }
2657 }
2658
2659 done:
2660 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2661 return res;
2662 }
2663
2664 static int
2665 check_sysfile (const char *path, DWORD fileattr, HANDLE h,
2666 char *contents, int *error, unsigned *pflags)
2667 {
2668 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2669 DWORD got;
2670 int res = 0;
2671
2672 if (!ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
2673 {
2674 debug_printf ("ReadFile1 failed");
2675 *error = EIO;
2676 }
2677 else if (got == sizeof (cookie_buf)
2678 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
2679 {
2680 /* It's a symlink. */
2681 *pflags = PATH_SYMLINK;
2682
2683 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2684 if (!res)
2685 {
2686 debug_printf ("ReadFile2 failed");
2687 *error = EIO;
2688 }
2689 else
2690 {
2691 /* Versions prior to b16 stored several trailing
2692 NULs with the path (to fill the path out to 1024
2693 chars). Current versions only store one trailing
2694 NUL. The length returned is the path without
2695 *any* trailing NULs. We also have to handle (or
2696 at least not die from) corrupted paths. */
2697 if (memchr (contents, 0, got) != NULL)
2698 res = strlen (contents);
2699 else
2700 res = got;
2701 }
2702 }
2703 else if (got == sizeof (cookie_buf)
2704 && memcmp (cookie_buf, SOCKET_COOKIE, sizeof (cookie_buf)) == 0)
2705 *pflags |= PATH_SOCKET;
2706 else
2707 {
2708 /* Not a symlink, see if executable. */
2709 if (*pflags & PATH_ALL_EXEC)
2710 /* Nothing to do */;
2711 else if (has_exec_chars (cookie_buf, got))
2712 *pflags |= PATH_EXEC;
2713 else
2714 *pflags |= PATH_NOTEXEC;
2715 }
2716 syscall_printf ("%d = symlink.check_sysfile (%s, %s) (%p)",
2717 res, path, contents, *pflags);
2718
2719 CloseHandle (h);
2720 return res;
2721 }
2722
2723 enum
2724 {
2725 SCAN_BEG,
2726 SCAN_LNK,
2727 SCAN_HASLNK,
2728 SCAN_JUSTCHECK,
2729 SCAN_APPENDLNK,
2730 SCAN_EXTRALNK,
2731 SCAN_DONE,
2732 };
2733
2734 class suffix_scan
2735 {
2736 const suffix_info *suffixes, *suffixes_start;
2737 int nextstate;
2738 char *eopath;
2739 public:
2740 const char *path;
2741 char *has (const char *, const suffix_info *);
2742 int next ();
2743 int lnk_match () {return nextstate >= SCAN_EXTRALNK;}
2744 };
2745
2746 char *
2747 suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
2748 {
2749 nextstate = SCAN_BEG;
2750 suffixes = suffixes_start = in_suffixes;
2751
2752 char *ext_here = strrchr (in_path, '.');
2753 path = in_path;
2754 eopath = strchr (path, '\0');
2755
2756 if (!ext_here)
2757 goto noext;
2758
2759 if (suffixes)
2760 {
2761 /* Check if the extension matches a known extension */
2762 for (const suffix_info *ex = in_suffixes; ex->name != NULL; ex++)
2763 if (strcasematch (ext_here, ex->name))
2764 {
2765 nextstate = SCAN_JUSTCHECK;
2766 suffixes = NULL; /* Has an extension so don't scan for one. */
2767 goto done;
2768 }
2769 }
2770
2771 /* Didn't match. Use last resort -- .lnk. */
2772 if (strcasematch (ext_here, ".lnk"))
2773 {
2774 nextstate = SCAN_HASLNK;
2775 suffixes = NULL;
2776 }
2777
2778 noext:
2779 ext_here = eopath;
2780
2781 done:
2782 return ext_here;
2783 }
2784
2785 int
2786 suffix_scan::next ()
2787 {
2788 if (suffixes)
2789 {
2790 while (suffixes && suffixes->name)
2791 if (!suffixes->addon)
2792 suffixes++;
2793 else
2794 {
2795 strcpy (eopath, suffixes->name);
2796 if (nextstate == SCAN_EXTRALNK)
2797 strcat (eopath, ".lnk");
2798 suffixes++;
2799 return 1;
2800 }
2801 suffixes = NULL;
2802 }
2803
2804 switch (nextstate)
2805 {
2806 case SCAN_BEG:
2807 suffixes = suffixes_start;
2808 if (!suffixes)
2809 nextstate = SCAN_LNK;
2810 else
2811 {
2812 if (!*suffixes->name)
2813 suffixes++;
2814 nextstate = SCAN_EXTRALNK;
2815 }
2816 return 1;
2817 case SCAN_HASLNK:
2818 nextstate = SCAN_EXTRALNK; /* Skip SCAN_BEG */
2819 return 1;
2820 case SCAN_LNK:
2821 case SCAN_EXTRALNK:
2822 strcpy (eopath, ".lnk");
2823 nextstate = SCAN_DONE;
2824 return 1;
2825 case SCAN_JUSTCHECK:
2826 nextstate = SCAN_APPENDLNK;
2827 return 1;
2828 case SCAN_APPENDLNK:
2829 strcat (eopath, ".lnk");
2830 nextstate = SCAN_DONE;
2831 return 1;
2832 default:
2833 *eopath = '\0';
2834 return 0;
2835 }
2836 }
2837
2838 /* Check if PATH is a symlink. PATH must be a valid Win32 path name.
2839
2840 If PATH is a symlink, put the value of the symlink--the file to
2841 which it points--into BUF. The value stored in BUF is not
2842 necessarily null terminated. BUFLEN is the length of BUF; only up
2843 to BUFLEN characters will be stored in BUF. BUF may be NULL, in
2844 which case nothing will be stored.
2845
2846 Set *SYML if PATH is a symlink.
2847
2848 Set *EXEC if PATH appears to be executable. This is an efficiency
2849 hack because we sometimes have to open the file anyhow. *EXEC will
2850 not be set for every executable file.
2851
2852 Return -1 on error, 0 if PATH is not a symlink, or the length
2853 stored into BUF if PATH is a symlink. */
2854
2855 int
2856 symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
2857 {
2858 HANDLE h;
2859 int res = 0;
2860 suffix_scan suffix;
2861 contents[0] = '\0';
2862
2863 is_symlink = TRUE;
2864 ext_here = suffix.has (path, suffixes);
2865 extn = ext_here - path;
2866
2867 pflags &= ~PATH_SYMLINK;
2868
2869 case_clash = FALSE;
2870
2871 while (suffix.next ())
2872 {
2873 error = 0;
2874 fileattr = GetFileAttributesA (suffix.path);
2875 if (fileattr == (DWORD) -1)
2876 {
2877 /* The GetFileAttributesA call can fail for reasons that don't
2878 matter, so we just return 0. For example, getting the
2879 attributes of \\HOST will typically fail. */
2880 debug_printf ("GetFileAttributesA (%s) failed", suffix.path);
2881 error = geterrno_from_win_error (GetLastError (), EACCES);
2882 continue;
2883 }
2884
2885
2886 ext_tacked_on = !!*ext_here;
2887
2888 if (pcheck_case != PCHECK_RELAXED && !case_check (path)
2889 || (opt & PC_SYM_IGNORE))
2890 goto file_not_symlink;
2891
2892 int sym_check;
2893
2894 sym_check = 0;
2895
2896 if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
2897 goto file_not_symlink;
2898
2899 /* Windows shortcuts are treated as symlinks. */
2900 if (suffix.lnk_match ())
2901 sym_check = 1;
2902
2903 /* This is the old Cygwin method creating symlinks: */
2904 /* A symlink will have the `system' file attribute. */
2905 /* Only files can be symlinks (which can be symlinks to directories). */
2906 if (fileattr & FILE_ATTRIBUTE_SYSTEM)
2907 sym_check = 2;
2908
2909 if (!sym_check)
2910 goto file_not_symlink;
2911
2912 if (sym_check > 0 && opt & PC_CHECK_EA &&
2913 (res = get_symlink_ea (suffix.path, contents, sizeof (contents))) > 0)
2914 {
2915 pflags = PATH_SYMLINK;
2916 debug_printf ("Got symlink from EA: %s", contents);
2917 break;
2918 }
2919
2920 /* Open the file. */
2921
2922 h = CreateFileA (suffix.path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
2923 FILE_ATTRIBUTE_NORMAL, 0);
2924 res = -1;
2925 if (h == INVALID_HANDLE_VALUE)
2926 goto file_not_symlink;
2927
2928 /* FIXME: if symlink isn't present in EA, but EAs are supported,
2929 * should we write it there?
2930 */
2931 switch (sym_check)
2932 {
2933 case 1:
2934 res = check_shortcut (suffix.path, fileattr, h, contents, &error, &pflags);
2935 if (res)
2936 break;
2937 /* If searching for `foo' and then finding a `foo.lnk' which is
2938 no shortcut, return the same as if file not found. */
2939 if (!suffix.lnk_match () || !ext_tacked_on)
2940 goto file_not_symlink;
2941
2942 fileattr = (DWORD) -1;
2943 continue; /* in case we're going to tack *another* .lnk on this filename. */
2944 case 2:
2945 res = check_sysfile (suffix.path, fileattr, h, contents, &error, &pflags);
2946 if (!res)
2947 goto file_not_symlink;
2948 break;
2949 }
2950 break;
2951
2952 file_not_symlink:
2953 is_symlink = FALSE;
2954 syscall_printf ("not a symlink");
2955 res = 0;
2956 break;
2957 }
2958
2959 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
2960 res, suffix.path, contents, pflags);
2961 return res;
2962 }
2963
2964 /* Check the correct case of the last path component (given in DOS style).
2965 Adjust the case in this->path if pcheck_case == PCHECK_ADJUST or return
2966 FALSE if pcheck_case == PCHECK_STRICT.
2967 Dont't call if pcheck_case == PCHECK_RELAXED.
2968 */
2969
2970 BOOL
2971 symlink_info::case_check (char *path)
2972 {
2973 WIN32_FIND_DATA data;
2974 HANDLE h;
2975 char *c;
2976
2977 /* Set a pointer to the beginning of the last component. */
2978 if (!(c = strrchr (path, '\\')))
2979 c = path;
2980 else
2981 ++c;
2982
2983 if ((h = FindFirstFile (path, &data))
2984 != INVALID_HANDLE_VALUE)
2985 {
2986 FindClose (h);
2987
2988 /* If that part of the component exists, check the case. */
2989 if (strcmp (c, data.cFileName))
2990 {
2991 case_clash = TRUE;
2992
2993 /* If check is set to STRICT, a wrong case results
2994 in returning a ENOENT. */
2995 if (pcheck_case == PCHECK_STRICT)
2996 return FALSE;
2997
2998 /* PCHECK_ADJUST adjusts the case in the incoming
2999 path which points to the path in *this. */
3000 strcpy (c, data.cFileName);
3001 }
3002 }
3003 return TRUE;
3004 }
3005
3006 /* readlink system call */
3007
3008 extern "C" int
3009 readlink (const char *path, char *buf, int buflen)
3010 {
3011 extern suffix_info stat_suffixes[];
3012
3013 if (buflen < 0)
3014 {
3015 set_errno (ENAMETOOLONG);
3016 return -1;
3017 }
3018
3019 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
3020
3021 if (pathbuf.error)
3022 {
3023 set_errno (pathbuf.error);
3024 syscall_printf ("-1 = readlink (%s, %p, %d)", path, buf, buflen);
3025 return -1;
3026 }
3027
3028 if (!pathbuf.exists ())
3029 {
3030 set_errno (ENOENT);
3031 return -1;
3032 }
3033
3034 if (!pathbuf.issymlink ())
3035 {
3036 if (pathbuf.fileattr != (DWORD) -1)
3037 set_errno (EINVAL);
3038 return -1;
3039 }
3040
3041 int len = min (buflen, (int) strlen (pathbuf.get_win32 ()));
3042 memcpy (buf, pathbuf.get_win32 (), len);
3043
3044 /* errno set by symlink.check if error */
3045 return len;
3046 }
3047
3048 /* Some programs rely on st_dev/st_ino being unique for each file.
3049 Hash the path name and hope for the best. The hash arg is not
3050 always initialized to zero since readdir needs to compute the
3051 dirent ino_t based on a combination of the hash of the directory
3052 done during the opendir call and the hash or the filename within
3053 the directory. FIXME: Not bullet-proof. */
3054 /* Cygwin internal */
3055
3056 unsigned long __stdcall
3057 hash_path_name (unsigned long hash, const char *name)
3058 {
3059 if (!*name)
3060 return hash;
3061
3062 /* Perform some initial permutations on the pathname if this is
3063 not "seeded" */
3064 if (!hash)
3065 {
3066 /* Simplistic handling of drives. If there is a drive specified,
3067 make sure that the initial letter is upper case. If there is
3068 no \ after the ':' assume access through the root directory
3069 of that drive.
3070 FIXME: Should really honor MS-Windows convention of using
3071 the environment to track current directory on various drives. */
3072 if (name[1] == ':')
3073 {
3074 char *nn, *newname = (char *) alloca (strlen (name) + 2);
3075 nn = newname;
3076 *nn = isupper (*name) ? cyg_tolower (*name) : *name;
3077 *++nn = ':';
3078 name += 2;
3079 if (*name != '\\')
3080 *++nn = '\\';
3081 strcpy (++nn, name);
3082 name = newname;
3083 goto hashit;
3084 }
3085
3086 /* Fill out the hashed path name with the current working directory if
3087 this is not an absolute path and there is no pre-specified hash value.
3088 Otherwise the inodes same will differ depending on whether a file is
3089 referenced with an absolute value or relatively. */
3090
3091 if (!hash && !isabspath (name))
3092 {
3093 hash = cygheap->cwd.get_hash ();
3094 if (name[0] == '.' && name[1] == '\0')
3095 return hash;
3096 hash += hash_path_name (hash, "\\");
3097 }
3098 }
3099
3100 hashit:
3101 /* Build up hash. Ignore single trailing slash or \a\b\ != \a\b or
3102 \a\b\. but allow a single \ if that's all there is. */
3103 do
3104 {
3105 int ch = cyg_tolower(*name);
3106 hash += ch + (ch << 17);
3107 hash ^= hash >> 2;
3108 }
3109 while (*++name != '\0' &&
3110 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
3111 return hash;
3112 }
3113
3114 char *
3115 getcwd (char *buf, size_t ulen)
3116 {
3117 char* res = NULL;
3118 if (ulen == 0 && buf)
3119 set_errno (EINVAL);
3120 else if (buf == NULL || !__check_null_invalid_struct_errno (buf, ulen))
3121 res = cygheap->cwd.get (buf, 1, 1, ulen);
3122 return res;
3123 }
3124
3125 /* getwd: standards? */
3126 extern "C" char *
3127 getwd (char *buf)
3128 {
3129 return getcwd (buf, MAX_PATH);
3130 }
3131
3132 /* chdir: POSIX 5.2.1.1 */
3133 extern "C" int
3134 chdir (const char *in_dir)
3135 {
3136 if (check_null_empty_str_errno (in_dir))
3137 return -1;
3138
3139 syscall_printf ("dir '%s'", in_dir);
3140
3141 char *s;
3142 char dir[strlen (in_dir) + 1];
3143 strcpy (dir, in_dir);
3144 /* Incredibly. Windows allows you to specify a path with trailing
3145 whitespace to SetCurrentDirectory. This doesn't work too well
3146 with other parts of the API, though, apparently. So nuke trailing
3147 white space. */
3148 for (s = strchr (dir, '\0'); --s >= dir && isspace ((unsigned int) (*s & 0xff)); )
3149 *s = '\0';
3150
3151 if (!*s)
3152 {
3153 set_errno (ENOENT);
3154 return -1;
3155 }
3156
3157 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
3158 again. */
3159 path_conv path (PC_NONULLEMPTY, dir, PC_FULL | PC_SYM_FOLLOW);
3160 if (path.error)
3161 {
3162 set_errno (path.error);
3163 syscall_printf ("-1 = chdir (%s)", dir);
3164 return -1;
3165 }
3166
3167
3168 /* Look for trailing path component consisting entirely of dots. This
3169 is needed only in case of chdir since Windows simply ignores count
3170 of dots > 2 here instead of returning an error code. Counts of dots
3171 <= 2 are already eliminated by normalize_posix_path. */
3172 const char *p = strrchr (dir, '/');
3173 if (!p)
3174 p = dir;
3175 else
3176 p++;
3177
3178 size_t len = strlen (p);
3179 if (len > 2 && strspn (p, ".") == len)
3180 {
3181 set_errno (ENOENT);
3182 return -1;
3183 }
3184
3185 char *native_dir = path.get_win32 ();
3186
3187 /* Check to see if path translates to something like C:.
3188 If it does, append a \ to the native directory specification to
3189 defeat the Windows 95 (i.e. MS-DOS) tendency of returning to
3190 the last directory visited on the given drive. */
3191 if (isdrive (native_dir) && !native_dir[2])
3192 {
3193 native_dir[2] = '\\';
3194 native_dir[3] = '\0';
3195 }
3196 int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
3197
3198 /* If res < 0, we didn't change to a new directory.
3199 Otherwise, set the current windows and posix directory cache from input.
3200 If the specified directory is a MS-DOS style directory or if the directory
3201 was symlinked, convert the MS-DOS path back to posix style. Otherwise just
3202 store the given directory. This allows things like "find", which traverse
3203 directory trees, to work correctly with Cygwin mounted directories.
3204 FIXME: Is just storing the posixized windows directory the correct thing to
3205 do when we detect a symlink? Should we instead rebuild the posix path from
3206 the input by traversing links? This would be an expensive operation but
3207 we'll see if Cygwin mailing list users whine about the current behavior. */
3208 if (res == -1)
3209 __seterrno ();
3210 else if (!path.has_symlinks () && strpbrk (dir, ":\\") == NULL
3211 && pcheck_case == PCHECK_RELAXED)
3212 cygheap->cwd.set (path, dir);
3213 else
3214 cygheap->cwd.set (path, NULL);
3215
3216 /* Note that we're accessing cwd.posix without a lock here. I didn't think
3217 it was worth locking just for strace. */
3218 syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%s'", res,
3219 cygheap->cwd.posix, native_dir);
3220 MALLOC_CHECK;
3221 return res;
3222 }
3223
3224 extern "C" int
3225 fchdir (int fd)
3226 {
3227 int res;
3228 sigframe thisframe (mainthread);
3229
3230 cygheap_fdget cfd (fd);
3231 if (cfd >= 0)
3232 res = chdir (cfd->get_name ());
3233 else
3234 res = -1;
3235
3236 syscall_printf ("%d = fchdir (%d)", res, fd);
3237 return res;
3238 }
3239
3240 /******************** Exported Path Routines *********************/
3241
3242 /* Cover functions to the path conversion routines.
3243 These are exported to the world as cygwin_foo by cygwin.din. */
3244
3245 extern "C" int
3246 cygwin_conv_to_win32_path (const char *path, char *win32_path)
3247 {
3248 path_conv p (path, PC_SYM_FOLLOW);
3249 if (p.error)
3250 {
3251 set_errno (p.error);
3252 return -1;
3253 }
3254
3255 strcpy (win32_path, p.get_win32 ());
3256 return 0;
3257 }
3258
3259 extern "C" int
3260 cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3261 {
3262 path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
3263 if (p.error)
3264 {
3265 set_errno (p.error);
3266 return -1;
3267 }
3268
3269 strcpy (win32_path, p.get_win32 ());
3270 return 0;
3271 }
3272
3273 /* This is exported to the world as cygwin_foo by cygwin.din. */
3274
3275 extern "C" int
3276 cygwin_conv_to_posix_path (const char *path, char *posix_path)
3277 {
3278 if (check_null_empty_str_errno (path))
3279 return -1;
3280 mount_table->conv_to_posix_path (path, posix_path, 1);
3281 return 0;
3282 }
3283
3284 extern "C" int
3285 cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3286 {
3287 if (check_null_empty_str_errno (path))
3288 return -1;
3289 mount_table->conv_to_posix_path (path, posix_path, 0);
3290 return 0;
3291 }
3292
3293 /* The realpath function is supported on some UNIX systems. */
3294
3295 extern "C" char *
3296 realpath (const char *path, char *resolved)
3297 {
3298 int err;
3299
3300 path_conv real_path (path, PC_SYM_FOLLOW | PC_FULL);
3301
3302 if (real_path.error)
3303 err = real_path.error;
3304 else
3305 {
3306 err = mount_table->conv_to_posix_path (real_path.get_win32 (), resolved, 0);
3307 if (err == 0)
3308 return resolved;
3309 }
3310
3311 /* FIXME: on error, we are supposed to put the name of the path
3312 component which could not be resolved into RESOLVED. */
3313 resolved[0] = '\0';
3314
3315 set_errno (err);
3316 return NULL;
3317 }
3318
3319 /* Return non-zero if path is a POSIX path list.
3320 This is exported to the world as cygwin_foo by cygwin.din.
3321
3322 DOCTOOL-START
3323 <sect1 id="add-func-cygwin-posix-path-list-p">
3324 <para>Rather than use a mode to say what the "proper" path list
3325 format is, we allow any, and give apps the tools they need to
3326 convert between the two. If a ';' is present in the path list it's
3327 a Win32 path list. Otherwise, if the first path begins with
3328 [letter]: (in which case it can be the only element since if it
3329 wasn't a ';' would be present) it's a Win32 path list. Otherwise,
3330 it's a POSIX path list.</para>
3331 </sect1>
3332 DOCTOOL-END
3333 */
3334
3335 extern "C" int
3336 cygwin_posix_path_list_p (const char *path)
3337 {
3338 int posix_p = !(strchr (path, ';') || isdrive (path));
3339 return posix_p;
3340 }
3341
3342 /* These are used for apps that need to convert env vars like PATH back and
3343 forth. The conversion is a two step process. First, an upper bound on the
3344 size of the buffer needed is computed. Then the conversion is done. This
3345 allows the caller to use alloca if it wants. */
3346
3347 static int
3348 conv_path_list_buf_size (const char *path_list, int to_posix_p)
3349 {
3350 int i, num_elms, max_mount_path_len, size;
3351 const char *p;
3352
3353 /* The theory is that an upper bound is
3354 current_size + (num_elms * max_mount_path_len) */
3355
3356 char delim = to_posix_p ? ';' : ':';
3357 p = path_list;
3358 for (num_elms = 1; (p = strchr (p, delim)) != NULL; ++num_elms)
3359 ++p;
3360
3361 /* 7: strlen ("//c") + slop, a conservative initial value */
3362 for (max_mount_path_len = 7, i = 0; i < mount_table->nmounts; ++i)
3363 {
3364 int mount_len = (to_posix_p
3365 ? mount_table->mount[i].posix_pathlen
3366 : mount_table->mount[i].native_pathlen);
3367 if (max_mount_path_len < mount_len)
3368 max_mount_path_len = mount_len;
3369 }
3370
3371 /* 100: slop */
3372 size = strlen (path_list) + (num_elms * max_mount_path_len) + 100;
3373 return size;
3374 }
3375
3376 extern "C" int
3377 cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3378 {
3379 return conv_path_list_buf_size (path_list, 1);
3380 }
3381
3382 extern "C" int
3383 cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3384 {
3385 return conv_path_list_buf_size (path_list, 0);
3386 }
3387
3388 extern "C" int
3389 cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3390 {
3391 conv_path_list (win32, posix, 1);
3392 return 0;
3393 }
3394
3395 extern "C" int
3396 cygwin_posix_to_win32_path_list (const char *posix, char *win32)
3397 {
3398 conv_path_list (posix, win32, 0);
3399 return 0;
3400 }
3401
3402 /* cygwin_split_path: Split a path into directory and file name parts.
3403 Buffers DIR and FILE are assumed to be big enough.
3404
3405 Examples (path -> `dir' / `file'):
3406 / -> `/' / `'
3407 "" -> `.' / `'
3408 . -> `.' / `.' (FIXME: should this be `.' / `'?)
3409 .. -> `.' / `..' (FIXME: should this be `..' / `'?)
3410 foo -> `.' / `foo'
3411 foo/bar -> `foo' / `bar'
3412 foo/bar/ -> `foo' / `bar'
3413 /foo -> `/' / `foo'
3414 /foo/bar -> `/foo' / `bar'
3415 c: -> `c:/' / `'
3416 c:/ -> `c:/' / `'
3417 c:foo -> `c:/' / `foo'
3418 c:/foo -> `c:/' / `foo'
3419 */
3420
3421 extern "C" void
3422 cygwin_split_path (const char *path, char *dir, char *file)
3423 {
3424 int dir_started_p = 0;
3425
3426 /* Deal with drives.
3427 Remember that c:foo <==> c:/foo. */
3428 if (isdrive (path))
3429 {
3430 *dir++ = *path++;
3431 *dir++ = *path++;
3432 *dir++ = '/';
3433 if (!*path)
3434 {
3435 *dir = 0;
3436 *file = 0;
3437 return;
3438 }
3439 if (SLASH_P (*path))
3440 ++path;
3441 dir_started_p = 1;
3442 }
3443
3444 /* Determine if there are trailing slashes and "delete" them if present.
3445 We pretend as if they don't exist. */
3446 const char *end = path + strlen (path);
3447 /* path + 1: keep leading slash. */
3448 while (end > path + 1 && SLASH_P (end[-1]))
3449 --end;
3450
3451 /* At this point, END points to one beyond the last character
3452 (with trailing slashes "deleted"). */
3453
3454 /* Point LAST_SLASH at the last slash (duh...). */
3455 const char *last_slash;
3456 for (last_slash = end - 1; last_slash >= path; --last_slash)
3457 if (SLASH_P (*last_slash))
3458 break;
3459
3460 if (last_slash == path)
3461 {
3462 *dir++ = '/';
3463 *dir = 0;
3464 }
3465 else if (last_slash > path)
3466 {
3467 memcpy (dir, path, last_slash - path);
3468 dir[last_slash - path] = 0;
3469 }
3470 else
3471 {
3472 if (dir_started_p)
3473 ; /* nothing to do */
3474 else
3475 *dir++ = '.';
3476 *dir = 0;
3477 }
3478
3479 memcpy (file, last_slash + 1, end - last_slash - 1);
3480 file[end - last_slash - 1] = 0;
3481 }
3482
3483 /*****************************************************************************/
3484
3485 /* Return the hash value for the current win32 value.
3486 This is used when constructing inodes. */
3487 DWORD
3488 cwdstuff::get_hash ()
3489 {
3490 DWORD hashnow;
3491 lock->acquire ();
3492 hashnow = hash;
3493 lock->release ();
3494 return hashnow;
3495 }
3496
3497 /* Initialize cygcwd 'muto' for serializing access to cwd info. */
3498 void
3499 cwdstuff::init ()
3500 {
3501 lock = new_muto (FALSE, "cwd");
3502 }
3503
3504 /* Get initial cwd. Should only be called once in a
3505 process tree. */
3506 bool
3507 cwdstuff::get_initial ()
3508 {
3509 lock->acquire ();
3510
3511 if (win32)
3512 return 1;
3513
3514 int i;
3515 DWORD len, dlen;
3516 for (i = 0, dlen = MAX_PATH, len = 0; i < 3; dlen *= 2, i++)
3517 {
3518 win32 = (char *) crealloc (win32, dlen + 2);
3519 if ((len = GetCurrentDirectoryA (dlen, win32)) < dlen)
3520 break;
3521 }
3522
3523 if (len == 0)
3524 {
3525 __seterrno ();
3526 lock->release ();
3527 debug_printf ("get_initial_cwd failed, %E");
3528 lock->release ();
3529 return 0;
3530 }
3531 set (NULL);
3532 return 1; /* Leaves cwd lock unreleased */
3533 }
3534
3535 /* Fill out the elements of a cwdstuff struct.
3536 It is assumed that the lock for the cwd is acquired if
3537 win32_cwd == NULL. */
3538 void
3539 cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
3540 {
3541 char pathbuf[MAX_PATH];
3542
3543 if (win32_cwd)
3544 {
3545 lock->acquire ();
3546 win32 = (char *) crealloc (win32, strlen (win32_cwd) + 1);
3547 strcpy (win32, win32_cwd);
3548 }
3549
3550 if (!posix_cwd)
3551 mount_table->conv_to_posix_path (win32, pathbuf, 0);
3552 else
3553 (void) normalize_posix_path (posix_cwd, pathbuf);
3554
3555 posix = (char *) crealloc (posix, strlen (pathbuf) + 1);
3556 strcpy (posix, pathbuf);
3557
3558 hash = hash_path_name (0, win32);
3559
3560 if (win32_cwd)
3561 lock->release ();
3562
3563 return;
3564 }
3565
3566 /* Copy the value for either the posix or the win32 cwd into a buffer. */
3567 char *
3568 cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3569 {
3570 MALLOC_CHECK;
3571
3572 if (ulen)
3573 /* nothing */;
3574 else if (buf == NULL)
3575 ulen = (unsigned) -1;
3576 else
3577 {
3578 set_errno (EINVAL);
3579 goto out;
3580 }
3581
3582 if (!get_initial ()) /* Get initial cwd and set cwd lock */
3583 return NULL;
3584
3585 char *tocopy;
3586 if (!need_posix)
3587 tocopy = win32;
3588 else
3589 tocopy = posix;
3590
3591 debug_printf("posix %s", posix);
3592 if (strlen (tocopy) >= ulen)
3593 {
3594 set_errno (ERANGE);
3595 buf = NULL;
3596 }
3597 else
3598 {
3599 if (!buf)
3600 buf = (char *) malloc (strlen (tocopy) + 1);
3601 strcpy (buf, tocopy);
3602 if (!buf[0]) /* Should only happen when chroot */
3603 strcpy (buf, "/");
3604 }
3605
3606 lock->release ();
3607
3608 out:
3609 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3610 buf, buf, ulen, need_posix, with_chroot, errno);
3611 MALLOC_CHECK;
3612 return buf;
3613 }
This page took 0.189455 seconds and 5 git commands to generate.