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
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. */
23 #include "filemanip.h"
24 #include "LogSingleton.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
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);
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())
79 /* Used when treating / and \ as equivalent. */
83 ((__c) == '/' || (__c) == '\\'); \
94 struct mnt
*root_here
= NULL
;
97 create_install_root ()
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
)
116 Log (LOG_PLAIN
) << "Access denied trying to create rootdir registry key"
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
)
129 Log (LOG_PLAIN
) << "Access denied trying to create rootdir registry value"
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
);
138 Log (LOG_TIMESTAMP
) << "Registry value set: HKEY_"
139 << (root_scope
== IDC_ROOT_USER
? "CURRENT_USER\\"
141 << buf
<< "\\rootdir = \"" << get_root_dir () << "\""
146 unconvert_slashes (char *in_name
)
148 char *name
= in_name
;
149 while ((name
= strchr (name
, '/')) != NULL
)
157 while (*in
== ' ' || *in
== '\t')
165 while (*in
&& *in
!= ' ' && *in
!= '\t')
171 conv_fstab_spaces (char *field
)
173 register char *sp
= field
;
174 while ((sp
= strstr (sp
, "\\040")))
177 memmove (sp
, sp
+ 3, strlen (sp
+ 3) + 1);
182 static bool got_usr_bin
;
183 static bool got_usr_lib
;
186 from_fstab_line (mnt
*m
, char *line
)
188 char *native_path
, *posix_path
, *fs_type
;
190 /* First field: Native path. */
191 char *c
= skip_ws (line
);
192 if (!*c
|| *c
== '#')
194 char *cend
= find_ws (c
);
196 native_path
= conv_fstab_spaces (c
);
197 /* Second field: POSIX path. */
198 c
= skip_ws (cend
+ 1);
203 posix_path
= conv_fstab_spaces (c
);
204 /* Third field: FS type. */
205 c
= skip_ws (cend
+ 1);
212 if (strcmp (fs_type
, "cygdrive"))
214 for (mnt
*sm
= mount_table
; sm
< m
; ++sm
)
215 if (sm
->posix
== std::string (posix_path
))
217 sm
->native
= std::string (unconvert_slashes (native_path
));
220 m
->posix
= std::string (posix_path
);
221 m
->native
= std::string (unconvert_slashes (native_path
));
222 if (!strcmp (posix_path
, "/usr/bin"))
224 else if (!strcmp (posix_path
, "/usr/lib"))
230 #define BUFSIZE 65536
231 #define LFSTAB L"\\etc\\fstab"
234 from_fstab (mnt
*m
, const std::string
& in_path
)
237 WCHAR path
[in_path
.size () + sizeof (LFSTAB
)];
239 mklongpath (path
, in_path
.c_str (), sizeof (path
) / sizeof (WCHAR
));
240 wcscat (path
, LFSTAB
);
241 HANDLE h
= CreateFileW (path
, GENERIC_READ
, FILE_SHARE_READ
, NULL
,
243 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
,
245 if (h
== INVALID_HANDLE_VALUE
)
249 /* Using BUFSIZE-2 leaves space to append two \0. */
250 while (ReadFile (h
, got
, BUFSIZE
- 2 - (got
- buf
), &len
, NULL
))
254 /* Set end marker. */
255 got
[len
] = got
[len
+ 1] = '\0';
256 /* Set len to the absolute len of bytes in buf. */
258 /* Reset got to start reading at the start of the buffer again. */
260 while (got
< buf
+ len
&& (end
= strchr (got
, '\n')))
262 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
263 if (from_fstab_line (m
, got
))
267 if (len
< BUFSIZE
- 1)
269 /* We have to read once more. Move remaining bytes to the start of
270 the buffer and reposition got so that it points to the end of
271 the remaining bytes. */
272 len
= buf
+ len
- got
;
273 memmove (buf
, got
, len
);
275 buf
[len
] = buf
[len
+ 1] = '\0';
277 if (got
> buf
&& from_fstab_line (m
, got
))
284 add_usr_mnts (struct mnt
*m
)
286 /* Set default /usr/bin and /usr/lib */
289 m
->posix
= "/usr/bin";
290 m
->native
= root_here
->native
+ "\\bin";
295 m
->posix
= "/usr/lib";
296 m
->native
= root_here
->native
+ "\\lib";
301 read_mounts (const std::string val
)
303 DWORD posix_path_size
;
304 struct mnt
*m
= mount_table
;
308 for (mnt
* m1
= mount_table
; m1
->posix
.size (); m1
++)
313 got_usr_bin
= got_usr_lib
= false;
317 /* Cygwin rootdir always < MAX_PATH. */
318 char rootdir
[MAX_PATH
+ 1];
320 if (GetFullPathName (val
.c_str (), MAX_PATH
+ 1, rootdir
, NULL
))
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
)
341 /* Cygwin rootdir always < MAX_PATH. */
342 char aBuffer
[MAX_PATH
+ 1];
343 posix_path_size
= MAX_PATH
;
345 (key
, "rootdir", 0, &type
, (BYTE
*) aBuffer
,
346 &posix_path_size
) == ERROR_SUCCESS
)
348 m
->native
= std::string (aBuffer
);
351 from_fstab (m
, root_here
->native
);
361 /* Affected path always < MAX_PATH. */
362 char windir
[MAX_PATH
];
363 GetSystemWindowsDirectory (windir
, sizeof (windir
));
365 m
->native
= std::string (windir
) + (is_64bit
? "\\cygwin64" : "\\cygwin");
372 // set default root_scope: USER if only HKEY_CURRENT_USER registry key exists,
374 void set_default_root_scope()
376 root_scope
= IDC_ROOT_SYSTEM
;
379 for (int isuser
= 0; isuser
<= 1; isuser
++)
381 snprintf (buf
, sizeof(buf
), "Software\\%s\\%s",
382 CYGWIN_INFO_CYGWIN_REGISTRY_NAME
,
383 CYGWIN_INFO_CYGWIN_SETUP_REGISTRY_NAME
);
384 HKEY key
= isuser
? HKEY_CURRENT_USER
: HKEY_LOCAL_MACHINE
;
385 if (RegOpenKeyEx (key
, buf
, 0, KEY_ALL_ACCESS
| SETUP_KEY_WOW64
,
386 &key
) == ERROR_SUCCESS
)
389 root_scope
= isuser
? IDC_ROOT_USER
: IDC_ROOT_SYSTEM
;
396 set_root_dir (const std::string val
)
401 static std::string empty
;
406 return root_here
? root_here
->native
: empty
;
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.
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
423 path_prefix_p (const std::string path1
, const std::string path2
)
425 size_t len1
= path1
.size ();
426 /* Handle case where PATH1 has trailing '/' and when it doesn't. */
427 if (len1
> 0 && SLASH_P (path1
.c_str ()[len1
- 1]))
431 return SLASH_P (path2
.c_str ()[0])
432 && !SLASH_P (path2
.c_str ()[1]);
434 if (casecompare(path1
, path2
, len1
) != 0)
437 return SLASH_P (path2
.c_str ()[len1
]) || path2
.size () == len1
438 || path1
.c_str ()[len1
- 1] == ':';
442 cygpath (const std::string
& thePath
)
445 struct mnt
*m
, *match
= NULL
;
446 for (m
= mount_table
; m
->posix
.size (); m
++)
448 size_t n
= m
->posix
.size ();
449 if (n
<= max_len
|| !path_prefix_p (m
->posix
, thePath
))
456 return std::string();
459 if (max_len
== thePath
.size ())
461 native
= match
->native
;
463 else if (match
->posix
.size () > 1)
464 native
= match
->native
+ thePath
.substr(max_len
, std::string::npos
);
466 native
= match
->native
+ "/" + thePath
.substr(max_len
, std::string::npos
);