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