Show deprecation warning for Windows versions 6.1 and 6.2
[cygwin-setup.git] / mount.cc
blob01363965b54be43fab46278b25eb4bc6b9686e0a
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 #include "ini.h"
22 #include "win32.h"
23 #include "filemanip.h"
24 #include "LogSingleton.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <malloc.h>
30 // These headers aren't available outside the winsup tree
31 // #include "../cygwin/include/cygwin/version.h"
32 // KEEP SYNCHRONISED WITH /src/winsup/cygwin/include/cygwin/version.h
34 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME "Cygwin"
35 #define CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME "setup"
37 // #include "../cygwin/include/sys/mount.h"
39 // KEEP SYNCHRONISED WITH /src/winsup/cygwin/include/sys/mount.h
40 #ifdef __cplusplus
41 extern "C" {
42 #endif
44 enum
46 MOUNT_SYMLINK = 0x001, /* "mount point" is a symlink */
47 MOUNT_BINARY = 0x002, /* "binary" format read/writes */
48 MOUNT_SYSTEM = 0x008, /* mount point came from system table */
49 MOUNT_EXEC = 0x010, /* Any file in the mounted directory gets 'x' bit */
50 MOUNT_AUTO = 0x020, /* mount point refers to auto device mount */
51 MOUNT_CYGWIN_EXEC = 0x040, /* file or directory is or contains a cygwin executable */
52 MOUNT_MIXED = 0x080, /* reads are text, writes are binary */
55 // int mount (const char *, const char *, unsigned __flags);
56 // int umount (const char *);
57 // int cygwin_umount (const char *__path, unsigned __flags);
59 #ifdef __cplusplus
61 #endif
65 #include "mount.h"
66 #include "msg.h"
67 #include "resource.h"
68 #include "dialog.h"
69 #include "state.h"
71 #ifdef MAINTAINER_FEATURES
72 #include "getopt++/GetOption.h"
73 #include "getopt++/StringOption.h"
74 static StringOption CygwinRegistryNameOption (CYGWIN_INFO_CYGWIN_REGISTRY_NAME, '#', "override-registry-name", "Override registry name to allow parallel installs for testing purposes", false);
75 #undef CYGWIN_INFO_CYGWIN_REGISTRY_NAME
76 #define CYGWIN_INFO_CYGWIN_REGISTRY_NAME (((std::string)CygwinRegistryNameOption).c_str())
77 #endif
79 /* Used when treating / and \ as equivalent. */
80 #define SLASH_P(ch) \
81 ({ \
82 char __c = (ch); \
83 ((__c) == '/' || (__c) == '\\'); \
86 static struct mnt
88 std::string native;
89 std::string posix;
90 int istext;
92 mount_table[255];
94 struct mnt *root_here = NULL;
96 void
97 create_install_root ()
99 char buf[1000];
100 HKEY key;
101 DWORD disposition;
102 DWORD rv;
104 snprintf (buf, sizeof(buf), "Software\\%s\\%s",
105 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
106 CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME);
107 HKEY kr = (root_scope == IDC_ROOT_USER) ? HKEY_CURRENT_USER
108 : HKEY_LOCAL_MACHINE;
111 rv = RegCreateKeyEx (kr, buf, 0, (char *)"Cygwin", 0,
112 KEY_ALL_ACCESS | SETUP_KEY_WOW64,
113 0, &key, &disposition);
114 if (rv != ERROR_ACCESS_DENIED || kr != HKEY_LOCAL_MACHINE)
115 break;
116 Log (LOG_PLAIN) << "Access denied trying to create rootdir registry key"
117 << endLog;
118 kr = HKEY_CURRENT_USER;
120 while (rv == ERROR_ACCESS_DENIED);
121 if (rv == ERROR_SUCCESS)
124 rv = RegSetValueEx (key, "rootdir", 0, REG_SZ,
125 (BYTE *) get_root_dir ().c_str (),
126 get_root_dir ().size () + 1);
127 if (rv != ERROR_ACCESS_DENIED || kr != HKEY_LOCAL_MACHINE)
128 break;
129 Log (LOG_PLAIN) << "Access denied trying to create rootdir registry value"
130 << endLog;
131 kr = HKEY_CURRENT_USER;
133 while (rv == ERROR_ACCESS_DENIED);
134 if (rv != ERROR_SUCCESS)
135 mbox (NULL, IDS_MOUNT_REGISTRY_KEY_FAILED, MB_OK | MB_ICONWARNING);
136 RegCloseKey (key);
138 Log (LOG_TIMESTAMP) << "Registry value set: HKEY_"
139 << (root_scope == IDC_ROOT_USER ? "CURRENT_USER\\"
140 : "LOCAL_MACHINE\\")
141 << buf << "\\rootdir = \"" << get_root_dir () << "\""
142 << endLog;
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 /* Cygwin rootdir always < MAX_PATH. */
324 char rootdir[MAX_PATH + 1];
326 if (GetFullPathName (val.c_str (), MAX_PATH + 1, rootdir, NULL))
328 m->native = rootdir;
329 m->posix = "/";
330 root_here = m;
331 add_usr_mnts (++m);
334 else
336 /* Always check HKEY_LOCAL_MACHINE first. */
337 for (int isuser = 0; isuser <= 1; isuser++)
339 snprintf (buf, sizeof(buf), "Software\\%s\\%s",
340 CYGWIN_INFO_CYGWIN_REGISTRY_NAME,
341 CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME);
342 HKEY key = isuser ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
343 if (RegOpenKeyEx (key, buf, 0, KEY_ALL_ACCESS | SETUP_KEY_WOW64,
344 &key) != ERROR_SUCCESS)
345 continue;
346 DWORD type;
347 /* Cygwin rootdir always < MAX_PATH. */
348 char aBuffer[MAX_PATH + 1];
349 posix_path_size = MAX_PATH;
350 if (RegQueryValueEx
351 (key, "rootdir", 0, &type, (BYTE *) aBuffer,
352 &posix_path_size) == ERROR_SUCCESS)
354 m->native = std::string (aBuffer);
355 m->posix = "/";
356 root_scope = isuser ? IDC_ROOT_USER : IDC_ROOT_SYSTEM;
357 root_here = m++;
358 from_fstab (m, root_here->native);
359 add_usr_mnts (m);
360 break;
362 RegCloseKey (key);
366 if (!root_here)
368 /* Affected path always < MAX_PATH. */
369 char windir[MAX_PATH];
370 GetSystemWindowsDirectory (windir, sizeof (windir));
371 windir[2] = 0;
372 m->native = std::string (windir) + (is_64bit ? "\\cygwin64" : "\\cygwin");
373 m->posix = "/";
374 root_here = m;
375 add_usr_mnts (++m);
379 void
380 set_root_dir (const std::string val)
382 read_mounts (val);
385 static std::string empty;
387 const std::string &
388 get_root_dir ()
390 return root_here ? root_here->native : empty;
393 /* Return non-zero if PATH1 is a prefix of PATH2.
394 Both are assumed to be of the same path style and / vs \ usage.
395 Neither may be "".
397 Examples:
398 /foo/ is a prefix of /foo <-- may seem odd, but desired
399 /foo is a prefix of /foo/
400 / is a prefix of /foo/bar
401 / is not a prefix of foo/bar
402 foo/ is a prefix foo/bar
403 /foo is not a prefix of /foobar
406 static int
407 path_prefix_p (const std::string path1, const std::string path2)
409 size_t len1 = path1.size ();
410 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
411 if (len1 > 0 && SLASH_P (path1.c_str ()[len1 - 1]))
412 --len1;
414 if (len1 == 0)
415 return SLASH_P (path2.c_str ()[0])
416 && !SLASH_P (path2.c_str ()[1]);
418 if (casecompare(path1, path2, len1) != 0)
419 return 0;
421 return SLASH_P (path2.c_str ()[len1]) || path2.size () == len1
422 || path1.c_str ()[len1 - 1] == ':';
425 std::string
426 cygpath (const std::string& thePath)
428 size_t max_len = 0;
429 struct mnt *m, *match = NULL;
430 for (m = mount_table; m->posix.size (); m++)
432 size_t n = m->posix.size ();
433 if (n <= max_len || !path_prefix_p (m->posix, thePath))
434 continue;
435 max_len = n;
436 match = m;
439 if (!match)
440 return std::string();
442 std::string native;
443 if (max_len == thePath.size ())
445 native = match->native;
447 else if (match->posix.size () > 1)
448 native = match->native + thePath.substr(max_len, std::string::npos);
449 else
450 native = match->native + "/" + thePath.substr(max_len, std::string::npos);
451 return native;