]>
Commit | Line | Data |
---|---|---|
23c9e63c DD |
1 | /* |
2 | * Copyright (c) 2000, Red Hat, Inc. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or modify | |
5 | * it under the terms of the GNU General Public License as published by | |
6 | * the Free Software Foundation; either version 2 of the License, or | |
7 | * (at your option) any later version. | |
8 | * | |
9 | * A copy of the GNU General Public License can be found at | |
10 | * http://www.gnu.org/ | |
11 | * | |
12 | * Written by DJ Delorie <dj@cygnus.com> | |
13 | * | |
14 | */ | |
15 | ||
16 | /* The purpose of this file is to hide all the details about accessing | |
17 | Cygwin's mount table. If the format or location of the mount table | |
18 | changes, this is the file to change to match it. */ | |
19 | ||
b24c88b3 | 20 | #if 0 |
3c054baf | 21 | static const char *cvsid = "\n%%% $Id$\n"; |
b24c88b3 | 22 | #endif |
8507f105 | 23 | |
23c9e63c DD |
24 | #include "win32.h" |
25 | ||
26 | #include <stdio.h> | |
a351e48c | 27 | #include <stdlib.h> |
23c9e63c DD |
28 | #include "../cygwin/include/cygwin/version.h" |
29 | #include "../cygwin/include/sys/mount.h" | |
30 | ||
31 | #include "mount.h" | |
32 | #include "msg.h" | |
33 | #include "resource.h" | |
34 | #include "dialog.h" | |
a351e48c CF |
35 | #include "state.h" |
36 | #include "concat.h" | |
23c9e63c | 37 | |
3c054baf RC |
38 | #include "String++.h" |
39 | ||
a351e48c | 40 | static struct mnt |
b24c88b3 | 41 | { |
3c054baf RC |
42 | String native; |
43 | String posix; | |
b24c88b3 RC |
44 | int istext; |
45 | } | |
46 | mount_table[255]; | |
23c9e63c | 47 | |
85b43844 CF |
48 | struct mnt *root_here = NULL; |
49 | ||
3c054baf RC |
50 | static String |
51 | find2 (HKEY rkey, int *istext, String const &what) | |
23c9e63c | 52 | { |
a351e48c | 53 | HKEY key; |
23c9e63c | 54 | |
3c054baf RC |
55 | if (RegOpenKeyEx (rkey, what.cstr_oneuse (), 0, KEY_READ, &key) != |
56 | ERROR_SUCCESS) | |
23c9e63c DD |
57 | return 0; |
58 | ||
3c054baf RC |
59 | DWORD retvallen = 0; |
60 | DWORD type; | |
61 | ||
62 | String Sretval; | |
23c9e63c DD |
63 | if (RegQueryValueEx (key, "native", 0, &type, 0, &retvallen) |
64 | == ERROR_SUCCESS) | |
65 | { | |
3c054baf | 66 | char retval[retvallen]; |
b24c88b3 RC |
67 | if (RegQueryValueEx |
68 | (key, "native", 0, &type, (BYTE *) retval, | |
3c054baf RC |
69 | &retvallen) == ERROR_SUCCESS) |
70 | Sretval = String (retval); | |
23c9e63c DD |
71 | } |
72 | ||
3c054baf | 73 | DWORD flags = 0; |
23c9e63c | 74 | retvallen = sizeof (flags); |
b24c88b3 | 75 | RegQueryValueEx (key, "flags", 0, &type, (BYTE *) & flags, &retvallen); |
23c9e63c DD |
76 | |
77 | RegCloseKey (key); | |
78 | ||
3c054baf | 79 | if (Sretval.size ()) |
23c9e63c | 80 | *istext = (flags & MOUNT_BINARY) ? 0 : 1; |
23c9e63c | 81 | |
3c054baf | 82 | return Sretval; |
23c9e63c DD |
83 | } |
84 | ||
85 | void | |
3c054baf RC |
86 | create_mount (String const posix, String const win32, int istext, |
87 | int issystem) | |
23c9e63c DD |
88 | { |
89 | char buf[1000]; | |
23c9e63c | 90 | HKEY key; |
b24c88b3 | 91 | DWORD disposition; |
23c9e63c DD |
92 | DWORD flags; |
93 | ||
94 | remove_mount (posix); | |
95 | ||
96 | sprintf (buf, "Software\\%s\\%s\\%s\\%s", | |
97 | CYGWIN_INFO_CYGNUS_REGISTRY_NAME, | |
98 | CYGWIN_INFO_CYGWIN_REGISTRY_NAME, | |
3c054baf | 99 | CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, posix.cstr_oneuse ()); |
23c9e63c | 100 | |
24e259bb | 101 | HKEY kr = issystem ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; |
3c054baf | 102 | if (RegCreateKeyEx (kr, buf, 0, "Cygwin", 0, KEY_ALL_ACCESS, |
23c9e63c DD |
103 | 0, &key, &disposition) != ERROR_SUCCESS) |
104 | fatal ("mount"); | |
105 | ||
3c054baf RC |
106 | RegSetValueEx (key, "native", 0, REG_SZ, (BYTE *) win32.cstr_oneuse (), |
107 | win32.size () + 1); | |
24e259bb DD |
108 | flags = 0; |
109 | if (!istext) | |
110 | flags |= MOUNT_BINARY; | |
111 | if (issystem) | |
112 | flags |= MOUNT_SYSTEM; | |
b24c88b3 RC |
113 | RegSetValueEx (key, "flags", 0, REG_DWORD, (BYTE *) & flags, |
114 | sizeof (flags)); | |
115 | ||
116 | RegCloseKey (key); | |
0af2d779 | 117 | read_mounts (); |
23c9e63c DD |
118 | } |
119 | ||
120 | static void | |
3c054baf | 121 | remove1 (HKEY rkey, String const posix) |
23c9e63c DD |
122 | { |
123 | char buf[1000]; | |
124 | ||
125 | sprintf (buf, "Software\\%s\\%s\\%s\\%s", | |
126 | CYGWIN_INFO_CYGNUS_REGISTRY_NAME, | |
127 | CYGWIN_INFO_CYGWIN_REGISTRY_NAME, | |
3c054baf | 128 | CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME, posix.cstr_oneuse ()); |
23c9e63c DD |
129 | |
130 | RegDeleteKey (rkey, buf); | |
131 | } | |
132 | ||
133 | void | |
3c054baf | 134 | remove_mount (String const posix) |
23c9e63c DD |
135 | { |
136 | remove1 (HKEY_LOCAL_MACHINE, posix); | |
137 | remove1 (HKEY_CURRENT_USER, posix); | |
138 | } | |
f8a6415f DD |
139 | |
140 | static void | |
141 | set_cygdrive_flags (HKEY key, int istext, DWORD cygdrive_flags) | |
142 | { | |
143 | int cur_istext = (cygdrive_flags & MOUNT_BINARY) ? 0 : 1; | |
144 | if (cur_istext != istext) | |
145 | { | |
146 | if (!istext) | |
147 | cygdrive_flags |= MOUNT_BINARY; | |
148 | else | |
149 | cygdrive_flags &= ~MOUNT_BINARY; | |
150 | RegSetValueEx (key, CYGWIN_INFO_CYGDRIVE_FLAGS, 0, REG_DWORD, | |
b24c88b3 | 151 | (BYTE *) & cygdrive_flags, sizeof (cygdrive_flags)); |
f8a6415f DD |
152 | } |
153 | } | |
154 | ||
155 | static LONG | |
b24c88b3 | 156 | get_cygdrive_flags (HKEY key, DWORD * cygdrive_flags) |
f8a6415f | 157 | { |
b24c88b3 | 158 | DWORD retvallen = sizeof (*cygdrive_flags); |
f8a6415f | 159 | LONG status = RegQueryValueEx (key, CYGWIN_INFO_CYGDRIVE_FLAGS, 0, 0, |
b24c88b3 | 160 | (BYTE *) cygdrive_flags, &retvallen); |
f8a6415f DD |
161 | return status; |
162 | } | |
163 | ||
164 | static DWORD | |
b24c88b3 | 165 | default_cygdrive (HKEY key) |
f8a6415f DD |
166 | { |
167 | RegSetValueEx (key, CYGWIN_INFO_CYGDRIVE_PREFIX, 0, REG_SZ, | |
b24c88b3 | 168 | (BYTE *) CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX, |
f8a6415f DD |
169 | strlen (CYGWIN_INFO_CYGDRIVE_DEFAULT_PREFIX) + 1); |
170 | DWORD cygdrive_flags = MOUNT_AUTO; | |
171 | RegSetValueEx (key, CYGWIN_INFO_CYGDRIVE_FLAGS, 0, REG_DWORD, | |
b24c88b3 | 172 | (BYTE *) & cygdrive_flags, sizeof (cygdrive_flags)); |
f8a6415f DD |
173 | return cygdrive_flags; |
174 | } | |
175 | ||
176 | void | |
177 | set_cygdrive_flags (int istext, int issystem) | |
178 | { | |
179 | int found_system = 0; | |
180 | ||
181 | char buf[1000]; | |
182 | sprintf (buf, "Software\\%s\\%s\\%s", | |
183 | CYGWIN_INFO_CYGNUS_REGISTRY_NAME, | |
184 | CYGWIN_INFO_CYGWIN_REGISTRY_NAME, | |
185 | CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME); | |
186 | ||
187 | if (issystem) | |
188 | { | |
189 | HKEY key; | |
190 | DWORD disposition; | |
191 | LONG status = RegCreateKeyEx (HKEY_LOCAL_MACHINE, buf, 0, 0, 0, | |
b24c88b3 | 192 | KEY_ALL_ACCESS, 0, &key, &disposition); |
f8a6415f DD |
193 | if (status == ERROR_SUCCESS) |
194 | { | |
195 | DWORD cygdrive_flags = 0; | |
196 | status = get_cygdrive_flags (key, &cygdrive_flags); | |
197 | if (status == ERROR_SUCCESS) | |
198 | { | |
199 | set_cygdrive_flags (key, istext, cygdrive_flags); | |
200 | found_system = 1; | |
201 | } | |
b24c88b3 | 202 | RegCloseKey (key); |
f8a6415f DD |
203 | } |
204 | } | |
205 | ||
206 | HKEY key; | |
207 | DWORD disposition; | |
b24c88b3 RC |
208 | LONG status = |
209 | RegCreateKeyEx (HKEY_CURRENT_USER, buf, 0, 0, 0, KEY_ALL_ACCESS, | |
210 | 0, &key, &disposition); | |
f8a6415f DD |
211 | if (status != ERROR_SUCCESS) |
212 | fatal ("set_cygdrive_flags"); | |
213 | ||
214 | DWORD cygdrive_flags = 0; | |
215 | status = get_cygdrive_flags (key, &cygdrive_flags); | |
216 | if (status == ERROR_FILE_NOT_FOUND && !found_system) | |
217 | { | |
b24c88b3 | 218 | cygdrive_flags = default_cygdrive (key); |
f8a6415f DD |
219 | status = ERROR_SUCCESS; |
220 | } | |
221 | ||
222 | if (status == ERROR_SUCCESS) | |
223 | set_cygdrive_flags (key, istext, cygdrive_flags); | |
224 | ||
b24c88b3 | 225 | RegCloseKey (key); |
f8a6415f | 226 | } |
a351e48c | 227 | |
85b43844 | 228 | static int |
a351e48c CF |
229 | in_table (struct mnt *m) |
230 | { | |
b24c88b3 | 231 | for (struct mnt * m1 = mount_table; m1 < m; m1++) |
3c054baf | 232 | if (m1->posix.casecompare (m->posix) == 0) |
a351e48c CF |
233 | return 1; |
234 | return 0; | |
235 | } | |
236 | ||
237 | /* | |
238 | * is_admin () determines whether or not the current user is a member of the | |
239 | * Administrators group. On Windows 9X, the current user is considered an | |
240 | * Administrator by definition. | |
241 | */ | |
242 | ||
243 | static int | |
244 | is_admin () | |
245 | { | |
246 | // Windows 9X users are considered Administrators by definition | |
247 | OSVERSIONINFO verinfo; | |
248 | verinfo.dwOSVersionInfoSize = sizeof (verinfo); | |
249 | GetVersionEx (&verinfo); | |
250 | if (verinfo.dwPlatformId != VER_PLATFORM_WIN32_NT) | |
251 | return 1; | |
252 | ||
253 | // Get the process token for the current process | |
254 | HANDLE token; | |
b24c88b3 | 255 | BOOL status = OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &token); |
a351e48c CF |
256 | if (!status) |
257 | return 0; | |
258 | ||
259 | // Get the group token information | |
260 | UCHAR token_info[1024]; | |
261 | PTOKEN_GROUPS groups = (PTOKEN_GROUPS) token_info; | |
262 | DWORD token_info_len = sizeof (token_info); | |
b24c88b3 RC |
263 | status = |
264 | GetTokenInformation (token, TokenGroups, token_info, token_info_len, | |
265 | &token_info_len); | |
266 | CloseHandle (token); | |
a351e48c CF |
267 | if (!status) |
268 | return 0; | |
269 | ||
270 | // Create the Administrators group SID | |
271 | PSID admin_sid; | |
b24c88b3 RC |
272 | SID_IDENTIFIER_AUTHORITY authority = { SECURITY_NT_AUTHORITY }; |
273 | status = | |
274 | AllocateAndInitializeSid (&authority, 2, SECURITY_BUILTIN_DOMAIN_RID, | |
275 | DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, | |
276 | &admin_sid); | |
a351e48c CF |
277 | if (!status) |
278 | return 0; | |
279 | ||
280 | // Check to see if the user is a member of the Administrators group | |
281 | status = 0; | |
b24c88b3 RC |
282 | for (UINT i = 0; i < groups->GroupCount; i++) |
283 | { | |
284 | if (EqualSid (groups->Groups[i].Sid, admin_sid)) | |
285 | { | |
286 | status = 1; | |
287 | break; | |
288 | } | |
a351e48c | 289 | } |
a351e48c CF |
290 | |
291 | // Destroy the Administrators group SID | |
292 | FreeSid (admin_sid); | |
293 | ||
294 | // Return whether or not the user is a member of the Administrators group | |
295 | return status; | |
296 | } | |
297 | ||
298 | void | |
299 | read_mounts () | |
300 | { | |
301 | DWORD posix_path_size; | |
302 | int res; | |
303 | struct mnt *m = mount_table; | |
304 | DWORD disposition; | |
305 | char buf[10000]; | |
306 | ||
0af2d779 | 307 | root_here = NULL; |
3c054baf | 308 | for (mnt * m1 = mount_table; m1->posix.size (); m1++) |
0af2d779 | 309 | { |
3c054baf RC |
310 | m1->posix = String (); //empty string; |
311 | m1->native = String (); | |
0af2d779 CF |
312 | } |
313 | ||
a351e48c CF |
314 | /* Loop through subkeys */ |
315 | /* FIXME: we would like to not check MAX_MOUNTS but the heap in the | |
316 | shared area is currently statically allocated so we can't have an | |
317 | arbitrarily large number of mounts. */ | |
318 | for (int issystem = 0; issystem <= 1; issystem++) | |
319 | { | |
320 | sprintf (buf, "Software\\%s\\%s\\%s", | |
321 | CYGWIN_INFO_CYGNUS_REGISTRY_NAME, | |
322 | CYGWIN_INFO_CYGWIN_REGISTRY_NAME, | |
323 | CYGWIN_INFO_CYGWIN_MOUNT_REGISTRY_NAME); | |
324 | ||
325 | HKEY key = issystem ? HKEY_LOCAL_MACHINE : HKEY_CURRENT_USER; | |
3c054baf | 326 | if (RegCreateKeyEx (key, buf, 0, "Cygwin", 0, KEY_ALL_ACCESS, |
a351e48c CF |
327 | 0, &key, &disposition) != ERROR_SUCCESS) |
328 | break; | |
b24c88b3 | 329 | for (int i = 0;; i++, m++) |
a351e48c | 330 | { |
3c054baf | 331 | char aBuffer[MAX_PATH + 1]; |
a351e48c CF |
332 | posix_path_size = MAX_PATH; |
333 | /* FIXME: if maximum posix_path_size is 256, we're going to | |
334 | run into problems if we ever try to store a mount point that's | |
335 | over 256 but is under MAX_PATH. */ | |
3c054baf | 336 | res = RegEnumKeyEx (key, i, aBuffer, &posix_path_size, NULL, |
a351e48c CF |
337 | NULL, NULL, NULL); |
338 | ||
339 | if (res == ERROR_NO_MORE_ITEMS) | |
0af2d779 | 340 | { |
3c054baf | 341 | m->posix = String (); |
0af2d779 CF |
342 | break; |
343 | } | |
3c054baf | 344 | m->posix = String (aBuffer); |
a351e48c | 345 | |
3c054baf | 346 | if (!m->posix.size () || in_table (m)) |
0af2d779 | 347 | goto no_go; |
a351e48c CF |
348 | else if (res != ERROR_SUCCESS) |
349 | break; | |
350 | else | |
351 | { | |
352 | m->native = find2 (key, &m->istext, m->posix); | |
3c054baf | 353 | if (!m->native.size ()) |
0af2d779 | 354 | goto no_go; |
b24c88b3 | 355 | |
3c054baf | 356 | if (m->posix == "/") |
a351e48c | 357 | { |
85b43844 | 358 | root_here = m; |
a351e48c CF |
359 | if (m->istext) |
360 | root_text = IDC_ROOT_TEXT; | |
361 | else | |
362 | root_text = IDC_ROOT_BINARY; | |
363 | if (issystem) | |
364 | root_scope = IDC_ROOT_SYSTEM; | |
365 | else | |
366 | root_scope = IDC_ROOT_USER; | |
367 | } | |
368 | } | |
0af2d779 CF |
369 | continue; |
370 | no_go: | |
3c054baf RC |
371 | m->posix = String (); |
372 | --m; | |
a351e48c CF |
373 | } |
374 | RegCloseKey (key); | |
375 | } | |
376 | ||
85b43844 | 377 | if (!root_here) |
a351e48c | 378 | { |
85b43844 | 379 | root_here = m; |
3c054baf | 380 | m->posix = String ("/"); |
a351e48c | 381 | char windir[_MAX_PATH]; |
a351e48c | 382 | root_text = IDC_ROOT_BINARY; |
b24c88b3 | 383 | root_scope = (is_admin ())? IDC_ROOT_SYSTEM : IDC_ROOT_USER; |
85b43844 CF |
384 | GetWindowsDirectory (windir, sizeof (windir)); |
385 | windir[2] = 0; | |
3c054baf | 386 | set_root_dir (String (windir) + "\\cygwin"); |
0af2d779 | 387 | m++; |
a351e48c | 388 | } |
a351e48c CF |
389 | } |
390 | ||
85b43844 | 391 | void |
3c054baf | 392 | set_root_dir (String const val) |
85b43844 CF |
393 | { |
394 | root_here->native = val; | |
395 | } | |
396 | ||
3c054baf | 397 | String const |
85b43844 CF |
398 | get_root_dir () |
399 | { | |
3c054baf | 400 | return root_here ? root_here->native : String (); |
85b43844 CF |
401 | } |
402 | ||
a351e48c CF |
403 | /* Return non-zero if PATH1 is a prefix of PATH2. |
404 | Both are assumed to be of the same path style and / vs \ usage. | |
405 | Neither may be "". | |
a351e48c CF |
406 | |
407 | Examples: | |
408 | /foo/ is a prefix of /foo <-- may seem odd, but desired | |
409 | /foo is a prefix of /foo/ | |
410 | / is a prefix of /foo/bar | |
411 | / is not a prefix of foo/bar | |
412 | foo/ is a prefix foo/bar | |
413 | /foo is not a prefix of /foobar | |
414 | */ | |
415 | ||
416 | static int | |
3c054baf | 417 | path_prefix_p (String const path1, String const path2) |
a351e48c | 418 | { |
3c054baf | 419 | size_t len1 = path1.size (); |
a351e48c | 420 | /* Handle case where PATH1 has trailing '/' and when it doesn't. */ |
3c054baf RC |
421 | if (len1 > 0 && SLASH_P (path1.cstr_oneuse ()[len1 - 1])) |
422 | --len1; | |
a351e48c CF |
423 | |
424 | if (len1 == 0) | |
3c054baf RC |
425 | return SLASH_P (path2.cstr_oneuse ()[0]) |
426 | && !SLASH_P (path2.cstr_oneuse ()[1]); | |
a351e48c | 427 | |
3c054baf | 428 | if (path1.casecompare (path2, len1) != 0) |
a351e48c CF |
429 | return 0; |
430 | ||
3c054baf RC |
431 | return SLASH_P (path2.cstr_oneuse ()[len1]) || path2.size () == len1 |
432 | || path1.cstr_oneuse ()[len1 - 1] == ':'; | |
a351e48c CF |
433 | } |
434 | ||
3c054baf RC |
435 | static String |
436 | cygpath (String const &thePath) | |
a351e48c | 437 | { |
3c054baf | 438 | size_t max_len = 0; |
b24c88b3 | 439 | struct mnt *m, *match = NULL; |
3c054baf | 440 | for (m = mount_table; m->posix.size (); m++) |
a351e48c | 441 | { |
3c054baf RC |
442 | size_t n = m->posix.size (); |
443 | if (n <= max_len || !path_prefix_p (m->posix, thePath)) | |
a351e48c CF |
444 | continue; |
445 | max_len = n; | |
446 | match = m; | |
447 | } | |
448 | ||
b24c88b3 RC |
449 | if (!match) |
450 | return NULL; | |
451 | ||
3c054baf RC |
452 | String native; |
453 | if (max_len == thePath.size ()) | |
454 | { | |
455 | native = match->native; | |
456 | } | |
a351e48c | 457 | else |
3c054baf | 458 | native = match->native + "/" + String (thePath.cstr_oneuse () + max_len); |
a351e48c CF |
459 | return native; |
460 | } | |
3c054baf RC |
461 | |
462 | String | |
463 | cygpath (const char *s, ...) | |
464 | { | |
465 | va_list v; | |
466 | ||
467 | va_start (v, s); | |
468 | char *path = vconcat (s, v); | |
469 | if (strncmp (path, "./", 2) == 0) | |
470 | memmove (path, path + 2, strlen (path + 2) + 1); | |
471 | if (strncmp (path, "/./", 3) == 0) | |
472 | memmove (path + 1, path + 3, strlen (path + 3) + 1); | |
473 | ||
474 | String thePath (path); | |
475 | delete[]path; | |
476 | return cygpath (thePath); | |
477 | } |