README: document some recent changes in the build environment
[cygwin-setup.git] / mount.cc
blobbf198a59365128daf902535332024b4e08ae42ec
1 /*
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
11 * http://www.gnu.org/
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. */
21 #if 0
22 static const char *cvsid = "\n%%% $Id$\n";
23 #endif
25 #include "ini.h"
26 #include "win32.h"
27 #include "filemanip.h"
28 #include "LogSingleton.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <malloc.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
44 #ifdef __cplusplus
45 extern "C" {
46 #endif
48 enum
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);
63 #ifdef __cplusplus
65 #endif
69 #include "mount.h"
70 #include "msg.h"
71 #include "resource.h"
72 #include "dialog.h"
73 #include "state.h"
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())
81 #endif
83 /* Used when treating / and \ as equivalent. */
84 #define SLASH_P(ch) \
85 ({ \
86 char __c = (ch); \
87 ((__c) == '/' || (__c) == '\\'); \
90 static struct mnt
92 std::string native;
93 std::string posix;
94 int istext;
96 mount_table[255];
98 struct mnt *root_here = NULL;
100 void
101 create_install_root ()
103 char buf[1000];
104 HKEY key;
105 DWORD disposition;
106 DWORD rv;
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)
119 break;
120 Log (LOG_PLAIN) << "Access denied trying to create rootdir registry key"
121 << endLog;
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)
132 break;
133 Log (LOG_PLAIN) << "Access denied trying to create rootdir registry value"
134 << endLog;
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);
142 RegCloseKey (key);
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 ());
149 inline char *
150 unconvert_slashes (char *in_name)
152 char *name = in_name;
153 while ((name = strchr (name, '/')) != NULL)
154 *name++ = '\\';
155 return in_name;
158 inline char *
159 skip_ws (char *in)
161 while (*in == ' ' || *in == '\t')
162 ++in;
163 return in;
166 inline char *
167 find_ws (char *in)
169 while (*in && *in != ' ' && *in != '\t')
170 ++in;
171 return in;
174 inline char *
175 conv_fstab_spaces (char *field)
177 register char *sp = field;
178 while ((sp = strstr (sp, "\\040")))
180 *sp++ = ' ';
181 memmove (sp, sp + 3, strlen (sp + 3) + 1);
183 return field;
186 static bool got_usr_bin;
187 static bool got_usr_lib;
189 static bool
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 == '#')
197 return false;
198 char *cend = find_ws (c);
199 *cend = '\0';
200 native_path = conv_fstab_spaces (c);
201 /* Second field: POSIX path. */
202 c = skip_ws (cend + 1);
203 if (!*c)
204 return false;
205 cend = find_ws (c);
206 *cend = '\0';
207 posix_path = conv_fstab_spaces (c);
208 /* Third field: FS type. */
209 c = skip_ws (cend + 1);
210 if (!*c)
211 return false;
212 cend = find_ws (c);
213 *cend = '\0';
214 fs_type = c;
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));
222 return false;
224 m->posix = std::string (posix_path);
225 m->native = std::string (unconvert_slashes (native_path));
226 if (!strcmp (posix_path, "/usr/bin"))
227 got_usr_bin = true;
228 else if (!strcmp (posix_path, "/usr/lib"))
229 got_usr_lib = true;
231 return true;
234 #define BUFSIZE 65536
235 #define LFSTAB L"\\etc\\fstab"
237 static bool
238 from_fstab (mnt *m, const std::string& in_path)
240 char buf[BUFSIZE];
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,
246 OPEN_EXISTING,
247 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS,
248 NULL);
249 if (h == INVALID_HANDLE_VALUE)
250 return false;
251 char *got = buf;
252 DWORD len = 0;
253 /* Using BUFSIZE-2 leaves space to append two \0. */
254 while (ReadFile (h, got, BUFSIZE - 2 - (got - buf), &len, NULL))
256 char *end;
258 /* Set end marker. */
259 got[len] = got[len + 1] = '\0';
260 /* Set len to the absolute len of bytes in buf. */
261 len += got - buf;
262 /* Reset got to start reading at the start of the buffer again. */
263 got = buf;
264 while (got < buf + len && (end = strchr (got, '\n')))
266 end[end[-1] == '\r' ? -1 : 0] = '\0';
267 if (from_fstab_line (m, got))
268 ++m;
269 got = end + 1;
271 if (len < BUFSIZE - 1)
272 break;
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);
278 got = buf + len;
279 buf[len] = buf[len + 1] = '\0';
281 if (got > buf && from_fstab_line (m, got))
282 ++m;
283 CloseHandle (h);
284 return true;
287 static void
288 add_usr_mnts (struct mnt *m)
290 /* Set default /usr/bin and /usr/lib */
291 if (!got_usr_bin)
293 m->posix = "/usr/bin";
294 m->native = root_here->native + "\\bin";
295 ++m;
297 if (!got_usr_lib)
299 m->posix = "/usr/lib";
300 m->native = root_here->native + "\\lib";
304 void
305 read_mounts (const std::string val)
307 DWORD posix_path_size;
308 struct mnt *m = mount_table;
309 char buf[10000];
311 root_here = NULL;
312 for (mnt * m1 = mount_table; m1->posix.size (); m1++)
314 m1->posix.clear();
315 m1->native.clear();
317 got_usr_bin = got_usr_lib = false;
319 root_scope = (nt_sec.isRunAsAdmin ())? IDC_ROOT_SYSTEM : IDC_ROOT_USER;
321 if (val.size ())
323 m->native = val;
324 m->posix = "/";
325 root_here = m;
326 add_usr_mnts (++m);
328 else
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)
339 continue;
340 DWORD type;
341 /* Cygwin rootdir always < MAX_PATH. */
342 char aBuffer[MAX_PATH + 1];
343 posix_path_size = MAX_PATH;
344 if (RegQueryValueEx
345 (key, "rootdir", 0, &type, (BYTE *) aBuffer,
346 &posix_path_size) == ERROR_SUCCESS)
348 m->native = std::string (aBuffer);
349 m->posix = "/";
350 root_scope = isuser ? IDC_ROOT_USER : IDC_ROOT_SYSTEM;
351 root_here = m++;
352 from_fstab (m, root_here->native);
353 add_usr_mnts (m);
354 break;
356 RegCloseKey (key);
360 if (!root_here)
362 /* Affected path always < MAX_PATH. */
363 char windir[MAX_PATH];
364 GetSystemWindowsDirectory (windir, sizeof (windir));
365 windir[2] = 0;
366 m->native = std::string (windir) + (is_64bit ? "\\cygwin64" : "\\cygwin");
367 m->posix = "/";
368 root_here = m;
369 add_usr_mnts (++m);
373 void
374 set_root_dir (const std::string val)
376 read_mounts (val);
379 const std::string
380 get_root_dir ()
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.
387 Neither may be "".
389 Examples:
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
398 static int
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]))
404 --len1;
406 if (len1 == 0)
407 return SLASH_P (path2.c_str ()[0])
408 && !SLASH_P (path2.c_str ()[1]);
410 if (casecompare(path1, path2, len1) != 0)
411 return 0;
413 return SLASH_P (path2.c_str ()[len1]) || path2.size () == len1
414 || path1.c_str ()[len1 - 1] == ':';
417 std::string
418 cygpath (const std::string& thePath)
420 size_t max_len = 0;
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))
426 continue;
427 max_len = n;
428 match = m;
431 if (!match)
432 return std::string();
434 std::string native;
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);
441 else
442 native = match->native + "/" + thePath.substr(max_len, std::string::npos);
443 return native;