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