summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-07-11 20:14:00 -0700
committerKaz Kylheku <kaz@kylheku.com>2021-07-26 21:52:24 -0700
commitee6eae5d2bde5dc57a8534bc4b3a07ed176480ce (patch)
treeea781868c0f3c25739beae407b222667cfb4efea
parent18bf3105812dfe4a3b3982838175ec9a60372198 (diff)
downloadcygnal-ee6eae5d2bde5dc57a8534bc4b3a07ed176480ce.tar.gz
cygnal-ee6eae5d2bde5dc57a8534bc4b3a07ed176480ce.tar.bz2
cygnal-ee6eae5d2bde5dc57a8534bc4b3a07ed176480ce.zip
Implement drive-relative paths and per-drive working dir.
* winsup/cygwin/path.cc (normalize_win32_path): When a drive-relative path is normalized, look up the remembered working directory of that drive in the environment. A drive-relative path is, for example, "C:file.txt". Or just "C:", with no component. If there is no path for the drive in the environment, then the root directory is used, and the "C:" part thus becomes "C:\", causing the path to refer to "C:\file.txt". Otherwise the path is inserted, with a backslash, like "C:\users\bob\file.txt". The Windows convention for storing these per-drive paths in the environment is to use environment variables based on drive letters. For instance the path for the C drive is stored in the environment variable "!C:" (bang, letter, colon). The path includes the C:\ prefix. (cwdstuff::override_win32_cwd): Add the behavior of associating the current working directory with its drive (if it is a current working directory based on a drive). For instance if the overriding cwd is "C:\Users", then the "C:\Users" path is stored into the "!C:" environment variable.
-rw-r--r--winsup/cygwin/path.cc41
1 files changed, 40 insertions, 1 deletions
diff --git a/winsup/cygwin/path.cc b/winsup/cygwin/path.cc
index edc17152b..807a7c6ef 100644
--- a/winsup/cygwin/path.cc
+++ b/winsup/cygwin/path.cc
@@ -1481,7 +1481,32 @@ normalize_win32_path (const char *src, char *dst, char *&tail)
if (isdrive (src))
{
/* Always convert drive letter to uppercase for case sensitivity. */
- *tail++ = cyg_toupper (*src++);
+
+ if (isdirsep (src[2]))
+ /* Always convert drive letter to uppercase for case sensitivity. */
+ *tail++ = cyg_toupper (*src++);
+ else
+ {
+ /* Drive-relative path: get drive path from environment. */
+ char env[] = { '!', cyg_toupper (*src), ':', 0 };
+ const char *drvpath = getenv(env);
+
+ if (drvpath)
+ {
+ size_t len = strlcpy(tail, drvpath, NT_MAX_PATH);
+
+ if (len >= NT_MAX_PATH - 1)
+ return ENAMETOOLONG;
+
+ tail += len;
+ *tail++ = '\\';
+ src += 2;
+ }
+ else
+ {
+ *tail++ = cyg_toupper (*src++);
+ }
+ }
*tail++ = *src++;
dst = tail;
/* If backslash is missing in src, add one. */
@@ -4802,6 +4827,20 @@ cwdstuff::override_win32_cwd (bool init, ULONG old_dismount_count)
from the parent process. We always have to close it here. */
NtClose (h);
}
+
+ /* Simulate the SetCurrentDirectory effect of associating a drive
+ with its own current directory. This behavior dating all the way
+ back to MS-DOS is done in Windows with special environment
+ variables. */
+ if (iswdrive (win32.Buffer)) {
+ tmp_pathbuf tp;
+ char env[] = { '!', (char) win32.Buffer[0], ':', 0 };
+ char *cwdcopy = tp.c_get ();
+
+ sys_wcstombs (cwdcopy, NT_MAX_PATH, win32.Buffer,
+ win32.Length / sizeof (WCHAR));
+ setenv(env, cwdcopy, 1);
+ }
}
/* Initialize cygcwd 'muto' for serializing access to cwd info. */