2 * Copyright (c) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
3 * 2010, 2013 Red Hat, Inc.
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * A copy of the GNU General Public License can be found at
13 * Written by DJ Delorie <dj@cygnus.com>
17 /* The purpose of this file is to hide all the details about accessing
18 Cygwin's mount table. If the format or location of the mount table
19 changes, this is the file to change to match it. */
22 static const char *cvsid
= "\n%%% $Id$\n";
27 #include "filemanip.h"
28 #include "LogSingleton.h"
34 // These headers aren't available outside the winsup tree
35 // #include "../cygwin/include/cygwin/version.h"
36 // KEEP SYNCHRONISED WITH /src/winsup/cygwin/include/cygwin/version.h
38 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin"
39 #define CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME "setup"
41 // #include "../cygwin/include/sys/mount.h"
43 // KEEP SYNCHRONISED WITH /src/winsup/cygwin/include/sys/mount.h
50 MOUNT_SYMLINK
= 0x001, /* "mount point" is a symlink */
51 MOUNT_BINARY
= 0x002, /* "binary" format read/writes */
52 MOUNT_SYSTEM
= 0x008, /* mount point came from system table */
53 MOUNT_EXEC
= 0x010, /* Any file in the mounted directory gets 'x' bit */
54 MOUNT_AUTO
= 0x020, /* mount point refers to auto device mount */
55 MOUNT_CYGWIN_EXEC
= 0x040, /* file or directory is or contains a cygwin executable */
56 MOUNT_MIXED
= 0x080, /* reads are text, writes are binary */
59 // int mount (const char *, const char *, unsigned __flags);
60 // int umount (const char *);
61 // int cygwin_umount (const char *__path, unsigned __flags);
75 #ifdef MAINTAINER_FEATURES
76 #include "getopt++/GetOption.h"
77 #include "getopt++/StringOption.h"
78 static StringOption
CygwinRegistryNameOption (CYGWIN_INFO_CYGWIN_REGISTRY_NAME
, '#', "override-registry-name", "Override registry name to allow parallel installs for testing purposes", false);
79 #undef CYGWIN_INFO_CYGWIN_REGISTRY_NAME
80 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME (((std::string)CygwinRegistryNameOption).c_str())
83 /* Used when treating / and \ as equivalent. */
87 ((__c) == '/' || (__c) == '\\'); \
98 struct mnt
*root_here
= NULL
;
101 create_install_root ()
108 snprintf (buf
, sizeof(buf
), "Software\\%s\\%s",
109 CYGWIN_INFO_CYGWIN_REGISTRY_NAME
,
110 CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME
);
111 HKEY kr
= (root_scope
== IDC_ROOT_USER
) ? HKEY_CURRENT_USER
112 : HKEY_LOCAL_MACHINE
;
115 rv
= RegCreateKeyEx (kr
, buf
, 0, (char *)"Cygwin", 0,
116 KEY_ALL_ACCESS
| SETUP_KEY_WOW64
,
117 0, &key
, &disposition
);
118 if (rv
!= ERROR_ACCESS_DENIED
|| kr
!= HKEY_LOCAL_MACHINE
)
120 Log (LOG_PLAIN
) << "Access denied trying to create rootdir registry key"
122 kr
= HKEY_CURRENT_USER
;
124 while (rv
== ERROR_ACCESS_DENIED
);
125 if (rv
== ERROR_SUCCESS
)
128 rv
= RegSetValueEx (key
, "rootdir", 0, REG_SZ
,
129 (BYTE
*) get_root_dir ().c_str (),
130 get_root_dir ().size () + 1);
131 if (rv
!= ERROR_ACCESS_DENIED
|| kr
!= HKEY_LOCAL_MACHINE
)
133 Log (LOG_PLAIN
) << "Access denied trying to create rootdir registry value"
135 kr
= HKEY_CURRENT_USER
;
137 while (rv
== ERROR_ACCESS_DENIED
);
138 if (rv
!= ERROR_SUCCESS
)
139 MessageBox (NULL
, "Couldn't create registry key\n"
140 "to store installation path",
141 "Cygwin Setup", MB_OK
| MB_ICONWARNING
);
144 // The mount table is already in the right shape at this point.
145 // Reading it again is not necessary.
146 //read_mounts (std::string ());
150 unconvert_slashes (char *in_name
)
152 char *name
= in_name
;
153 while ((name
= strchr (name
, '/')) != NULL
)
161 while (*in
== ' ' || *in
== '\t')
169 while (*in
&& *in
!= ' ' && *in
!= '\t')
175 conv_fstab_spaces (char *field
)
177 register char *sp
= field
;
178 while ((sp
= strstr (sp
, "\\040")))
181 memmove (sp
, sp
+ 3, strlen (sp
+ 3) + 1);
186 static bool got_usr_bin
;
187 static bool got_usr_lib
;
190 from_fstab_line (mnt
*m
, char *line
)
192 char *native_path
, *posix_path
, *fs_type
;
194 /* First field: Native path. */
195 char *c
= skip_ws (line
);
196 if (!*c
|| *c
== '#')
198 char *cend
= find_ws (c
);
200 native_path
= conv_fstab_spaces (c
);
201 /* Second field: POSIX path. */
202 c
= skip_ws (cend
+ 1);
207 posix_path
= conv_fstab_spaces (c
);
208 /* Third field: FS type. */
209 c
= skip_ws (cend
+ 1);
216 if (strcmp (fs_type
, "cygdrive"))
218 for (mnt
*sm
= mount_table
; sm
< m
; ++sm
)
219 if (sm
->posix
== std::string (posix_path
))
221 sm
->native
= std::string (unconvert_slashes (native_path
));
224 m
->posix
= std::string (posix_path
);
225 m
->native
= std::string (unconvert_slashes (native_path
));
226 if (!strcmp (posix_path
, "/usr/bin"))
228 else if (!strcmp (posix_path
, "/usr/lib"))
234 #define BUFSIZE 65536
235 #define LFSTAB L"\\etc\\fstab"
238 from_fstab (mnt
*m
, const std::string
& in_path
)
241 WCHAR path
[in_path
.size () + sizeof (LFSTAB
)];
243 mklongpath (path
, in_path
.c_str (), sizeof (path
) / sizeof (WCHAR
));
244 wcscat (path
, LFSTAB
);
245 HANDLE h
= CreateFileW (path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
247 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
,
249 if (h
== INVALID_HANDLE_VALUE
)
253 /* Using BUFSIZE-2 leaves space to append two \0. */
254 while (ReadFile (h
, got
, BUFSIZE
- 2 - (got
- buf
), &len
, NULL
))
258 /* Set end marker. */
259 got
[len
] = got
[len
+ 1] = '\0';
260 /* Set len to the absolute len of bytes in buf. */
262 /* Reset got to start reading at the start of the buffer again. */
264 while (got
< buf
+ len
&& (end
= strchr (got
, '\n')))
266 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
267 if (from_fstab_line (m
, got
))
271 if (len
< BUFSIZE
- 1)
273 /* We have to read once more. Move remaining bytes to the start of
274 the buffer and reposition got so that it points to the end of
275 the remaining bytes. */
276 len
= buf
+ len
- got
;
277 memmove (buf
, got
, len
);
279 buf
[len
] = buf
[len
+ 1] = '\0';
281 if (got
> buf
&& from_fstab_line (m
, got
))
288 add_usr_mnts (struct mnt
*m
)
290 /* Set default /usr/bin and /usr/lib */
293 m
->posix
= "/usr/bin";
294 m
->native
= root_here
->native
+ "\\bin";
299 m
->posix
= "/usr/lib";
300 m
->native
= root_here
->native
+ "\\lib";
305 read_mounts (const std::string val
)
307 DWORD posix_path_size
;
308 struct mnt
*m
= mount_table
;
312 for (mnt
* m1
= mount_table
; m1
->posix
.size (); m1
++)
317 got_usr_bin
= got_usr_lib
= false;
319 root_scope
= (nt_sec
.isRunAsAdmin ())? IDC_ROOT_SYSTEM
: IDC_ROOT_USER
;
330 /* Always check HKEY_LOCAL_MACHINE first. */
331 for (int isuser
= 0; isuser
<= 1; isuser
++)
333 snprintf (buf
, sizeof(buf
), "Software\\%s\\%s",
334 CYGWIN_INFO_CYGWIN_REGISTRY_NAME
,
335 CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME
);
336 HKEY key
= isuser
? HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
;
337 if (RegOpenKeyEx (key
, buf
, 0, KEY_ALL_ACCESS
| SETUP_KEY_WOW64
,
338 &key
) != ERROR_SUCCESS
)
341 /* Cygwin rootdir always < MAX_PATH. */
342 char aBuffer
[MAX_PATH
+ 1];
343 posix_path_size
= MAX_PATH
;
345 (key
, "rootdir", 0, &type
, (BYTE
*) aBuffer
,
346 &posix_path_size
) == ERROR_SUCCESS
)
348 m
->native
= std::string (aBuffer
);
350 root_scope
= isuser
? IDC_ROOT_USER
: IDC_ROOT_SYSTEM
;
352 from_fstab (m
, root_here
->native
);
362 /* Affected path always < MAX_PATH. */
363 char windir
[MAX_PATH
];
364 GetSystemWindowsDirectory (windir
, sizeof (windir
));
366 m
->native
= std::string (windir
) + (is_64bit
? "\\cygwin64" : "\\cygwin");
374 set_root_dir (const std::string val
)
382 return root_here
? root_here
->native
: std::string();
385 /* Return non-zero if PATH1 is a prefix of PATH2.
386 Both are assumed to be of the same path style and / vs \ usage.
390 /foo/ is a prefix of /foo <-- may seem odd, but desired
391 /foo is a prefix of /foo/
392 / is a prefix of /foo/bar
393 / is not a prefix of foo/bar
394 foo/ is a prefix foo/bar
395 /foo is not a prefix of /foobar
399 path_prefix_p (const std::string path1
, const std::string path2
)
401 size_t len1
= path1
.size ();
402 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
403 if (len1
> 0 && SLASH_P (path1
.c_str ()[len1
- 1]))
407 return SLASH_P (path2
.c_str ()[0])
408 && !SLASH_P (path2
.c_str ()[1]);
410 if (casecompare(path1
, path2
, len1
) != 0)
413 return SLASH_P (path2
.c_str ()[len1
]) || path2
.size () == len1
414 || path1
.c_str ()[len1
- 1] == ':';
418 cygpath (const std::string
& thePath
)
421 struct mnt
*m
, *match
= NULL
;
422 for (m
= mount_table
; m
->posix
.size (); m
++)
424 size_t n
= m
->posix
.size ();
425 if (n
<= max_len
|| !path_prefix_p (m
->posix
, thePath
))
432 return std::string();
435 if (max_len
== thePath
.size ())
437 native
= match
->native
;
439 else if (match
->posix
.size () > 1)
440 native
= match
->native
+ thePath
.substr(max_len
, std::string::npos
);
442 native
= match
->native
+ "/" + thePath
.substr(max_len
, std::string::npos
);