3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
9 /* The purpose of this file is to hide all the details about accessing
10 Cygwin's mount table, shortcuts, etc. If the format or location of
11 the mount table, or the shortcut format changes, this is the file to
12 change to match it. */
15 #define scat(a,b) str(a##b)
23 #include <cygwin/version.h>
24 #include <cygwin/bits.h>
25 #include <sys/mount.h>
26 #define _NOMNTENT_MACROS
29 #include <sys/cygwin.h>
33 /* Used when treating / and \ as equivalent. */
37 ((__c) == '/' || (__c) == '\\'); \
41 static const GUID GUID_shortcut
=
42 {0x00021401L
, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46}};
45 WSH_FLAG_IDLIST
= 0x01, /* Contains an ITEMIDLIST. */
46 WSH_FLAG_FILE
= 0x02, /* Contains a file locator element. */
47 WSH_FLAG_DESC
= 0x04, /* Contains a description. */
48 WSH_FLAG_RELPATH
= 0x08, /* Contains a relative path. */
49 WSH_FLAG_WD
= 0x10, /* Contains a working dir. */
50 WSH_FLAG_CMDLINE
= 0x20, /* Contains command line args. */
51 WSH_FLAG_ICON
= 0x40 /* Contains a custom icon. */
54 struct win_shortcut_hdr
56 DWORD size
; /* Header size in bytes. Must contain 0x4c. */
57 GUID magic
; /* GUID of shortcut files. */
58 DWORD flags
; /* Content flags. See above. */
60 /* The next fields from attr to icon_no are always set to 0 in Cygwin
61 and U/Win shortcuts. */
62 DWORD attr
; /* Target file attributes. */
63 FILETIME ctime
; /* These filetime items are never touched by the */
64 FILETIME mtime
; /* system, apparently. Values don't matter. */
66 DWORD filesize
; /* Target filesize. */
67 DWORD icon_no
; /* Icon number. */
69 DWORD run
; /* Values defined in winuser.h. Use SW_NORMAL. */
70 DWORD hotkey
; /* Hotkey value. Set to 0. */
71 DWORD dummy
[2]; /* Future extension probably. Always 0. */
75 cmp_shortcut_header (win_shortcut_hdr
*file_header
)
77 /* A Cygwin or U/Win shortcut only contains a description and a relpath.
78 Cygwin shortcuts also might contain an ITEMIDLIST. The run type is
79 always set to SW_NORMAL. */
80 return file_header
->size
== sizeof (win_shortcut_hdr
)
81 && !memcmp (&file_header
->magic
, &GUID_shortcut
, sizeof GUID_shortcut
)
82 && (file_header
->flags
& ~WSH_FLAG_IDLIST
)
83 == (WSH_FLAG_DESC
| WSH_FLAG_RELPATH
)
84 && file_header
->run
== SW_NORMAL
;
88 get_word (HANDLE fh
, int offset
)
93 SetLastError(NO_ERROR
);
94 if (SetFilePointer (fh
, offset
, 0, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
95 && GetLastError () != NO_ERROR
)
98 if (!ReadFile (fh
, &rv
, 2, (DWORD
*) &r
, 0))
105 * Check the value of GetLastError() to find out whether there was an error.
108 get_dword (HANDLE fh
, int offset
)
113 SetLastError(NO_ERROR
);
114 if (SetFilePointer (fh
, offset
, 0, FILE_BEGIN
) == INVALID_SET_FILE_POINTER
115 && GetLastError () != NO_ERROR
)
118 if (!ReadFile (fh
, &rv
, 4, (DWORD
*) &r
, 0))
124 #define EXE_MAGIC ((int)*(unsigned short *)"MZ")
125 #define SHORTCUT_MAGIC ((int)*(unsigned short *)"L\0")
126 #define SYMLINK_COOKIE "!<symlink>"
127 #define SYMLINK_MAGIC ((int)*(unsigned short *)SYMLINK_COOKIE)
132 int magic
= get_word (fh
, 0x0);
133 return magic
== EXE_MAGIC
;
137 is_symlink (HANDLE fh
)
140 int magic
= get_word (fh
, 0x0);
141 if (magic
!= SHORTCUT_MAGIC
&& magic
!= SYMLINK_MAGIC
)
144 BY_HANDLE_FILE_INFORMATION local
;
145 if (!GetFileInformationByHandle (fh
, &local
))
147 if (magic
== SHORTCUT_MAGIC
)
150 if (!local
.dwFileAttributes
& FILE_ATTRIBUTE_READONLY
)
151 goto out
; /* Not a Cygwin symlink. */
152 if ((size
= GetFileSize (fh
, NULL
)) > 8192)
153 goto out
; /* Not a Cygwin symlink. */
155 SetFilePointer (fh
, 0, 0, FILE_BEGIN
);
156 if (!ReadFile (fh
, buf
, size
, &got
, 0))
158 if (got
!= size
|| !cmp_shortcut_header ((win_shortcut_hdr
*) buf
))
159 goto out
; /* Not a Cygwin symlink. */
160 /* TODO: check for invalid path contents
161 (see symlink_info::check() in ../cygwin/path.cc) */
163 else /* magic == SYMLINK_MAGIC */
165 if (!(local
.dwFileAttributes
& FILE_ATTRIBUTE_SYSTEM
))
166 goto out
; /* Not a Cygwin symlink. */
167 char buf
[sizeof (SYMLINK_COOKIE
) - 1];
168 SetFilePointer (fh
, 0, 0, FILE_BEGIN
);
169 if (!ReadFile (fh
, buf
, sizeof (buf
), &got
, 0))
171 if (got
!= sizeof (buf
) ||
172 memcmp (buf
, SYMLINK_COOKIE
, sizeof (buf
)) != 0)
173 goto out
; /* Not a Cygwin symlink. */
177 SetFilePointer (fh
, 0, 0, FILE_BEGIN
);
181 /* Assumes is_symlink(fh) is true */
183 readlink (HANDLE fh
, char *path
, size_t maxlen
)
188 win_shortcut_hdr
*file_header
;
189 BY_HANDLE_FILE_INFORMATION fi
;
191 if (!GetFileInformationByHandle (fh
, &fi
)
192 || fi
.nFileSizeHigh
!= 0
193 || fi
.nFileSizeLow
> 4 * 65536)
196 buf
= (char *) alloca (fi
.nFileSizeLow
+ 1);
197 file_header
= (win_shortcut_hdr
*) buf
;
199 if (!ReadFile (fh
, buf
, fi
.nFileSizeLow
, &rv
, NULL
)
200 || rv
!= fi
.nFileSizeLow
)
203 if (fi
.nFileSizeLow
> sizeof (file_header
)
204 && cmp_shortcut_header (file_header
))
206 cp
= buf
+ sizeof (win_shortcut_hdr
);
207 if (file_header
->flags
& WSH_FLAG_IDLIST
) /* Skip ITEMIDLIST */
208 cp
+= *(unsigned short *) cp
+ 2;
209 if (!(len
= *(unsigned short *) cp
))
212 /* Has appended full path? If so, use it instead of description. */
213 unsigned short relpath_len
= *(unsigned short *) (cp
+ len
);
214 if (cp
+ len
+ 2 + relpath_len
< buf
+ fi
.nFileSizeLow
)
216 cp
+= len
+ 2 + relpath_len
;
217 len
= *(unsigned short *) cp
;
220 if (*(PWCHAR
) cp
== 0xfeff) /* BOM */
222 size_t wlen
= wcstombs (NULL
, (wchar_t *) (cp
+ 2), 0);
223 if (wlen
== (size_t) -1 || wlen
+ 1 > maxlen
)
225 wcstombs (path
, (wchar_t *) (cp
+ 2), wlen
+ 1);
227 else if ((size_t) (len
+ 1) > maxlen
)
230 memcpy (path
, cp
, len
);
234 else if (strncmp (buf
, SYMLINK_COOKIE
, strlen (SYMLINK_COOKIE
)) == 0
235 && buf
[fi
.nFileSizeLow
- 1] == '\0')
237 cp
= buf
+ strlen (SYMLINK_COOKIE
);
238 if (*(PWCHAR
) cp
== 0xfeff) /* BOM */
240 size_t wlen
= wcstombs (NULL
, (wchar_t *) (cp
+ 2), 0);
241 if (wlen
== (size_t) -1 || wlen
+ 1 > maxlen
)
243 wcstombs (path
, (wchar_t *) (cp
+ 2), wlen
+ 1);
245 else if (fi
.nFileSizeLow
- strlen (SYMLINK_COOKIE
) > maxlen
)
254 #endif /* !FSTAB_ONLY */
256 mnt_t mount_table
[255];
260 unconvert_slashes (char* name
)
262 while ((name
= strchr (name
, '/')) != NULL
)
269 while (*in
== ' ' || *in
== '\t')
277 while (*in
&& *in
!= ' ' && *in
!= '\t')
283 conv_fstab_spaces (char *field
)
286 while ((sp
= strstr (sp
, "\\040")) != NULL
)
289 memmove (sp
, sp
+ 3, strlen (sp
+ 3) + 1);
302 {"acl", MOUNT_NOACL
, 1},
304 {"binary", MOUNT_TEXT
, 1},
305 {"cygexec", MOUNT_CYGWIN_EXEC
, 0},
306 {"dos", MOUNT_DOS
, 0},
307 {"exec", MOUNT_EXEC
, 0},
308 {"ihash", MOUNT_IHASH
, 0},
309 {"noacl", MOUNT_NOACL
, 0},
311 {"notexec", MOUNT_NOTEXEC
, 0},
312 {"nouser", MOUNT_SYSTEM
, 0},
313 {"override", MOUNT_OVERRIDE
, 0},
314 {"posix=0", MOUNT_NOPOSIX
, 0},
315 {"posix=1", MOUNT_NOPOSIX
, 1},
316 {"text", MOUNT_TEXT
, 0},
317 {"user", MOUNT_SYSTEM
, 1}
321 read_flags (char *options
, unsigned &flags
)
325 char *p
= strchr (options
, ',');
329 p
= strchr (options
, '\0');
332 o
< (oopts
+ (sizeof (oopts
) / sizeof (oopts
[0])));
334 if (strcmp (options
, o
->name
) == 0)
352 from_fstab_line (mnt_t
*m
, char *line
, bool user
)
354 char *native_path
, *posix_path
, *fs_type
;
356 /* First field: Native path. */
357 char *c
= skip_ws (line
);
358 if (!*c
|| *c
== '#')
360 char *cend
= find_ws (c
);
362 native_path
= conv_fstab_spaces (c
);
363 /* Second field: POSIX path. */
364 c
= skip_ws (cend
+ 1);
369 posix_path
= conv_fstab_spaces (c
);
370 /* Third field: FS type. */
371 c
= skip_ws (cend
+ 1);
377 /* Forth field: Flags. */
378 c
= skip_ws (cend
+ 1);
383 unsigned mount_flags
= MOUNT_SYSTEM
;
385 if (!read_flags (c
, mount_flags
))
387 if (cygwin_internal (CW_CVT_MNT_OPTS
, &c
, &mount_flags
))
391 mount_flags
&= ~MOUNT_SYSTEM
;
392 if (!strcmp (fs_type
, "cygdrive"))
394 for (mnt_t
*sm
= mount_table
; sm
< m
; ++sm
)
395 if (sm
->flags
& MOUNT_CYGDRIVE
)
397 if ((mount_flags
& MOUNT_SYSTEM
) || !(sm
->flags
& MOUNT_SYSTEM
))
401 sm
->posix
= strdup (posix_path
);
402 sm
->flags
= mount_flags
| MOUNT_CYGDRIVE
;
406 m
->posix
= strdup (posix_path
);
407 m
->native
= strdup ("cygdrive prefix");
408 m
->flags
= mount_flags
| MOUNT_CYGDRIVE
;
412 for (mnt_t
*sm
= mount_table
; sm
< m
; ++sm
)
413 if (!strcmp (sm
->posix
, posix_path
))
415 /* Don't allow overriding of a system mount with a user mount. */
416 if ((sm
->flags
& MOUNT_SYSTEM
) && !(mount_flags
& MOUNT_SYSTEM
))
418 if ((sm
->flags
& MOUNT_SYSTEM
) != (mount_flags
& MOUNT_SYSTEM
))
420 /* Changing immutable mount points require the override flag. */
421 if ((sm
->flags
& MOUNT_IMMUTABLE
)
422 && !(mount_flags
& MOUNT_OVERRIDE
))
424 if (mount_flags
& MOUNT_OVERRIDE
)
425 mount_flags
|= MOUNT_IMMUTABLE
;
428 sm
->native
= strdup (native_path
);
429 sm
->flags
= mount_flags
;
432 m
->posix
= strdup (posix_path
);
433 /* Bind mounts require POSIX paths, otherwise the path is wrongly
434 prefixed with the Cygwin root dir when trying to convert it to
435 a Win32 path in mount(2). So don't convert slashes to backslashes
437 if (!(mount_flags
& MOUNT_BIND
))
438 unconvert_slashes (native_path
);
439 m
->native
= strdup (native_path
);
440 m
->flags
= mount_flags
;
447 #define BUFSIZE 65536
452 static char user
[UNLEN
+ 1];
456 if ((userenv
= getenv ("USER")) || (userenv
= getenv ("USERNAME")))
457 strncat (user
, userenv
, UNLEN
);
462 from_fstab (bool user
, PWCHAR path
, PWCHAR path_end
)
464 mnt_t
*m
= mount_table
+ max_mount_entry
;
469 /* Create a default root dir from path. */
470 wcstombs (buf
, path
, BUFSIZE
);
471 unconvert_slashes (buf
);
472 char *native_path
= buf
;
473 if (!strncmp (native_path
, "\\\\?\\", 4))
475 if (!strncmp (native_path
, "UNC\\", 4))
476 *(native_path
+= 2) = '\\';
477 m
->posix
= strdup ("/");
478 m
->native
= strdup (native_path
);
479 m
->flags
= MOUNT_SYSTEM
| MOUNT_IMMUTABLE
| MOUNT_AUTOMATIC
;
481 /* Create default /usr/bin and /usr/lib entries. */
482 char *trail
= strchr (native_path
, '\0');
483 strcpy (trail
, "\\bin");
484 m
->posix
= strdup ("/usr/bin");
485 m
->native
= strdup (native_path
);
486 m
->flags
= MOUNT_SYSTEM
| MOUNT_AUTOMATIC
;
488 strcpy (trail
, "\\lib");
489 m
->posix
= strdup ("/usr/lib");
490 m
->native
= strdup (native_path
);
491 m
->flags
= MOUNT_SYSTEM
| MOUNT_AUTOMATIC
;
493 /* Create a default cygdrive entry. Note that this is a user entry.
494 This allows to override it with mount, unless the sysadmin created
495 a cygdrive entry in /etc/fstab. */
496 m
->posix
= strdup (CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX
);
497 m
->native
= strdup ("cygdrive prefix");
498 m
->flags
= MOUNT_CYGDRIVE
;
500 max_mount_entry
= m
- mount_table
;
503 PWCHAR u
= wcscpy (path_end
, L
"\\etc\\fstab") + 10;
505 mbstowcs (wcscpy (u
, L
".d\\") + 3, get_user (), BUFSIZE
- (u
- path
));
506 HANDLE h
= CreateFileW (path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
507 OPEN_EXISTING
, FILE_ATTRIBUTE_NORMAL
, NULL
);
508 if (h
== INVALID_HANDLE_VALUE
)
512 /* Using BUFSIZE-1 leaves space to append two \0. */
513 while (ReadFile (h
, got
, BUFSIZE
- 1 - (got
- buf
),
518 /* Set end marker. */
519 got
[len
] = got
[len
+ 1] = '\0';
520 /* Set len to the absolute len of bytes in buf. */
522 /* Reset got to start reading at the start of the buffer again. */
524 while (got
< buf
+ len
&& (end
= strchr (got
, '\n')))
526 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
527 if (from_fstab_line (m
, got
, user
))
531 if (len
< BUFSIZE
- 1)
533 /* We have to read once more. Move remaining bytes to the start of
534 the buffer and reposition got so that it points to the end of
535 the remaining bytes. */
536 len
= buf
+ len
- got
;
537 memmove (buf
, got
, len
);
539 buf
[len
] = buf
[len
+ 1] = '\0';
541 if (got
> buf
&& from_fstab_line (m
, got
, user
))
543 max_mount_entry
= m
- mount_table
;
546 #endif /* !FSTAB_ONLY */
550 #define read_mounts testsuite_read_mounts
553 mnt_sort (const void *a
, const void *b
)
555 const mnt_t
*ma
= (const mnt_t
*) a
;
556 const mnt_t
*mb
= (const mnt_t
*) b
;
559 ret
= (ma
->flags
& MOUNT_CYGDRIVE
) - (mb
->flags
& MOUNT_CYGDRIVE
);
562 ret
= (ma
->flags
& MOUNT_SYSTEM
) - (mb
->flags
& MOUNT_SYSTEM
);
565 return strcmp (ma
->posix
, mb
->posix
);
568 extern "C" WCHAR cygwin_dll_path
[];
579 for (mnt_t
*m1
= mount_table
; m1
->posix
; m1
++)
583 free ((char *) m1
->native
);
588 /* First fetch the cygwin1.dll path from the LoadLibrary call in load_cygwin.
589 This utilizes the DLL search order to find a matching cygwin1.dll and to
590 compute the installation path from that DLL's path. */
591 if (cygwin_dll_path
[0])
592 wcscpy (path
, cygwin_dll_path
);
593 /* If we can't load cygwin1.dll, check where cygcheck is living itself and
594 try to fetch installation path from here. Does cygwin1.dll exist in the
595 same path? This should only kick in if the cygwin1.dll in the same path
596 has been made non-executable for the current user accidentally. */
597 else if (!GetModuleFileNameW (NULL
, path
, 32768))
599 path_end
= wcsrchr (path
, L
'\\');
602 if (!cygwin_dll_path
[0])
604 wcscpy (path_end
, L
"\\cygwin1.dll");
605 DWORD attr
= GetFileAttributesW (path
);
606 if (attr
== (DWORD
) -1
607 || (attr
& (FILE_ATTRIBUTE_DIRECTORY
608 | FILE_ATTRIBUTE_REPARSE_POINT
)))
614 path_end
= wcsrchr (path
, L
'\\');
617 /* If we can't create a valid installation dir from that, try to fetch
618 the installation dir from the setup registry key. */
621 for (int i
= 0; i
< 2; ++i
)
622 if ((ret
= RegOpenKeyExW (i
? HKEY_LOCAL_MACHINE
: HKEY_CURRENT_USER
,
623 L
"Software\\Cygwin\\setup", 0,
624 KEY_READ
, &setup_key
)) == ERROR_SUCCESS
)
626 len
= 32768 * sizeof (WCHAR
);
627 ret
= RegQueryValueExW (setup_key
, L
"rootdir", NULL
, NULL
,
629 RegCloseKey (setup_key
);
630 if (ret
== ERROR_SUCCESS
)
633 if (ret
== ERROR_SUCCESS
)
634 path_end
= wcschr (path
, L
'\0');
636 /* If we can't fetch an installation dir, bail out. */
641 from_fstab (false, path
, path_end
);
642 from_fstab (true, path
, path_end
);
643 qsort (mount_table
, max_mount_entry
, sizeof (mnt_t
), mnt_sort
);
647 /* Return non-zero if PATH1 is a prefix of PATH2.
648 Both are assumed to be of the same path style and / vs \ usage.
650 LEN1 = strlen (PATH1). It's passed because often it's already known.
653 /foo/ is a prefix of /foo <-- may seem odd, but desired
654 /foo is a prefix of /foo/
655 / is a prefix of /foo/bar
656 / is not a prefix of foo/bar
657 foo/ is a prefix foo/bar
658 /foo is not a prefix of /foobar
662 path_prefix_p (const char *path1
, const char *path2
, size_t len1
)
664 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
665 if (len1
> 0 && isslash (path1
[len1
- 1]))
669 return isslash (path2
[0]) && !isslash (path2
[1]);
671 if (strncasecmp (path1
, path2
, len1
) != 0)
674 return isslash (path2
[len1
]) || path2
[len1
] == 0 || path1
[len1
- 1] == ':';
678 vconcat (const char *s
, va_list v
)
690 unc
= isslash (*s
) && isslash (s
[1]);
694 arg
= va_arg (v
, char *);
701 rv
= (char *) malloc (len
+ 1);
706 arg
= va_arg (v
, char *);
715 /* concat is only used for urls and files, so we can safely
716 canonicalize the results */
717 for (p
= d
= rv
; *p
; p
++)
720 /* special case for URLs */
721 if (*p
== ':' && p
[1] == '/' && p
[2] == '/' && p
> rv
+ 1)
726 else if (isslash (*p
))
740 concat (const char *s
, ...)
746 return vconcat (s
, v
);
750 #undef GetCurrentDirectory
751 #define GetCurrentDirectory testsuite_getcwd
754 /* This is a helper function for when vcygpath is passed what appears
755 to be a relative POSIX path. We take a Win32 CWD (either as specified
756 in 'cwd' or as retrieved with GetCurrentDirectory() if 'cwd' is NULL)
757 and find the mount table entry with the longest match. We replace the
758 matching portion with the corresponding POSIX prefix, and to that append
759 's' and anything in 'v'. The returned result is a mostly-POSIX
760 absolute path -- 'mostly' because the portions of CWD that didn't
761 match the mount prefix will still have '\\' separators. */
763 rel_vconcat (const char *cwd
, const char *s
, va_list v
)
765 char pathbuf
[MAX_PATH
];
766 if (!cwd
|| *cwd
== '\0')
768 if (!GetCurrentDirectory (MAX_PATH
, pathbuf
))
774 mnt_t
*m
, *match
= NULL
;
776 for (m
= mount_table
; m
->posix
; m
++)
778 if (m
->flags
& MOUNT_CYGDRIVE
)
781 size_t n
= strlen (m
->native
);
782 if (n
< max_len
|| !path_prefix_p (m
->native
, cwd
, n
))
790 // No prefix matched - best effort to return meaningful value.
791 temppath
= concat (cwd
, "/", s
, NULL
);
792 else if (strcmp (match
->posix
, "/") != 0)
793 // Matched on non-root. Copy matching prefix + remaining 'path'.
794 temppath
= concat (match
->posix
, cwd
+ max_len
, "/", s
, NULL
);
795 else if (cwd
[max_len
] == '\0')
796 // Matched on root and there's no remaining 'path'.
797 temppath
= concat ("/", s
, NULL
);
798 else if (isslash (cwd
[max_len
]))
799 // Matched on root but remaining 'path' starts with a slash anyway.
800 temppath
= concat (cwd
+ max_len
, "/", s
, NULL
);
802 temppath
= concat ("/", cwd
+ max_len
, "/", s
, NULL
);
804 char *res
= vconcat (temppath
, v
);
809 /* Convert a POSIX path in 's' to an absolute Win32 path, and append
810 anything in 'v' to the end, returning the result. If 's' is a
811 relative path then 'cwd' is used as the working directory to make
812 it absolute. Pass NULL in 'cwd' to use GetCurrentDirectory. */
814 vcygpath (const char *cwd
, const char *s
, va_list v
)
817 mnt_t
*m
, *match
= NULL
;
819 if (!max_mount_entry
)
823 if (s
[0] == '.' && isslash (s
[1]))
826 if (s
[0] == '/' || s
[1] == ':') /* FIXME: too crude? */
827 path
= vconcat (s
, v
);
829 path
= rel_vconcat (cwd
, s
, v
);
834 if (strncmp (path
, "/./", 3) == 0)
835 memmove (path
+ 1, path
+ 3, strlen (path
+ 3) + 1);
837 for (m
= mount_table
; m
->posix
; m
++)
839 size_t n
= strlen (m
->posix
);
840 if (n
< max_len
|| !path_prefix_p (m
->posix
, path
, n
))
842 if (m
->flags
& MOUNT_CYGDRIVE
)
844 if (strlen (path
) < n
+ 2)
846 /* If cygdrive path is just '/', fix n for followup evaluation. */
851 if (!isalpha (path
[n
+ 1]))
853 if (path
[n
+ 2] != '/')
862 native
= strdup (path
);
863 else if (max_len
== strlen (path
))
864 native
= strdup (match
->native
);
865 else if (match
->flags
& MOUNT_CYGDRIVE
)
867 char drive
[3] = { path
[max_len
+ 1], ':', '\0' };
868 native
= concat (drive
, path
+ max_len
+ 2, NULL
);
870 else if (isslash (path
[max_len
]))
871 native
= concat (match
->native
, path
+ max_len
, NULL
);
873 native
= concat (match
->native
, "\\", path
+ max_len
, NULL
);
876 unconvert_slashes (native
);
877 for (char *s
= strstr (native
+ 1, "\\.\\"); s
&& *s
; s
= strstr (s
, "\\.\\"))
878 memmove (s
+ 1, s
+ 3, strlen (s
+ 3) + 1);
883 cygpath_rel (const char *cwd
, const char *s
, ...)
889 return vcygpath (cwd
, s
, v
);
893 cygpath (const char *s
, ...)
899 return vcygpath (NULL
, s
, v
);
902 static mnt_t
*m
= NULL
;
905 setmntent (const char *, const char *)
909 if (!max_mount_entry
)
915 extern "C" struct mntent
*
922 mnt
.mnt_fsname
= (char *) m
->native
;
923 mnt
.mnt_dir
= (char *) m
->posix
;
925 mnt
.mnt_type
= (char *) malloc (16);
927 mnt
.mnt_opts
= (char *) malloc (64);
929 strcpy (mnt
.mnt_type
,
930 (char *) ((m
->flags
& MOUNT_SYSTEM
) ? "system" : "user"));
932 if (m
->flags
& MOUNT_TEXT
)
933 strcpy (mnt
.mnt_opts
, (char *) "text");
935 strcpy (mnt
.mnt_opts
, (char *) "binary");
937 if (m
->flags
& MOUNT_CYGWIN_EXEC
)
938 strcat (mnt
.mnt_opts
, (char *) ",cygexec");
939 else if (m
->flags
& MOUNT_EXEC
)
940 strcat (mnt
.mnt_opts
, (char *) ",exec");
941 else if (m
->flags
& MOUNT_NOTEXEC
)
942 strcat (mnt
.mnt_opts
, (char *) ",notexec");
944 if (m
->flags
& MOUNT_NOACL
)
945 strcat (mnt
.mnt_opts
, (char *) ",noacl");
947 if (m
->flags
& MOUNT_NOPOSIX
)
948 strcat (mnt
.mnt_opts
, (char *) ",posix=0");
950 if (m
->flags
& (MOUNT_AUTOMATIC
| MOUNT_CYGDRIVE
))
951 strcat (mnt
.mnt_opts
, (char *) ",auto");
959 #endif /* !FSTAB_ONLY */