]> sourceware.org Git - newlib-cygwin.git/blame - winsup/cygwin/path.cc
* Makefile.in: Only build testsuite directory on first 'make check'.
[newlib-cygwin.git] / winsup / cygwin / path.cc
CommitLineData
1fd5e000
CF
1/* path.cc: path support.
2
fc168ded 3 Copyright 1996, 1997, 1998, 1999, 2000, 2001 Red Hat, Inc.
1fd5e000
CF
4
5This file is part of Cygwin.
6
7This software is a copyrighted work licensed under the terms of the
8Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9details. */
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
7e24f1bf 18 - A \ or : in a path denotes a pure windows spec.
1fd5e000
CF
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.
1fd5e000
CF
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
1fd5e000
CF
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
1fd5e000 31 Text vs Binary issues are not considered here in path style
7e24f1bf
CF
32 decisions, although the appropriate flags are retrieved and
33 stored in various structures.
1fd5e000
CF
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
7e24f1bf 47 c: means c:\. FIXME: Is this still true?
1fd5e000
CF
48*/
49
4c8d72de 50#include "winsup.h"
1fd5e000
CF
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>
1fd5e000 58#include <ctype.h>
95bdb496 59#include <winioctl.h>
10b06c5e
CV
60#include <wingdi.h>
61#include <winuser.h>
62#include <winnls.h>
63#include <winnetwk.h>
f0338f54
CF
64#include <sys/cygwin.h>
65#include <cygwin/version.h>
9e2baf8d 66#include "cygerrno.h"
95a8465b 67#include "perprocess.h"
6b91b8d5 68#include "security.h"
bccd5e0d
CF
69#include "fhandler.h"
70#include "path.h"
bccd5e0d
CF
71#include "sync.h"
72#include "sigproc.h"
73#include "pinfo.h"
0381fec6 74#include "dtable.h"
b0e82b74 75#include "cygheap.h"
29ac7f89 76#include "shared_info.h"
f0338f54 77#include "registry.h"
1ec4f618 78#include <assert.h>
79e56091 79#include "shortcut.h"
1fd5e000 80
f2aeff27
CF
81#ifdef _MT_SAFE
82#define iteration _reent_winsup ()->_iteration
83#define available_drives _reent_winsup ()->available_drives
84#else
85static int iteration;
86static DWORD available_drives;
87#endif
88
7e24f1bf 89static int normalize_win32_path (const char *src, char *dst);
1fd5e000
CF
90static void slashify (const char *src, char *dst, int trailing_slash_p);
91static void backslashify (const char *src, char *dst, int trailing_slash_p);
1fd5e000 92
2cf9359a
CF
93struct symlink_info
94{
b98ebf54 95 char contents[MAX_PATH + 4];
2cf9359a 96 char *ext_here;
fc672fb2 97 int extn;
2cf9359a
CF
98 unsigned pflags;
99 DWORD fileattr;
100 int is_symlink;
fc672fb2 101 bool ext_tacked_on;
9e2baf8d 102 int error;
70c370d6 103 BOOL case_clash;
2b5803d4
CF
104 int check (char *path, const suffix_info *suffixes, unsigned opt);
105 BOOL case_check (char *path);
2cf9359a
CF
106};
107
70c370d6
CV
108int pcheck_case = PCHECK_RELAXED; /* Determines the case check behaviour. */
109
a9f20457
CF
110#define CYGWIN_REGNAME (cygheap->cygwin_regname ?: CYGWIN_INFO_CYGWIN_REGISTRY_NAME)
111
1fd5e000
CF
112/* Determine if path prefix matches current cygdrive */
113#define iscygdrive(path) \
2a6fc028 114 (path_prefix_p (mount_table->cygdrive, (path), mount_table->cygdrive_len))
1fd5e000
CF
115
116#define iscygdrive_device(path) \
2a6fc028
CF
117 (iscygdrive(path) && isalpha(path[mount_table->cygdrive_len]) && \
118 (isdirsep(path[mount_table->cygdrive_len + 1]) || \
119 !path[mount_table->cygdrive_len + 1]))
1fd5e000 120
7e24f1bf
CF
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
7ceb1cac
CF
135int
136path_prefix_p (const char *path1, const char *path2, int len1)
1fd5e000
CF
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
70c370d6 145 if (!pathnmatch (path1, path2, len1))
1fd5e000
CF
146 return 0;
147
148 return SLASH_P (path2[len1]) || path2[len1] == 0 || path1[len1 - 1] == ':';
149}
150
70c370d6
CV
151/* Return non-zero if paths match in first len chars.
152 Check is dependent of the case sensitivity setting. */
153int
154pathnmatch (const char *path1, const char *path2, int len)
155{
156 return pcheck_case == PCHECK_STRICT ? !strncmp (path1, path2, len)
fc633b63 157 : strncasematch (path1, path2, len);
70c370d6
CV
158}
159
160/* Return non-zero if paths match. Check is dependent of the case
161 sensitivity setting. */
162int
163pathmatch (const char *path1, const char *path2)
164{
165 return pcheck_case == PCHECK_STRICT ? !strcmp (path1, path2)
fc633b63 166 : strcasematch (path1, path2);
70c370d6
CV
167}
168
b98ebf54
CF
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
7ceb1cac 176int
b98ebf54
CF
177normalize_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 {
b98ebf54
CF
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 }
c27a2981
CF
214 else if (src[0] == '.' && isslash (src[1]))
215 {
216 *dst++ = '.';
217 *dst++ = '/';
218 src += 2;
219 }
b98ebf54 220 }
b98ebf54
CF
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;
fc633b63 253 else
ac5561f2
CF
254 {
255 while (dst > dst_start && !isslash (*--dst))
256 continue;
257 src++;
258 }
b98ebf54
CF
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
270done:
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
1ff87985 279inline void
4199e1e6 280path_conv::add_ext_from_sym (symlink_info &sym)
1ff87985
CV
281{
282 if (sym.ext_here && *sym.ext_here)
283 {
284 known_suffix = path + sym.extn;
285 if (sym.ext_tacked_on)
ac5561f2 286 strcpy (known_suffix, sym.ext_here);
1ff87985
CV
287 }
288}
e61cead3 289
d3c7e9de
CF
290static void __stdcall mkrelpath (char *dst) __attribute__ ((regparm (2)));
291static void __stdcall
292mkrelpath (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
149da470
ED
317void
318path_conv::update_fs_info (const char* win32_path)
319{
320 char tmp_buf [MAX_PATH];
321 strncpy (tmp_buf, win32_path, MAX_PATH);
322
fc633b63 323 if (!rootdir (tmp_buf))
149da470
ED
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 {
fc633b63 334 strncpy (root_dir, tmp_buf, MAX_PATH);
149da470
ED
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
149da470
ED
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
fc633b63 350 {
149da470
ED
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 */
fc633b63
CF
356 sym_opt = (!is_remote_drive && strcmp (fs_name, "NTFS") == 0) ? PC_CHECK_EA : 0;
357 }
149da470
ED
358 }
359}
360
1fd5e000
CF
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
55fc91b9 374void
5bc584ba
CF
375path_conv::check (const char *src, unsigned opt,
376 const suffix_info *suffixes)
1fd5e000
CF
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. */
b98ebf54
CF
381 char path_copy[MAX_PATH + 3];
382 char tmp_buf[2 * MAX_PATH + 3];
2cf9359a 383 symlink_info sym;
829425c9 384 bool need_directory = 0;
bdfeca60 385 bool saw_symlinks = 0;
d3c7e9de 386 int is_relpath;
7a4078ee 387 sigframe thisframe (mainthread);
1fd5e000 388
ad30b4ff
CF
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
b9815dc3
CF
400 int loop = 0;
401 path_flags = 0;
402 known_suffix = NULL;
403 fileattr = (DWORD) -1;
404 case_clash = FALSE;
405 devn = unit = 0;
149da470
ED
406 root_dir[0] = '\0';
407 fs_name[0] = '\0';
408 fs_flags = fs_serial = 0;
409 sym_opt = 0;
ecfb6f11
CF
410 drive_type = 0;
411 is_remote_drive = 0;
b9815dc3 412
5bc584ba
CF
413 if (!(opt & PC_NULLEMPTY))
414 error = 0;
7a4078ee 415 else if ((error = check_null_empty_str (src)))
1fd5e000
CF
416 return;
417
1fd5e000 418 /* This loop handles symlink expansion. */
1fd5e000
CF
419 for (;;)
420 {
421 MALLOC_CHECK;
1ec4f618 422 assert (src);
947ab99e
CF
423
424 char *p = strrchr (src, '\0');
79201150
CF
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. */
947ab99e 428 if (--p > src)
6e604fb1 429 {
947ab99e
CF
430 if (isdirsep (*p))
431 need_directory = 1;
432 else if (--p > src && p[1] == '.' && isdirsep (*p))
829425c9 433 need_directory = 1;
6e604fb1 434 }
b98ebf54 435
d3c7e9de 436 is_relpath = !isabspath (src);
b98ebf54 437 error = normalize_posix_path (src, path_copy);
9e2baf8d 438 if (error)
1fd5e000 439 return;
1fd5e000 440
b98ebf54
CF
441 char *tail = strchr (path_copy, '\0'); // Point to end of copy
442 char *path_end = tail;
443 tail[1] = '\0';
1fd5e000 444
1fd5e000
CF
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
2cf9359a 449 symlink.check as the caller may need it. */
1fd5e000
CF
450 /* FIXME: Do we have to worry about multiple \'s here? */
451 int component = 0; // Number of translated components
2cf9359a
CF
452 sym.contents[0] = '\0';
453
1fd5e000
CF
454 for (;;)
455 {
1fd5e000 456 const suffix_info *suff;
b98ebf54 457 char pathbuf[MAX_PATH];
d3c7e9de 458 char *full_path;
9e2baf8d 459
2cf9359a 460 /* Don't allow symlink.check to set anything in the path_conv
1fd5e000
CF
461 class if we're working on an inner component of the path */
462 if (component)
463 {
c5a4eacc 464 suff = NULL;
2cf9359a 465 sym.pflags = 0;
d3c7e9de 466 full_path = pathbuf;
1fd5e000
CF
467 }
468 else
469 {
1fd5e000 470 suff = suffixes;
164a681c 471 sym.pflags = path_flags;
d3c7e9de 472 full_path = this->path;
1fd5e000 473 }
1fd5e000 474
79201150 475 /* Convert to native path spec sans symbolic link info. */
d3c7e9de 476 error = mount_table->conv_to_win32_path (path_copy, full_path, devn,
7ceb1cac
CF
477 unit, &sym.pflags, 1);
478
479 if (error)
480 return;
2b5803d4 481
79201150 482 /* devn should not be a device. If it is, then stop parsing now. */
2b5803d4
CF
483 if (devn != FH_BAD)
484 {
cbed6474
CF
485 if (component)
486 {
487 error = ENOTDIR;
488 return;
489 }
2b5803d4
CF
490 fileattr = 0;
491 goto out; /* Found a device. Stop parsing. */
492 }
493
32fb80db
CF
494 update_fs_info (full_path);
495
2b5803d4 496 /* Eat trailing slashes */
d3c7e9de 497 char *dostail = strchr (full_path, '\0');
2b5803d4
CF
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. */
d3c7e9de 502 while (dostail > full_path + 3 && (*--dostail == '\\'))
2b5803d4
CF
503 *tail = '\0';
504
d3c7e9de 505 if (full_path[0] && full_path[1] == ':' && full_path[2] == '\0')
79201150
CF
506 {
507 full_path[2] = '\\';
508 full_path[3] = '\0';
509 }
2b5803d4
CF
510
511 if ((opt & PC_SYM_IGNORE) && pcheck_case == PCHECK_RELAXED)
512 {
d3c7e9de 513 fileattr = GetFileAttributesA (full_path);
2b5803d4
CF
514 goto out;
515 }
516
fc633b63 517 int len = sym.check (full_path, suff, opt | sym_opt);
2cf9359a 518
70c370d6
CV
519 if (sym.case_clash)
520 {
0f565126 521 if (pcheck_case == PCHECK_STRICT)
ac5561f2 522 {
0f565126
CV
523 case_clash = TRUE;
524 error = ENOENT;
525 goto out;
526 }
527 /* If pcheck_case==PCHECK_ADJUST the case_clash is remembered
ac5561f2 528 if the last component is concerned. This allows functions
0f565126
CV
529 which shall create files to avoid overriding already existing
530 files with another case. */
531 if (!component)
ac5561f2 532 case_clash = TRUE;
70c370d6 533 }
2cf9359a 534
70c370d6 535 if (!(opt & PC_SYM_IGNORE))
1fd5e000 536 {
70c370d6
CV
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)
1fd5e000 544 {
70c370d6
CV
545 error = sym.error;
546 if (component == 0)
547 {
548 fileattr = sym.fileattr;
e61cead3 549 add_ext_from_sym (sym);
70c370d6
CV
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;
1fd5e000 556 }
70c370d6
CV
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)
1fd5e000 563 {
70c370d6
CV
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)
ac5561f2 570 {
70c370d6
CV
571 strcpy (path, sym.contents);
572 goto out;
573 }
e61cead3 574 add_ext_from_sym (sym);
70c370d6 575 if (pcheck_case == PCHECK_RELAXED)
ac5561f2 576 goto out;
70c370d6 577 /* Avoid further symlink evaluation. Only case checks are
ac5561f2 578 done now. */
70c370d6
CV
579 opt |= PC_SYM_IGNORE;
580 }
581 else
582 break;
1fd5e000 583 }
70c370d6 584 /* No existing file found. */
70c370d6 585 }
1fd5e000 586
79201150
CF
587 /* Find the "tail" of the path, e.g. in '/for/bar/baz',
588 /baz is the tail. */
b98ebf54
CF
589 char *newtail = strrchr (path_copy, '/');
590 if (tail != path_end)
591 *tail = '/';
592
79201150
CF
593 /* Exit loop if there is no tail or we are at the
594 beginning of a UNC path */
c0a45b92 595 if (!newtail || newtail == path_copy || (newtail == path_copy + 1 && newtail[-1] == '/'))
9e2baf8d 596 goto out; // all done
1fd5e000 597
b98ebf54
CF
598 tail = newtail;
599
bdfeca60 600 /* Haven't found an existing pathname component yet.
1fd5e000
CF
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 }
b98ebf54 612
1fd5e000
CF
613 MALLOC_CHECK;
614
79201150
CF
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. */
c0a45b92 618 int taillen = strlen (++tail);
2cf9359a 619 int buflen = strlen (sym.contents);
1fd5e000
CF
620 if (buflen + taillen > MAX_PATH)
621 {
622 error = ENAMETOOLONG;
623 strcpy (path, "::ENAMETOOLONG::");
624 return;
625 }
626
79201150
CF
627 /* Strip off current directory component since this is the part that refers
628 to the symbolic link. */
b98ebf54
CF
629 if ((p = strrchr (path_copy, '/')) == NULL)
630 p = path_copy;
41d53c98
CF
631 else if (p == path_copy)
632 p++;
1fd5e000
CF
633 *p = '\0';
634
b98ebf54 635 char *headptr;
2cf9359a 636 if (isabspath (sym.contents))
79201150 637 headptr = tmp_buf; /* absolute path */
1fd5e000
CF
638 else
639 {
79201150 640 /* Copy the first part of the path and point to the end. */
b98ebf54
CF
641 strcpy (tmp_buf, path_copy);
642 headptr = strchr (tmp_buf, '\0');
1fd5e000 643 }
b98ebf54 644
79201150 645 /* See if we need to separate first part + symlink contents with a / */
b98ebf54
CF
646 if (headptr > tmp_buf && headptr[-1] != '/')
647 *headptr++ = '/';
fc633b63 648
79201150
CF
649 /* Copy the symlink contents to the end of tmp_buf.
650 Convert slashes. FIXME? */
b98ebf54
CF
651 for (p = sym.contents; *p; p++)
652 *headptr++ = *p == '\\' ? '/' : *p;
79201150
CF
653
654 /* Copy any tail component */
c0a45b92 655 if (tail >= path_end)
b98ebf54
CF
656 *headptr = '\0';
657 else
658 {
659 *headptr++ = '/';
660 strcpy (headptr, tail);
661 }
662
79201150 663 /* Now evaluate everything all over again. */
b98ebf54 664 src = tmp_buf;
1fd5e000 665 }
0d60da26 666
e61cead3
CV
667 if (!(opt & PC_SYM_CONTENTS))
668 add_ext_from_sym (sym);
0d60da26 669
1fd5e000 670out:
829425c9
CF
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 }
70c370d6 683
32fb80db 684 if (devn == FH_BAD)
5d4af61e 685 {
32fb80db
CF
686 update_fs_info (path);
687 if (!fs_name[0])
688 {
689 set_has_acls (FALSE);
690 set_has_buggy_open (FALSE);
691 }
5827f4d9 692 else
32fb80db
CF
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 }
5d4af61e 705 }
0476bae5
CF
706#if 0
707 if (issocket ())
708 devn = FH_SOCKET;
709#endif
ad30b4ff 710
d3c7e9de
CF
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
bdfeca60
CF
729 if (saw_symlinks)
730 set_has_symlinks ();
731
95a8465b
CF
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
ad30b4ff
CF
742#if 0
743 if (!error)
744 {
745 last_path_conv = *this;
746 strcpy (last_src, src);
747 }
748#endif
1fd5e000
CF
749}
750
1fd5e000
CF
751static __inline int
752digits (const char *name)
753{
754 char *p;
755 int n = strtol(name, &p, 10);
756
757 return p > name && !*p ? n : -1;
758}
759
57c89867 760const char *windows_device_names[] NO_COPY =
1fd5e000
CF
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",
fc633b63 775
e6629a8a 776 NULL, NULL, NULL,
1fd5e000
CF
777
778 "\\dev\\disk",
779 "\\dev\\fd%d",
780 "\\dev\\st%d",
781 "nul",
782 "\\dev\\zero",
1c0c369b 783 "\\dev\\%srandom",
51c22a5c 784 "\\dev\\mem",
e6f5c9d5 785 "\\dev\\clipboard",
adfd477d 786 "\\dev\\dsp"
1fd5e000
CF
787};
788
8af0f81d
CF
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
796static int __stdcall
797get_devn (const char *name, int &unit)
1fd5e000 798{
8af0f81d
CF
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;
1fd5e000 855
8af0f81d
CF
856 return devn;
857}
858
99069065
CV
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*/
8af0f81d 896static int
99069065 897get_raw_device_number (const char *name, const char *w32_path, int &unit)
8af0f81d 898{
99069065
CV
899 DWORD devn = FH_BAD;
900
901 if (!w32_path) /* New approach using fixed device names. */
1fd5e000 902 {
99069065
CV
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 }
1fd5e000 943 }
99069065 944 else /* Backward compatible checking of mount table device mapping. */
1fd5e000 945 {
99069065
CV
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 }
1fd5e000
CF
964 }
965 return devn;
966}
967
8af0f81d
CF
968static int __stdcall get_device_number (const char *unix_path,
969 const char *w32_path, int &unit)
970 __attribute__ ((regparm(3)));
971static int __stdcall
972get_device_number (const char *unix_path, const char *w32_path, int &unit)
1fd5e000
CF
973{
974 DWORD devn = FH_BAD;
975 unit = 0;
976
8af0f81d 977 if (*unix_path == '/' && udeveqn ("/dev/", 5))
99069065
CV
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 }
1fd5e000
CF
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
996static BOOL
997win32_device_name (const char *src_path, char *win32_path,
998 DWORD &devn, int &unit)
999{
1000 const char *devfmt;
1001
99069065 1002 devn = get_device_number (src_path, win32_path, unit);
1fd5e000
CF
1003
1004 if (devn == FH_BAD)
1005 return FALSE;
1006
1007 if ((devfmt = windows_device_names[FHDEVN (devn)]) == NULL)
1008 return FALSE;
99069065
CV
1009 switch (devn)
1010 {
1011 case FH_RANDOM:
1012 __small_sprintf (win32_path, devfmt, unit == 8 ? "" : "u");
1013 break;
1014 case FH_TAPE:
081be67e 1015 __small_sprintf (win32_path, "\\Device\\Tape%d", unit % 128);
99069065
CV
1016 break;
1017 case FH_FLOPPY:
1018 if (unit < 16)
081be67e 1019 __small_sprintf (win32_path, "\\Device\\Floppy%d", unit);
99069065 1020 else if (unit < 32)
081be67e 1021 __small_sprintf (win32_path, "\\Device\\CdRom%d", unit - 16);
99069065 1022 else if (unit < 224)
081be67e 1023 __small_sprintf (win32_path, "\\Device\\Harddisk%d\\Partition%d",
99069065
CV
1024 (unit - 32) / 16, unit % 16);
1025 else
081be67e 1026 __small_sprintf (win32_path, "\\DosDevices\\%c:", unit - 224 + 'A');
99069065
CV
1027 break;
1028 default:
1029 __small_sprintf (win32_path, devfmt, unit);
1030 break;
1031 }
1fd5e000
CF
1032 return TRUE;
1033}
1034
1fd5e000
CF
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. */
1fd5e000 1041static int
7e24f1bf 1042normalize_win32_path (const char *src, char *dst)
1fd5e000
CF
1043{
1044 const char *src_start = src;
1045 char *dst_start = dst;
a67f4165 1046 char *dst_root_start = dst;
307cb8ba 1047 bool beg_src_slash = isdirsep (src[0]);
1fd5e000 1048
307cb8ba 1049 if (beg_src_slash && isdirsep (src[1]))
1fd5e000
CF
1050 {
1051 *dst++ = '\\';
c27a2981
CF
1052 src++;
1053 if (src[1] == '.' && isdirsep (src[2]))
1054 {
1055 *dst++ = '\\';
1056 *dst++ = '.';
1057 src += 2;
1058 }
1fd5e000 1059 }
307cb8ba 1060 else if (strchr (src, ':') == NULL && *src != '/')
82c8d7ef 1061 {
431ba7dd 1062 if (!cygheap->cwd.get (dst, 0))
82c8d7ef
CF
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 }
1fd5e000
CF
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])))
7fbcbc95 1093 src += 2;
1fd5e000
CF
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. */
a67f4165 1102 if (dst > dst_root_start + 1)
1fd5e000
CF
1103 dst--;
1104 /* Now back up to the next /. */
a67f4165 1105 while (dst > dst_root_start + 1 && dst[-1] != '\\' && dst[-2] != ':')
1fd5e000
CF
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 }
7fbcbc95
CF
1120 if ((dst - dst_start) >= MAX_PATH)
1121 return ENAMETOOLONG;
1fd5e000
CF
1122 }
1123 *dst = 0;
1124 debug_printf ("%s = normalize_win32_path (%s)", dst_start, src_start);
1125 return 0;
1126}
1fd5e000
CF
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
1134static void
1135slashify (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
1158static void
1159backslashify (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
1181void __stdcall
1182nofinalslash (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
1fd5e000
CF
1191/* slash_unc_prefix_p: Return non-zero if PATH begins with //UNC/SHARE */
1192
1193int __stdcall
1194slash_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])
191bacb0 1202 && ((p = strpbrk(path + 3, "\\/")) != NULL));
1fd5e000
CF
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
1217static void
1218conv_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
1fd5e000
CF
1249/* init: Initialize the mount table. */
1250
1251void
1252mount_info::init ()
1253{
1fd5e000
CF
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 ();
1fd5e000
CF
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
1275int
d3c7e9de 1276mount_info::conv_to_win32_path (const char *src_path, char *dst,
7ceb1cac
CF
1277 DWORD &devn, int &unit, unsigned *flags,
1278 bool no_normalize)
1fd5e000 1279{
9a089f21
CF
1280 while (sys_mount_table_counter < cygwin_shared->sys_mount_table_counter)
1281 {
1282 init ();
1283 sys_mount_table_counter++;
1284 }
1fd5e000 1285 int src_path_len = strlen (src_path);
1fd5e000 1286 MALLOC_CHECK;
1fd5e000 1287 unsigned dummy_flags;
7ceb1cac 1288 int chroot_ok = !cygheap->root.exists ();
1fd5e000
CF
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;
1fd5e000
CF
1306 mount_item *mi = NULL; /* initialized to avoid compiler warning */
1307 char pathbuf[MAX_PATH];
1308
fc6f4e20
CF
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. */
cedb00be 1314 if (strpbrk (src_path, ":\\") != NULL || slash_unc_prefix_p (src_path))
1fd5e000
CF
1315 {
1316 debug_printf ("%s already win32", src_path);
7e24f1bf 1317 rc = normalize_win32_path (src_path, dst);
1fd5e000 1318 if (rc)
fc6f4e20
CF
1319 {
1320 debug_printf ("normalize_win32_path failed, rc %d", rc);
1321 return rc;
1322 }
d3c7e9de 1323
523ebbe0 1324 *flags = set_flags_from_win32_path (dst);
d3c7e9de 1325 goto out;
1fd5e000
CF
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
7ceb1cac
CF
1344 if (no_normalize)
1345 strcpy (pathbuf, src_path);
1346 else
1fd5e000 1347 {
7ceb1cac
CF
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 }
1fd5e000 1356 }
1fd5e000 1357
1fd5e000
CF
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? */
7ceb1cac
CF
1362 rc = 0;
1363 goto out_no_chroot_check;
1fd5e000
CF
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 {
d3c7e9de 1371 if (!cygdrive_win32_path (pathbuf, dst, 0))
1fd5e000
CF
1372 return ENOENT;
1373 *flags = cygdrive_flags;
d3c7e9de 1374 goto out;
1fd5e000
CF
1375 }
1376
7ceb1cac
CF
1377 int chrooted_path_len;
1378 chrooted_path_len = 0;
1fd5e000
CF
1379 /* Check the mount table for prefix matches. */
1380 for (i = 0; i < nmounts; i++)
1381 {
7ceb1cac
CF
1382 const char *path;
1383 int len;
1384
1fd5e000 1385 mi = mount + posix_sorted[i];
7ceb1cac
CF
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))
1fd5e000
CF
1404 break;
1405 }
1406
1407 if (i >= nmounts)
1408 {
86f41a09 1409 backslashify (pathbuf, dst, 0); /* just convert */
1fd5e000
CF
1410 *flags = 0;
1411 }
1412 else
1413 {
7ceb1cac
CF
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;
c3a245f5
CF
1434 if (*p == '/')
1435 /* nothing */;
1436 else if ((isdrive (dst) && !dst[2]) || *p)
d3c7e9de
CF
1437 dst[n++] = '\\';
1438 strcpy (dst + n, p);
1439 backslashify (dst, dst, 0);
1fd5e000
CF
1440 *flags = mi->flags;
1441 }
1442
99069065 1443 win32_device_name (src_path, dst, devn, unit);
8af0f81d 1444
7ceb1cac 1445 out:
1fd5e000 1446 MALLOC_CHECK;
7ceb1cac
CF
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;
1fd5e000
CF
1459}
1460
1fd5e000
CF
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
1465void
1466mount_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. */
2556e737 1475 dst[len++] = cyg_tolower (src[0]);
6201d15e 1476 if (!src[2] || (SLASH_P (src[2]) && !src[3]))
1fd5e000
CF
1477 dst[len++] = '\000';
1478 else
1479 {
dc7f5226 1480 int n;
1fd5e000 1481 dst[len++] = '/';
dc7f5226
CF
1482 if (SLASH_P (src[2]))
1483 n = 3;
1484 else
1485 n = 2;
1486 strcpy (dst + len, src + n);
1fd5e000
CF
1487 }
1488 slashify (dst, dst, trailing_slash_p);
1489}
1490
1491int
1492mount_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
1511int
1512mount_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);
6201d15e
CF
1516 int relative_path_p = !isabspath (src_path);
1517 int trailing_slash_p;
1fd5e000 1518
6201d15e
CF
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 }
9e2baf8d 1526
2dd78662
CF
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");
1fd5e000
CF
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. */
6b762a4e 1540
1fd5e000
CF
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];
7e24f1bf 1549 int rc = normalize_win32_path (src_path, pathbuf);
1fd5e000
CF
1550 if (rc != 0)
1551 {
1552 debug_printf ("%d = conv_to_posix_path (%s)", rc, src_path);
1553 return rc;
1554 }
1fd5e000
CF
1555
1556 int pathbuflen = strlen (pathbuf);
1557 for (int i = 0; i < nmounts; ++i)
1558 {
1559 mount_item &mi = mount[native_sorted[i]];
95a8465b 1560 if (!path_prefix_p (mi.native_path, pathbuf, mi.native_pathlen))
1fd5e000
CF
1561 continue;
1562
7ceb1cac
CF
1563 if (cygheap->root.exists () && !cygheap->root.posix_ok (mi.posix_path))
1564 continue;
1565
1fd5e000
CF
1566 /* SRC_PATH is in the mount table. */
1567 int nextchar;
2dd78662
CF
1568 const char *p = pathbuf + mi.native_pathlen;
1569
1570 if (!*p || !p[1])
1fd5e000 1571 nextchar = 0;
2dd78662 1572 else if (isdirsep (*p))
1fd5e000
CF
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)
2dd78662 1584 slashify (p,
1fd5e000 1585 posix_path + addslash + (mi.posix_pathlen == 1 ? 0 : mi.posix_pathlen),
2dd78662 1586 trailing_slash_p);
7ceb1cac
CF
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 }
1fd5e000
CF
1593 goto out;
1594 }
1595
7ceb1cac
CF
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
1fd5e000
CF
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. */
75858e8a 1617 if (isdrive (pathbuf))
6201d15e 1618 cygdrive_posix_path (pathbuf, posix_path, trailing_slash_p);
1fd5e000
CF
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
1626out:
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
1634unsigned
1635mount_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
1649void
1650mount_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;
9a02bdb5 1655 int res;
1fd5e000
CF
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. */
9a02bdb5 1661 for (i = 0; ; i++)
1fd5e000
CF
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
95a8465b 1669 over 256 but is under MAX_PATH. */
9a02bdb5 1670 res = RegEnumKeyEx (key, i, posix_path, &posix_path_size, NULL,
1fd5e000
CF
1671 NULL, NULL, NULL);
1672
9a02bdb5 1673 if (res == ERROR_NO_MORE_ITEMS)
1fd5e000 1674 break;
9a02bdb5 1675 else if (res != ERROR_SUCCESS)
1fd5e000 1676 {
9a02bdb5 1677 debug_printf ("RegEnumKeyEx failed, error %d!\n", res);
1fd5e000
CF
1678 break;
1679 }
1680
1fd5e000
CF
1681 /* Get a reg_key based on i. */
1682 reg_key subkey = reg_key (key, KEY_READ, posix_path, NULL);
1683
1fd5e000
CF
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. */
2a6fc028 1689 res = mount_table->add_item (native_path, posix_path, mount_flags, FALSE);
95bdb496
CV
1690 if (res && get_errno () == EMFILE)
1691 break; /* The number of entries exceeds MAX_MOUNTS */
1692 }
1fd5e000
CF
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
1698void
1699mount_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",
a9f20457 1716 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1fd5e000
CF
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 ();
1fd5e000
CF
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
1731int
1732mount_info::add_reg_mount (const char * native_path, const char * posix_path, unsigned mountflags)
1733{
9a02bdb5
CF
1734 int res = 0;
1735
1fd5e000
CF
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. */
9a02bdb5
CF
1744 res = reg_user.kill (posix_path);
1745 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1746 goto err;
1fd5e000
CF
1747
1748 /* Create the new mount. */
1749 reg_key subkey = reg_key (reg_user.get_key (),
1750 KEY_ALL_ACCESS,
1751 posix_path, NULL);
9a02bdb5
CF
1752 res = subkey.set_string ("native", native_path);
1753 if (res != ERROR_SUCCESS)
1754 goto err;
1755 res = subkey.set_int ("flags", mountflags);
1fd5e000
CF
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",
a9f20457 1761 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1fd5e000
CF
1762 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1763 NULL);
1764
1fd5e000 1765 /* Start by deleting existing mount if one exists. */
9a02bdb5
CF
1766 res = reg_sys.kill (posix_path);
1767 if (res != ERROR_SUCCESS && res != ERROR_FILE_NOT_FOUND)
1768 goto err;
1fd5e000
CF
1769
1770 /* Create the new mount. */
1771 reg_key subkey = reg_key (reg_sys.get_key (),
1772 KEY_ALL_ACCESS,
1773 posix_path, NULL);
9a02bdb5
CF
1774 res = subkey.set_string ("native", native_path);
1775 if (res != ERROR_SUCCESS)
1776 goto err;
1777 res = subkey.set_int ("flags", mountflags);
9a089f21
CF
1778
1779 sys_mount_table_counter++;
1780 cygwin_shared->sys_mount_table_counter++;
1fd5e000
CF
1781 }
1782
95a8465b 1783 return 0; /* Success */
9a02bdb5
CF
1784 err:
1785 __seterrno_from_win_error (res);
1786 return -1;
1fd5e000
CF
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
1793int
1794mount_info::del_reg_mount (const char * posix_path, unsigned flags)
1795{
9a02bdb5 1796 int res;
1fd5e000 1797
9a089f21 1798 if (!(flags & MOUNT_SYSTEM)) /* Delete from user registry */
1fd5e000
CF
1799 {
1800 reg_key reg_user (KEY_ALL_ACCESS,
1801 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, NULL);
9a02bdb5 1802 res = reg_user.kill (posix_path);
1fd5e000 1803 }
9e2baf8d 1804 else /* Delete from system registry */
1fd5e000 1805 {
9a089f21
CF
1806 sys_mount_table_counter++;
1807 cygwin_shared->sys_mount_table_counter++;
1fd5e000 1808 reg_key reg_sys (HKEY_LOCAL_MACHINE, KEY_ALL_ACCESS, "SOFTWARE",
a9f20457 1809 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
1fd5e000
CF
1810 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1811 NULL);
9a02bdb5 1812 res = reg_sys.kill (posix_path);
1fd5e000
CF
1813 }
1814
9a02bdb5 1815 if (res != ERROR_SUCCESS)
1fd5e000 1816 {
9a02bdb5 1817 __seterrno_from_win_error (res);
1fd5e000
CF
1818 return -1;
1819 }
1820
95a8465b 1821 return 0; /* Success */
1fd5e000
CF
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
1828void
1829mount_info::read_cygdrive_info_from_registry ()
1830{
637f5ce0 1831 /* reg_key for user path prefix in HKEY_CURRENT_USER. */
1fd5e000
CF
1832 reg_key r;
1833
a98b1584
CF
1834 if (r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
1835 "") != 0)
1fd5e000 1836 {
637f5ce0
CF
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. */
93c1e56b 1840 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
a9f20457 1841 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
637f5ce0
CF
1842 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1843 NULL);
1844
a98b1584
CF
1845 if (r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, cygdrive, sizeof (cygdrive),
1846 "") != 0)
637f5ce0 1847 {
9e2baf8d 1848 /* Didn't find either so write the default to the registry and use it.
637f5ce0 1849 NOTE: We are writing and using the user path prefix. */
a98b1584
CF
1850 write_cygdrive_info_to_registry (CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX,
1851 MOUNT_AUTO);
637f5ce0
CF
1852 }
1853 else
1854 {
9e2baf8d 1855 /* Fetch system cygdrive_flags from registry; returns MOUNT_AUTO on
637f5ce0 1856 error. */
a98b1584 1857 cygdrive_flags = r2.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
9e2baf8d
CF
1858 slashify (cygdrive, cygdrive, 1);
1859 cygdrive_len = strlen(cygdrive);
637f5ce0 1860 }
1fd5e000
CF
1861 }
1862 else
1863 {
637f5ce0 1864 /* Fetch user cygdrive_flags from registry; returns MOUNT_AUTO on
9e2baf8d 1865 error. */
a98b1584 1866 cygdrive_flags = r.get_int (CYGWIN_INFO_CYGDRIVE_FLAGS, MOUNT_AUTO);
1fd5e000
CF
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
1876int
1877mount_info::write_cygdrive_info_to_registry (const char *cygdrive_prefix, unsigned flags)
1878{
637f5ce0
CF
1879 /* Determine whether to modify user or system cygdrive path prefix. */
1880 HKEY top = (flags & MOUNT_SYSTEM) ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER;
1881
9a089f21
CF
1882 if (flags & MOUNT_SYSTEM)
1883 {
1884 sys_mount_table_counter++;
1885 cygwin_shared->sys_mount_table_counter++;
1886 }
1887
637f5ce0
CF
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",
a9f20457 1891 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
637f5ce0
CF
1892 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1893 NULL);
1fd5e000
CF
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) ||
6b762a4e
CF
1898 (!isslash (cygdrive_prefix[0])) ||
1899 ((cygdrive_prefix[1] != '\0') && (isslash (cygdrive_prefix[1]))))
1fd5e000
CF
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
9a02bdb5 1909 int res;
a98b1584 1910 res = r.set_string (CYGWIN_INFO_CYGDRIVE_PREFIX, hold_cygdrive_prefix);
9a02bdb5
CF
1911 if (res != ERROR_SUCCESS)
1912 {
1913 __seterrno_from_win_error (res);
1914 return -1;
1915 }
a98b1584 1916 r.set_int (CYGWIN_INFO_CYGDRIVE_FLAGS, flags);
1fd5e000 1917
637f5ce0
CF
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 */
9a089f21 1922 if (!(flags & MOUNT_SYSTEM) || (mount_table->cygdrive_flags & MOUNT_SYSTEM))
637f5ce0 1923 {
2a6fc028
CF
1924 slashify (cygdrive_prefix, mount_table->cygdrive, 1);
1925 mount_table->cygdrive_flags = flags;
1926 mount_table->cygdrive_len = strlen(mount_table->cygdrive);
637f5ce0 1927 }
1fd5e000
CF
1928
1929 return 0;
1930}
1931
637f5ce0
CF
1932int
1933mount_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
9a089f21
CF
1938 if (flags & MOUNT_SYSTEM)
1939 {
1940 sys_mount_table_counter++;
1941 cygwin_shared->sys_mount_table_counter++;
1942 }
1943
637f5ce0
CF
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",
a9f20457 1947 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
637f5ce0
CF
1948 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1949 NULL);
1950
1951 /* Delete cygdrive prefix and flags. */
a98b1584
CF
1952 int res = r.killvalue (CYGWIN_INFO_CYGDRIVE_PREFIX);
1953 int res2 = r.killvalue (CYGWIN_INFO_CYGDRIVE_FLAGS);
637f5ce0
CF
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
1962int
9bc846bd
CF
1963mount_info::get_cygdrive_info (char *user, char *system, char* user_flags,
1964 char* system_flags)
637f5ce0
CF
1965{
1966 /* Get the user path prefix from HKEY_CURRENT_USER. */
1967 reg_key r;
a98b1584 1968 int res = r.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, user, MAX_PATH, "");
637f5ce0 1969
9bc846bd
CF
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
637f5ce0 1977 /* Get the system path prefix from HKEY_LOCAL_MACHINE. */
93c1e56b 1978 reg_key r2 (HKEY_LOCAL_MACHINE, KEY_READ, "SOFTWARE",
a9f20457 1979 CYGWIN_INFO_CYGNUS_REGISTRY_NAME, CYGWIN_REGNAME,
637f5ce0
CF
1980 CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME,
1981 NULL);
a98b1584 1982 int res2 = r2.get_string (CYGWIN_INFO_CYGDRIVE_PREFIX, system, MAX_PATH, "");
637f5ce0 1983
9bc846bd
CF
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
637f5ce0
CF
1991 return (res != ERROR_SUCCESS) ? res : res2;
1992}
1993
1fd5e000
CF
1994static 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??? */
2000static int
2001sort_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 */
9a089f21 2023 if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */
1fd5e000
CF
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??? */
2036static int
2037sort_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. */
ebbd4e8f 2054 res = strcmp (ap->native_path, bp->native_path);
1fd5e000
CF
2055
2056 if (res == 0)
2057 {
2058 /* need to select between user and system mount to same POSIX path */
9a089f21 2059 if (!(bp->flags & MOUNT_SYSTEM)) /* user mount */
1fd5e000
CF
2060 return 1;
2061 else
2062 return -1;
2063 }
2064
2065 return res;
2066}
2067
2068void
2069mount_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
95bdb496 2080/* Add an entry to the mount table.
1fd5e000
CF
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
2086int
95bdb496 2087mount_info::add_item (const char *native, const char *posix, unsigned mountflags, int reg_p)
1fd5e000 2088{
1fd5e000
CF
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) ||
9a02bdb5
CF
2094 !isabspath (native) || !isabspath (posix) ||
2095 slash_unc_prefix_p (posix) || isdrive (posix))
1fd5e000
CF
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
86f41a09 2105 backslashify (native, nativetmp, 0);
54ee4247 2106 nofinalslash (nativetmp, nativetmp);
1fd5e000
CF
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. */
95bdb496
CV
2126 int i;
2127 for (i = 0; i < nmounts; i++)
1fd5e000 2128 {
95bdb496
CV
2129 if (strcasematch (mount[i].posix_path, posixtmp) &&
2130 (mount[i].flags & MOUNT_SYSTEM) == (mountflags & MOUNT_SYSTEM))
2131 break;
1fd5e000
CF
2132 }
2133
9a02bdb5 2134 if (i == nmounts && nmounts == MAX_MOUNTS)
95bdb496 2135 {
9a02bdb5
CF
2136 set_errno (EMFILE);
2137 return -1;
95bdb496
CV
2138 }
2139
2140 if (reg_p && add_reg_mount (nativetmp, posixtmp, mountflags))
2141 return -1;
1fd5e000 2142
9a02bdb5
CF
2143 if (i == nmounts)
2144 nmounts++;
95bdb496 2145 mount[i].init (nativetmp, posixtmp, mountflags);
1fd5e000
CF
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
2159int
95bdb496 2160mount_info::del_item (const char *path, unsigned flags, int reg_p)
1fd5e000
CF
2161{
2162 char pathtmp[MAX_PATH];
54ee4247 2163 int posix_path_p = FALSE;
1fd5e000
CF
2164
2165 /* Something's wrong if path is NULL or empty. */
54ee4247 2166 if (path == NULL || *path == 0 || !isabspath (path))
1fd5e000
CF
2167 {
2168 set_errno (EINVAL);
2169 return -1;
2170 }
2171
86f41a09
CF
2172 if (slash_unc_prefix_p (path) || strpbrk (path, ":\\"))
2173 backslashify (path, pathtmp, 0);
54ee4247
CF
2174 else
2175 {
2176 slashify (path, pathtmp, 0);
2177 posix_path_p = TRUE;
2178 }
1fd5e000
CF
2179 nofinalslash (pathtmp, pathtmp);
2180
54ee4247
CF
2181 if (reg_p && posix_path_p &&
2182 del_reg_mount (pathtmp, flags) &&
2183 del_reg_mount (path, flags)) /* for old irregular entries */
95bdb496
CV
2184 return -1;
2185
1fd5e000
CF
2186 for (int i = 0; i < nmounts; i++)
2187 {
54ee4247
CF
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))
1fd5e000 2193 {
54ee4247
CF
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 */
1fd5e000 2199 /* Fill in the hole if not at the end of the table */
54ee4247
CF
2200 if (ent < nmounts)
2201 memmove (mount + ent, mount + ent + 1,
2202 sizeof (mount[ent]) * (nmounts - ent));
2203 sort (); /* Resort the table */
1fd5e000
CF
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
2217void
2218mount_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
2a6fc028 2249 int res = mount_table->add_item (win32path, unixpath, mountflags, TRUE);
95bdb496
CV
2250 if (res && get_errno () == EMFILE)
2251 break; /* The number of entries exceeds MAX_MOUNTS */
1fd5e000
CF
2252 }
2253 }
2254}
2255
95bdb496
CV
2256/* import_v1_mounts: If v1 mounts are present, load them and write
2257 the new entries to the new registry area. */
1fd5e000
CF
2258
2259void
95bdb496 2260mount_info::import_v1_mounts ()
1fd5e000
CF
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);
1fd5e000
CF
2284}
2285
2286/************************* mount_item class ****************************/
2287
f2aeff27
CF
2288static mntent *
2289fillout_mntent (const char *native_path, const char *posix_path, unsigned flags)
1fd5e000
CF
2290{
2291#ifdef _MT_SAFE
f2aeff27 2292 struct mntent &ret=_reent_winsup()->mntbuf;
1fd5e000
CF
2293#else
2294 static NO_COPY struct mntent ret;
2295#endif
2296
5817ee2d
CF
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
2a6fc028 2305 /* Pass back pointers to mount_table strings reserved for use by
1fd5e000
CF
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
f97adf98
CF
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;
1fd5e000 2314
9e2baf8d 2315 if (!(flags & MOUNT_SYSTEM)) /* user mount */
f97adf98 2316 strcpy (_reent_winsup ()->mnt_type, (char *) "user");
9e2baf8d 2317 else /* system mount */
f97adf98 2318 strcpy (_reent_winsup ()->mnt_type, (char *) "system");
1fd5e000 2319
f97adf98 2320 ret.mnt_type = _reent_winsup ()->mnt_type;
1fd5e000
CF
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
95a8465b 2326 if (!(flags & MOUNT_BINARY))
f97adf98 2327 strcpy (_reent_winsup ()->mnt_opts, (char *) "textmode");
1fd5e000 2328 else
f97adf98 2329 strcpy (_reent_winsup ()->mnt_opts, (char *) "binmode");
1fd5e000 2330
55fc91b9 2331 if (flags & MOUNT_CYGWIN_EXEC)
f97adf98 2332 strcat (_reent_winsup ()->mnt_opts, (char *) ",cygexec");
55fc91b9 2333 else if (flags & MOUNT_EXEC)
f97adf98 2334 strcat (_reent_winsup ()->mnt_opts, (char *) ",exec");
1fd5e000 2335
f97adf98
CF
2336 if ((flags & MOUNT_AUTO)) /* cygdrive */
2337 strcat (_reent_winsup ()->mnt_opts, (char *) ",noumount");
55fc91b9 2338
f97adf98 2339 ret.mnt_opts = _reent_winsup ()->mnt_opts;
1fd5e000
CF
2340
2341 ret.mnt_freq = 1;
2342 ret.mnt_passno = 1;
2343 return &ret;
2344}
2345
f2aeff27
CF
2346struct mntent *
2347mount_item::getmntent ()
2348{
2349 return fillout_mntent (native_path, posix_path, flags);
2350}
2351
2352static struct mntent *
2353cygdrive_getmntent ()
2354{
5817ee2d
CF
2355 char native_path[4];
2356 char posix_path[MAX_PATH];
2357 DWORD mask = 1, drive = 'a';
2358 struct mntent *ret = NULL;
f2aeff27 2359
5817ee2d
CF
2360 while (available_drives)
2361 {
2362 for (/* nothing */; drive <= 'z'; mask <<= 1, drive++)
2363 if (available_drives & mask)
2364 break;
f2aeff27 2365
5817ee2d
CF
2366 __small_sprintf (native_path, "%c:\\", drive);
2367 if (GetDriveType (native_path) == DRIVE_REMOVABLE ||
2368 GetFileAttributes (native_path) == (DWORD) -1)
ac5561f2 2369 {
5817ee2d
CF
2370 available_drives &= ~mask;
2371 continue;
ac5561f2 2372 }
5817ee2d
CF
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;
f2aeff27 2380}
fc633b63 2381
f2aeff27
CF
2382struct mntent *
2383mount_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
1fd5e000
CF
2391/* Fill in the fields of a mount table entry. */
2392
2393void
2394mount_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
f636c081 2414extern "C" int
1fd5e000
CF
2415mount (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. */
2a6fc028 2424 res = mount_table->write_cygdrive_info_to_registry (posix_path, flags);
1fd5e000
CF
2425 win32_path = NULL;
2426 }
2427 else
2a6fc028 2428 res = mount_table->add_item (win32_path, posix_path, flags, TRUE);
1fd5e000
CF
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
f636c081 2439extern "C" int
1fd5e000
CF
2440umount (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
f636c081 2449extern "C" int
1fd5e000
CF
2450cygwin_umount (const char *path, unsigned flags)
2451{
637f5ce0
CF
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
9e2baf8d 2457 to remove the cygdrive prefix and flags without actually unmounting
637f5ce0 2458 anything. */
2a6fc028 2459 res = mount_table->remove_cygdrive_info_from_registry (path, flags);
637f5ce0
CF
2460 }
2461 else
2462 {
2a6fc028 2463 res = mount_table->del_item (path, flags, TRUE);
637f5ce0 2464 }
1fd5e000
CF
2465
2466 syscall_printf ("%d = cygwin_umount (%s, %d)", res, path, flags);
2467 return res;
2468}
2469
f636c081 2470extern "C" FILE *
1fd5e000
CF
2471setmntent (const char *filep, const char *)
2472{
2473 iteration = 0;
f2aeff27 2474 available_drives = GetLogicalDrives ();
1fd5e000
CF
2475 return (FILE *) filep;
2476}
2477
f636c081 2478extern "C" struct mntent *
1fd5e000
CF
2479getmntent (FILE *)
2480{
2a6fc028 2481 return mount_table->getmntent (iteration++);
1fd5e000
CF
2482}
2483
f636c081 2484extern "C" int
1fd5e000
CF
2485endmntent (FILE *)
2486{
2487 return 1;
2488}
2489
2490/********************** Symbolic Link Support **************************/
2491
149da470
ED
2492/* Read symlink from Extended Attribute */
2493int
2494get_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 */
2503BOOL
2504set_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
1fd5e000
CF
2514/* Create a symlink from FROMPATH to TOPATH. */
2515
e03f5f73
CV
2516/* If TRUE create symlinks as Windows shortcuts, if FALSE create symlinks
2517 as normal files with magic number and system bit set. */
2518int allow_winsymlinks = TRUE;
2519
f636c081 2520extern "C" int
1fd5e000
CF
2521symlink (const char *topath, const char *frompath)
2522{
2523 HANDLE h;
2524 int res = -1;
e03f5f73 2525 path_conv win32_path, win32_topath;
649033a8 2526 char from[MAX_PATH + 5];
659b480b 2527 char cwd[MAX_PATH + 1], *cp = NULL, c = 0;
ff413a98 2528 char w32topath[MAX_PATH + 1];
e03f5f73 2529 DWORD written;
86fb0393 2530 SECURITY_ATTRIBUTES sa = sec_none_nih;
e03f5f73 2531
0aca521a
ED
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
70c370d6
CV
2545 win32_path.check (frompath, PC_SYM_NOFOLLOW);
2546 if (allow_winsymlinks && !win32_path.error)
e03f5f73
CV
2547 {
2548 strcpy (from, frompath);
2549 strcat (from, ".lnk");
2550 win32_path.check (from, PC_SYM_NOFOLLOW);
2551 }
10b06c5e 2552
1fd5e000
CF
2553 if (win32_path.error)
2554 {
70c370d6 2555 set_errno (win32_path.case_clash ? ECASECLASH : win32_path.error);
1fd5e000
CF
2556 goto done;
2557 }
2558
2559 syscall_printf ("symlink (%s, %s)", topath, win32_path.get_win32 ());
2560
47063f00 2561 if (win32_path.is_device () || win32_path.exists ())
1fd5e000
CF
2562 {
2563 set_errno (EEXIST);
2564 goto done;
2565 }
2566
e03f5f73
CV
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
86fb0393
CV
2593 if (allow_ntsec && win32_path.has_acls ())
2594 set_security_attribute (S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO,
4ce15a49 2595 &sa, alloca (4096), 4096);
86fb0393
CV
2596
2597 h = CreateFileA(win32_path, GENERIC_WRITE, 0, &sa,
1fd5e000
CF
2598 CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0);
2599 if (h == INVALID_HANDLE_VALUE)
2600 __seterrno ();
2601 else
2602 {
e03f5f73
CV
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,
ac5561f2 2613 &written, NULL)
e03f5f73
CV
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];
1fd5e000 2628
e03f5f73
CV
2629 __small_sprintf (buf, "%s%s", SYMLINK_COOKIE, topath);
2630 DWORD len = strlen (buf) + 1;
1fd5e000 2631
e03f5f73
CV
2632 /* Note that the terminating nul is written. */
2633 success = WriteFile (h, buf, len, &written, NULL)
ac5561f2 2634 || written != len;
e03f5f73
CV
2635
2636 }
2637 if (success)
1fd5e000
CF
2638 {
2639 CloseHandle (h);
86fb0393
CV
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);
e03f5f73 2644 SetFileAttributesA (win32_path.get_win32 (),
fc633b63
CF
2645 allow_winsymlinks ? FILE_ATTRIBUTE_READONLY
2646 : FILE_ATTRIBUTE_SYSTEM);
149da470 2647 if (win32_path.fs_fast_ea ())
fc633b63 2648 set_symlink_ea (win32_path, topath);
1fd5e000
CF
2649 res = 0;
2650 }
10b06c5e
CV
2651 else
2652 {
2653 __seterrno ();
2654 CloseHandle (h);
2655 DeleteFileA (win32_path.get_win32 ());
2656 }
1fd5e000
CF
2657 }
2658
2659done:
2660 syscall_printf ("%d = symlink (%s, %s)", res, topath, frompath);
2661 return res;
2662}
2663
79e56091
CV
2664static int
2665check_sysfile (const char *path, DWORD fileattr, HANDLE h,
2666 char *contents, int *error, unsigned *pflags)
10b06c5e
CV
2667{
2668 char cookie_buf[sizeof (SYMLINK_COOKIE) - 1];
2669 DWORD got;
2670 int res = 0;
2671
95a8465b 2672 if (!ReadFile (h, cookie_buf, sizeof (cookie_buf), &got, 0))
10b06c5e
CV
2673 {
2674 debug_printf ("ReadFile1 failed");
79e56091 2675 *error = EIO;
10b06c5e
CV
2676 }
2677 else if (got == sizeof (cookie_buf)
2678 && memcmp (cookie_buf, SYMLINK_COOKIE, sizeof (cookie_buf)) == 0)
2679 {
2680 /* It's a symlink. */
79e56091 2681 *pflags = PATH_SYMLINK;
10b06c5e
CV
2682
2683 res = ReadFile (h, contents, MAX_PATH + 1, &got, 0);
2684 if (!res)
2685 {
2686 debug_printf ("ReadFile2 failed");
79e56091 2687 *error = EIO;
10b06c5e
CV
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)
79e56091 2705 *pflags |= PATH_SOCKET;
10b06c5e
CV
2706 else
2707 {
2708 /* Not a symlink, see if executable. */
95a8465b
CF
2709 if (*pflags & PATH_ALL_EXEC)
2710 /* Nothing to do */;
2711 else if (has_exec_chars (cookie_buf, got))
79e56091 2712 *pflags |= PATH_EXEC;
95a8465b
CF
2713 else
2714 *pflags |= PATH_NOTEXEC;
2715 }
2716 syscall_printf ("%d = symlink.check_sysfile (%s, %s) (%p)",
2717 res, path, contents, *pflags);
96dc5dd7
CF
2718
2719 CloseHandle (h);
10b06c5e
CV
2720 return res;
2721}
2722
b65c6896
CF
2723enum
2724{
2725 SCAN_BEG,
2726 SCAN_LNK,
2727 SCAN_HASLNK,
2728 SCAN_JUSTCHECK,
b65c6896 2729 SCAN_APPENDLNK,
b63a3f55
CF
2730 SCAN_EXTRALNK,
2731 SCAN_DONE,
b65c6896 2732};
95a8465b
CF
2733
2734class suffix_scan
2735{
b63a3f55 2736 const suffix_info *suffixes, *suffixes_start;
b65c6896 2737 int nextstate;
b63a3f55 2738 char *eopath;
95a8465b
CF
2739public:
2740 const char *path;
b63a3f55 2741 char *has (const char *, const suffix_info *);
95a8465b 2742 int next ();
b63a3f55 2743 int lnk_match () {return nextstate >= SCAN_EXTRALNK;}
95a8465b
CF
2744};
2745
2746char *
b63a3f55 2747suffix_scan::has (const char *in_path, const suffix_info *in_suffixes)
95a8465b 2748{
b65c6896 2749 nextstate = SCAN_BEG;
b63a3f55
CF
2750 suffixes = suffixes_start = in_suffixes;
2751
2752 char *ext_here = strrchr (in_path, '.');
fc672fb2
CF
2753 path = in_path;
2754 eopath = strchr (path, '\0');
2755
b63a3f55 2756 if (!ext_here)
fc672fb2 2757 goto noext;
b63a3f55
CF
2758
2759 if (suffixes)
95a8465b 2760 {
b63a3f55
CF
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;
95a8465b
CF
2776 }
2777
fc672fb2
CF
2778 noext:
2779 ext_here = eopath;
2780
b63a3f55 2781 done:
fc672fb2 2782 return ext_here;
95a8465b
CF
2783}
2784
2785int
2786suffix_scan::next ()
2787{
2788 if (suffixes)
2789 {
2790 while (suffixes && suffixes->name)
2791 if (!suffixes->addon)
2792 suffixes++;
2793 else
2794 {
b63a3f55
CF
2795 strcpy (eopath, suffixes->name);
2796 if (nextstate == SCAN_EXTRALNK)
2797 strcat (eopath, ".lnk");
95a8465b
CF
2798 suffixes++;
2799 return 1;
2800 }
2801 suffixes = NULL;
95a8465b
CF
2802 }
2803
b65c6896 2804 switch (nextstate)
95a8465b 2805 {
b65c6896 2806 case SCAN_BEG:
b63a3f55 2807 suffixes = suffixes_start;
57499703 2808 if (!suffixes)
b63a3f55 2809 nextstate = SCAN_LNK;
57499703
CF
2810 else
2811 {
2812 if (!*suffixes->name)
2813 suffixes++;
2814 nextstate = SCAN_EXTRALNK;
2815 }
b65c6896
CF
2816 return 1;
2817 case SCAN_HASLNK:
b63a3f55 2818 nextstate = SCAN_EXTRALNK; /* Skip SCAN_BEG */
b65c6896 2819 return 1;
95a8465b 2820 case SCAN_LNK:
b63a3f55
CF
2821 case SCAN_EXTRALNK:
2822 strcpy (eopath, ".lnk");
2823 nextstate = SCAN_DONE;
b65c6896 2824 return 1;
95a8465b 2825 case SCAN_JUSTCHECK:
b63a3f55
CF
2826 nextstate = SCAN_APPENDLNK;
2827 return 1;
2828 case SCAN_APPENDLNK:
2829 strcat (eopath, ".lnk");
b65c6896 2830 nextstate = SCAN_DONE;
95a8465b
CF
2831 return 1;
2832 default:
b63a3f55 2833 *eopath = '\0';
95a8465b
CF
2834 return 0;
2835 }
2836}
2837
1fd5e000
CF
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
2cf9359a 2855int
2b5803d4 2856symlink_info::check (char *path, const suffix_info *suffixes, unsigned opt)
1fd5e000
CF
2857{
2858 HANDLE h;
2859 int res = 0;
95a8465b 2860 suffix_scan suffix;
b98ebf54 2861 contents[0] = '\0';
1fd5e000 2862
2cf9359a 2863 is_symlink = TRUE;
2b5803d4
CF
2864 ext_here = suffix.has (path, suffixes);
2865 extn = ext_here - path;
2866
2867 pflags &= ~PATH_SYMLINK;
fc672fb2 2868
70c370d6
CV
2869 case_clash = FALSE;
2870
95a8465b 2871 while (suffix.next ())
1fd5e000 2872 {
e136f5c0 2873 error = 0;
95a8465b 2874 fileattr = GetFileAttributesA (suffix.path);
1fd5e000
CF
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. */
95a8465b 2880 debug_printf ("GetFileAttributesA (%s) failed", suffix.path);
9e2baf8d 2881 error = geterrno_from_win_error (GetLastError (), EACCES);
1fd5e000
CF
2882 continue;
2883 }
2884
b9ce8140
CF
2885
2886 ext_tacked_on = !!*ext_here;
2887
2b5803d4 2888 if (pcheck_case != PCHECK_RELAXED && !case_check (path)
ac5561f2
CF
2889 || (opt & PC_SYM_IGNORE))
2890 goto file_not_symlink;
70c370d6 2891
b9ce8140
CF
2892 int sym_check;
2893
2894 sym_check = 0;
10b06c5e
CV
2895
2896 if (fileattr & FILE_ATTRIBUTE_DIRECTORY)
ac5561f2 2897 goto file_not_symlink;
10b06c5e
CV
2898
2899 /* Windows shortcuts are treated as symlinks. */
95a8465b 2900 if (suffix.lnk_match ())
10b06c5e
CV
2901 sym_check = 1;
2902
b98ebf54 2903 /* This is the old Cygwin method creating symlinks: */
1fd5e000
CF
2904 /* A symlink will have the `system' file attribute. */
2905 /* Only files can be symlinks (which can be symlinks to directories). */
10b06c5e
CV
2906 if (fileattr & FILE_ATTRIBUTE_SYSTEM)
2907 sym_check = 2;
2908
b98ebf54 2909 if (!sym_check)
1fd5e000
CF
2910 goto file_not_symlink;
2911
149da470
ED
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
1fd5e000
CF
2920 /* Open the file. */
2921
95a8465b 2922 h = CreateFileA (suffix.path, GENERIC_READ, FILE_SHARE_READ, &sec_none_nih, OPEN_EXISTING,
1fd5e000 2923 FILE_ATTRIBUTE_NORMAL, 0);
1fd5e000
CF
2924 res = -1;
2925 if (h == INVALID_HANDLE_VALUE)
a731e4e7 2926 goto file_not_symlink;
96dc5dd7 2927
fc633b63 2928 /* FIXME: if symlink isn't present in EA, but EAs are supported,
149da470
ED
2929 * should we write it there?
2930 */
96dc5dd7 2931 switch (sym_check)
1fd5e000 2932 {
96dc5dd7
CF
2933 case 1:
2934 res = check_shortcut (suffix.path, fileattr, h, contents, &error, &pflags);
2935 if (res)
b9ce8140 2936 break;
96dc5dd7
CF
2937 /* If searching for `foo' and then finding a `foo.lnk' which is
2938 no shortcut, return the same as if file not found. */
b9ce8140 2939 if (!suffix.lnk_match () || !ext_tacked_on)
96dc5dd7
CF
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;
1fd5e000 2949 }
95a8465b 2950 break;
1fd5e000 2951
b9ce8140
CF
2952 file_not_symlink:
2953 is_symlink = FALSE;
2954 syscall_printf ("not a symlink");
2955 res = 0;
2956 break;
2957 }
1fd5e000 2958
2cf9359a 2959 syscall_printf ("%d = symlink.check (%s, %p) (%p)",
95a8465b 2960 res, suffix.path, contents, pflags);
1fd5e000
CF
2961 return res;
2962}
2963
70c370d6
CV
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
2970BOOL
2b5803d4 2971symlink_info::case_check (char *path)
70c370d6
CV
2972{
2973 WIN32_FIND_DATA data;
2974 HANDLE h;
2b5803d4 2975 char *c;
70c370d6
CV
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 {
0f565126
CV
2991 case_clash = TRUE;
2992
70c370d6
CV
2993 /* If check is set to STRICT, a wrong case results
2994 in returning a ENOENT. */
2995 if (pcheck_case == PCHECK_STRICT)
0f565126 2996 return FALSE;
70c370d6
CV
2997
2998 /* PCHECK_ADJUST adjusts the case in the incoming
2999 path which points to the path in *this. */
2b5803d4 3000 strcpy (c, data.cFileName);
70c370d6
CV
3001 }
3002 }
3003 return TRUE;
3004}
3005
1fd5e000
CF
3006/* readlink system call */
3007
f636c081 3008extern "C" int
1fd5e000
CF
3009readlink (const char *path, char *buf, int buflen)
3010{
2cf9359a 3011 extern suffix_info stat_suffixes[];
f7632549
CF
3012
3013 if (buflen < 0)
3014 {
3015 set_errno (ENAMETOOLONG);
3016 return -1;
3017 }
3018
5bc584ba 3019 path_conv pathbuf (path, PC_SYM_CONTENTS, stat_suffixes);
2cf9359a 3020
1fd5e000
CF
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
47063f00 3028 if (!pathbuf.exists ())
772e2322
CF
3029 {
3030 set_errno (ENOENT);
3031 return -1;
3032 }
3033
1fd5e000
CF
3034 if (!pathbuf.issymlink ())
3035 {
3036 if (pathbuf.fileattr != (DWORD) -1)
3037 set_errno (EINVAL);
3038 return -1;
3039 }
3040
e321565b 3041 int len = min (buflen, (int) strlen (pathbuf.get_win32 ()));
1fd5e000 3042 memcpy (buf, pathbuf.get_win32 (), len);
1fd5e000 3043
2cf9359a 3044 /* errno set by symlink.check if error */
1fd5e000
CF
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
3056unsigned long __stdcall
3057hash_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);
17743fbc
CF
3075 nn = newname;
3076 *nn = isupper (*name) ? cyg_tolower (*name) : *name;
3077 *++nn = ':';
1fd5e000
CF
3078 name += 2;
3079 if (*name != '\\')
17743fbc
CF
3080 *++nn = '\\';
3081 strcpy (++nn, name);
1fd5e000
CF
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
1dc16fc7 3091 if (!hash && !isabspath (name))
1fd5e000 3092 {
431ba7dd 3093 hash = cygheap->cwd.get_hash ();
1fd5e000
CF
3094 if (name[0] == '.' && name[1] == '\0')
3095 return hash;
1dc16fc7 3096 hash += hash_path_name (hash, "\\");
1fd5e000
CF
3097 }
3098 }
3099
3100hashit:
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 {
2556e737 3105 int ch = cyg_tolower(*name);
1dc16fc7 3106 hash += ch + (ch << 17);
1fd5e000
CF
3107 hash ^= hash >> 2;
3108 }
3109 while (*++name != '\0' &&
3110 !(*name == '\\' && (!name[1] || (name[1] == '.' && !name[2]))));
3111 return hash;
3112}
3113
5d4af61e 3114char *
7e24f1bf 3115getcwd (char *buf, size_t ulen)
1fd5e000 3116{
0aca521a 3117 char* res = NULL;
5318c498 3118 if (ulen == 0 && buf)
0aca521a 3119 set_errno (EINVAL);
19639f41 3120 else if (buf == NULL || !__check_null_invalid_struct_errno (buf, ulen))
0aca521a
ED
3121 res = cygheap->cwd.get (buf, 1, 1, ulen);
3122 return res;
1fd5e000
CF
3123}
3124
3125/* getwd: standards? */
f636c081 3126extern "C" char *
1fd5e000
CF
3127getwd (char *buf)
3128{
3129 return getcwd (buf, MAX_PATH);
3130}
3131
3132/* chdir: POSIX 5.2.1.1 */
99a5bd2f 3133extern "C" int
02782489 3134chdir (const char *in_dir)
1fd5e000 3135{
7a4078ee
CF
3136 if (check_null_empty_str_errno (in_dir))
3137 return -1;
02782489
CF
3138
3139 syscall_printf ("dir '%s'", in_dir);
1fd5e000 3140
b5eb3d0f 3141 char *s;
02782489
CF
3142 char dir[strlen (in_dir) + 1];
3143 strcpy (dir, in_dir);
b5eb3d0f
CF
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. */
bb825147 3148 for (s = strchr (dir, '\0'); --s >= dir && isspace ((unsigned int) (*s & 0xff)); )
b5eb3d0f
CF
3149 *s = '\0';
3150
02782489
CF
3151 if (!*s)
3152 {
3153 set_errno (ENOENT);
3154 return -1;
3155 }
3156
f375b8d9 3157 /* Convert path. First argument ensures that we don't check for NULL/empty/invalid
02782489 3158 again. */
f375b8d9 3159 path_conv path (PC_NONULLEMPTY, dir, PC_FULL | PC_SYM_FOLLOW);
02782489
CF
3160 if (path.error)
3161 {
3162 set_errno (path.error);
3163 syscall_printf ("-1 = chdir (%s)", dir);
3164 return -1;
3165 }
3166
3167
4497c0df
CF
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
4f7ac76a 3178 size_t len = strlen (p);
4497c0df
CF
3179 if (len > 2 && strspn (p, ".") == len)
3180 {
3181 set_errno (ENOENT);
3182 return -1;
3183 }
3184
1fd5e000
CF
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. */
75858e8a 3191 if (isdrive (native_dir) && !native_dir[2])
1fd5e000
CF
3192 {
3193 native_dir[2] = '\\';
3194 native_dir[3] = '\0';
3195 }
75858e8a 3196 int res = SetCurrentDirectoryA (native_dir) ? 0 : -1;
bdfeca60
CF
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. */
75858e8a 3208 if (res == -1)
1fd5e000 3209 __seterrno ();
70c370d6 3210 else if (!path.has_symlinks () && strpbrk (dir, ":\\") == NULL
ac5561f2 3211 && pcheck_case == PCHECK_RELAXED)
431ba7dd 3212 cygheap->cwd.set (path, dir);
3875d9e6 3213 else
431ba7dd 3214 cygheap->cwd.set (path, NULL);
7e24f1bf
CF
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. */
431ba7dd
CF
3218 syscall_printf ("%d = chdir() cygheap->cwd.posix '%s' native '%s'", res,
3219 cygheap->cwd.posix, native_dir);
9fc09d00 3220 MALLOC_CHECK;
75858e8a 3221 return res;
1fd5e000
CF
3222}
3223
f636c081 3224extern "C" int
463513f0
CV
3225fchdir (int fd)
3226{
df63bd49 3227 int res;
463513f0
CV
3228 sigframe thisframe (mainthread);
3229
df63bd49
CF
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;
463513f0
CV
3238}
3239
1fd5e000
CF
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
f636c081 3245extern "C" int
1fd5e000
CF
3246cygwin_conv_to_win32_path (const char *path, char *win32_path)
3247{
5bc584ba 3248 path_conv p (path, PC_SYM_FOLLOW);
1fd5e000
CF
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
f636c081 3259extern "C" int
1fd5e000
CF
3260cygwin_conv_to_full_win32_path (const char *path, char *win32_path)
3261{
5bc584ba 3262 path_conv p (path, PC_SYM_FOLLOW | PC_FULL);
1fd5e000
CF
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
f636c081 3275extern "C" int
1fd5e000
CF
3276cygwin_conv_to_posix_path (const char *path, char *posix_path)
3277{
7a4078ee 3278 if (check_null_empty_str_errno (path))
1fd5e000 3279 return -1;
2a6fc028 3280 mount_table->conv_to_posix_path (path, posix_path, 1);
1fd5e000
CF
3281 return 0;
3282}
3283
f636c081 3284extern "C" int
1fd5e000
CF
3285cygwin_conv_to_full_posix_path (const char *path, char *posix_path)
3286{
7a4078ee 3287 if (check_null_empty_str_errno (path))
1fd5e000 3288 return -1;
2a6fc028 3289 mount_table->conv_to_posix_path (path, posix_path, 0);
1fd5e000
CF
3290 return 0;
3291}
3292
3293/* The realpath function is supported on some UNIX systems. */
3294
f636c081 3295extern "C" char *
1fd5e000
CF
3296realpath (const char *path, char *resolved)
3297{
3298 int err;
3299
5bc584ba 3300 path_conv real_path (path, PC_SYM_FOLLOW | PC_FULL);
1fd5e000
CF
3301
3302 if (real_path.error)
3303 err = real_path.error;
3304 else
3305 {
2a6fc028 3306 err = mount_table->conv_to_posix_path (real_path.get_win32 (), resolved, 0);
1fd5e000
CF
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
3322DOCTOOL-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>
3332DOCTOOL-END
3333 */
3334
f636c081 3335extern "C" int
1fd5e000
CF
3336cygwin_posix_path_list_p (const char *path)
3337{
95a8465b 3338 int posix_p = !(strchr (path, ';') || isdrive (path));
1fd5e000
CF
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
3347static int
3348conv_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 */
2a6fc028 3362 for (max_mount_path_len = 7, i = 0; i < mount_table->nmounts; ++i)
1fd5e000
CF
3363 {
3364 int mount_len = (to_posix_p
2a6fc028
CF
3365 ? mount_table->mount[i].posix_pathlen
3366 : mount_table->mount[i].native_pathlen);
1fd5e000
CF
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
f636c081 3376extern "C" int
1fd5e000
CF
3377cygwin_win32_to_posix_path_list_buf_size (const char *path_list)
3378{
3379 return conv_path_list_buf_size (path_list, 1);
3380}
3381
f636c081 3382extern "C" int
1fd5e000
CF
3383cygwin_posix_to_win32_path_list_buf_size (const char *path_list)
3384{
3385 return conv_path_list_buf_size (path_list, 0);
3386}
3387
f636c081 3388extern "C" int
1fd5e000
CF
3389cygwin_win32_to_posix_path_list (const char *win32, char *posix)
3390{
3391 conv_path_list (win32, posix, 1);
3392 return 0;
3393}
3394
f636c081 3395extern "C" int
1fd5e000
CF
3396cygwin_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
f636c081 3421extern "C" void
1fd5e000
CF
3422cygwin_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. */
75858e8a 3428 if (isdrive (path))
1fd5e000
CF
3429 {
3430 *dir++ = *path++;
3431 *dir++ = *path++;
3432 *dir++ = '/';
95a8465b 3433 if (!*path)
1fd5e000
CF
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
2556e737
DD
3483/*****************************************************************************/
3484
7e24f1bf
CF
3485/* Return the hash value for the current win32 value.
3486 This is used when constructing inodes. */
3487DWORD
3488cwdstuff::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. */
3498void
3499cwdstuff::init ()
3500{
3501 lock = new_muto (FALSE, "cwd");
3502}
3503
7e24f1bf
CF
3504/* Get initial cwd. Should only be called once in a
3505 process tree. */
3506bool
3507cwdstuff::get_initial ()
3508{
166b2571
CF
3509 lock->acquire ();
3510
b8a0fafe
CF
3511 if (win32)
3512 return 1;
7e24f1bf
CF
3513
3514 int i;
b8a0fafe 3515 DWORD len, dlen;
7e24f1bf
CF
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");
166b2571 3528 lock->release ();
7e24f1bf
CF
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. */
3538void
4497c0df 3539cwdstuff::set (const char *win32_cwd, const char *posix_cwd)
7e24f1bf 3540{
4497c0df
CF
3541 char pathbuf[MAX_PATH];
3542
7e24f1bf
CF
3543 if (win32_cwd)
3544 {
3545 lock->acquire ();
3546 win32 = (char *) crealloc (win32, strlen (win32_cwd) + 1);
3547 strcpy (win32, win32_cwd);
3548 }
3549
4497c0df 3550 if (!posix_cwd)
2a6fc028 3551 mount_table->conv_to_posix_path (win32, pathbuf, 0);
4497c0df
CF
3552 else
3553 (void) normalize_posix_path (posix_cwd, pathbuf);
7e24f1bf 3554
4497c0df
CF
3555 posix = (char *) crealloc (posix, strlen (pathbuf) + 1);
3556 strcpy (posix, pathbuf);
7e24f1bf 3557
4497c0df 3558 hash = hash_path_name (0, win32);
7e24f1bf
CF
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. */
3567char *
3568cwdstuff::get (char *buf, int need_posix, int with_chroot, unsigned ulen)
3569{
9fc09d00 3570 MALLOC_CHECK;
e62ae311 3571
e2fa5023
CF
3572 if (ulen)
3573 /* nothing */;
3574 else if (buf == NULL)
3575 ulen = (unsigned) -1;
3576 else
e62ae311
CF
3577 {
3578 set_errno (EINVAL);
3579 goto out;
3580 }
3581
7e24f1bf
CF
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
7ceb1cac 3589 tocopy = posix;
7e24f1bf 3590
7ceb1cac 3591 debug_printf("posix %s", posix);
7e24f1bf 3592 if (strlen (tocopy) >= ulen)
3e057695
CF
3593 {
3594 set_errno (ERANGE);
3595 buf = NULL;
3596 }
7e24f1bf
CF
3597 else
3598 {
e62ae311 3599 if (!buf)
9fc09d00 3600 buf = (char *) malloc (strlen (tocopy) + 1);
7e24f1bf
CF
3601 strcpy (buf, tocopy);
3602 if (!buf[0]) /* Should only happen when chroot */
3603 strcpy (buf, "/");
3604 }
3605
3606 lock->release ();
e62ae311
CF
3607
3608out:
3609 syscall_printf ("(%s) = cwdstuff::get (%p, %d, %d, %d), errno %d",
3610 buf, buf, ulen, need_posix, with_chroot, errno);
9fc09d00 3611 MALLOC_CHECK;
7e24f1bf
CF
3612 return buf;
3613}
This page took 0.535687 seconds and 5 git commands to generate.