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