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 () << "\""
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 ());
150 unconvert_slashes (char *in_name
)
152 char *name
= in_name
;
153 while ((name
= strchr (name
, '/')) != NULL
)
161 while (*in
== ' ' || *in
== '\t')
169 while (*in
&& *in
!= ' ' && *in
!= '\t')
175 conv_fstab_spaces (char *field
)
177 register char *sp
= field
;
178 while ((sp
= strstr (sp
, "\\040")))
181 memmove (sp
, sp
+ 3, strlen (sp
+ 3) + 1);
186 static bool got_usr_bin
;
187 static bool got_usr_lib
;
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
== '#')
198 char *cend
= find_ws (c
);
200 native_path
= conv_fstab_spaces (c
);
201 /* Second field: POSIX path. */
202 c
= skip_ws (cend
+ 1);
207 posix_path
= conv_fstab_spaces (c
);
208 /* Third field: FS type. */
209 c
= skip_ws (cend
+ 1);
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
));
224 m
->posix
= std::string (posix_path
);
225 m
->native
= std::string (unconvert_slashes (native_path
));
226 if (!strcmp (posix_path
, "/usr/bin"))
228 else if (!strcmp (posix_path
, "/usr/lib"))
234 #define BUFSIZE 65536
235 #define LFSTAB L"\\etc\\fstab"
238 from_fstab (mnt
*m
, const std::string
& in_path
)
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
,
247 FILE_ATTRIBUTE_NORMAL
| FILE_FLAG_BACKUP_SEMANTICS
,
249 if (h
== INVALID_HANDLE_VALUE
)
253 /* Using BUFSIZE-2 leaves space to append two \0. */
254 while (ReadFile (h
, got
, BUFSIZE
- 2 - (got
- buf
), &len
, NULL
))
258 /* Set end marker. */
259 got
[len
] = got
[len
+ 1] = '\0';
260 /* Set len to the absolute len of bytes in buf. */
262 /* Reset got to start reading at the start of the buffer again. */
264 while (got
< buf
+ len
&& (end
= strchr (got
, '\n')))
266 end
[end
[-1] == '\r' ? -1 : 0] = '\0';
267 if (from_fstab_line (m
, got
))
271 if (len
< BUFSIZE
- 1)
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
);
279 buf
[len
] = buf
[len
+ 1] = '\0';
281 if (got
> buf
&& from_fstab_line (m
, got
))
288 add_usr_mnts (struct mnt
*m
)
290 /* Set default /usr/bin and /usr/lib */
293 m
->posix
= "/usr/bin";
294 m
->native
= root_here
->native
+ "\\bin";
299 m
->posix
= "/usr/lib";
300 m
->native
= root_here
->native
+ "\\lib";
305 read_mounts (const std::string val
)
307 DWORD posix_path_size
;
308 struct mnt
*m
= mount_table
;
312 for (mnt
* m1
= mount_table
; m1
->posix
.size (); m1
++)
317 got_usr_bin
= got_usr_lib
= false;
319 root_scope
= (nt_sec
.isRunAsAdmin ())? IDC_ROOT_SYSTEM
: IDC_ROOT_USER
;
323 /* Cygwin rootdir always < MAX_PATH. */
324 char rootdir
[MAX_PATH
+ 1];
326 if (GetFullPathName (val
.c_str (), MAX_PATH
+ 1, rootdir
, NULL
))
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
)
347 /* Cygwin rootdir always < MAX_PATH. */
348 char aBuffer
[MAX_PATH
+ 1];
349 posix_path_size
= MAX_PATH
;
351 (key
, "rootdir", 0, &type
, (BYTE
*) aBuffer
,
352 &posix_path_size
) == ERROR_SUCCESS
)
354 m
->native
= std::string (aBuffer
);
356 root_scope
= isuser
? IDC_ROOT_USER
: IDC_ROOT_SYSTEM
;
358 from_fstab (m
, root_here
->native
);
368 /* Affected path always < MAX_PATH. */
369 char windir
[MAX_PATH
];
370 GetSystemWindowsDirectory (windir
, sizeof (windir
));
372 m
->native
= std::string (windir
) + (is_64bit
? "\\cygwin64" : "\\cygwin");
380 set_root_dir (const std::string val
)
385 static std::string empty
;
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.
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
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]))
415 return SLASH_P (path2
.c_str ()[0])
416 && !SLASH_P (path2
.c_str ()[1]);
418 if (casecompare(path1
, path2
, len1
) != 0)
421 return SLASH_P (path2
.c_str ()[len1
]) || path2
.size () == len1
422 || path1
.c_str ()[len1
- 1] == ':';
426 cygpath (const std::string
& thePath
)
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
))
440 return std::string();
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
);
450 native
= match
->native
+ "/" + thePath
.substr(max_len
, std::string::npos
);