aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/os/env.c53
-rw-r--r--test/functional/eval/environ_spec.lua61
2 files changed, 107 insertions, 7 deletions
diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c
index 879266e3d4..008f5ef63b 100644
--- a/src/nvim/os/env.c
+++ b/src/nvim/os/env.c
@@ -394,13 +394,21 @@ void os_get_hostname(char *hostname, size_t size)
}
/// To get the "real" home directory:
-/// - get value of $HOME
+/// 1. get value of $HOME
+/// 2. if $HOME is not set, try the following
+/// For Windows:
+/// 1. assemble homedir using HOMEDRIVE and HOMEPATH
+/// 2. try os_homedir()
+/// 3. resolve a direct reference to another system variable
+/// 4. guess C drive
/// For Unix:
-/// - go to that directory
-/// - do os_dirname() to get the real name of that directory.
-/// This also works with mounts and links.
-/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 1. try os_homedir()
+/// 2. go to that directory
+/// This also works with mounts and links.
+/// Don't do this for Windows, it will change the "current dir" for a drive.
+/// 3. fall back to current working directory as a last resort
static char *homedir = NULL;
+static char *os_homedir(void);
void init_homedir(void)
{
@@ -430,7 +438,7 @@ void init_homedir(void)
}
}
if (var == NULL) {
- var = os_getenv("USERPROFILE");
+ var = os_homedir();
}
// Weird but true: $HOME may contain an indirect reference to another
@@ -440,6 +448,7 @@ void init_homedir(void)
const char *p = strchr(var + 1, '%');
if (p != NULL) {
vim_snprintf(os_buf, (size_t)(p - var), "%s", var + 1);
+ var = NULL;
const char *exp = os_getenv(os_buf);
if (exp != NULL && *exp != NUL
&& STRLEN(exp) + STRLEN(p) < MAXPATHL) {
@@ -458,8 +467,12 @@ void init_homedir(void)
}
#endif
- if (var != NULL) {
#ifdef UNIX
+ if (var == NULL) {
+ var = os_homedir();
+ }
+
+ if (var != NULL) {
// Change to the directory and get the actual path. This resolves
// links. Don't do it when we can't return.
if (os_dirname((char_u *)os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) {
@@ -470,11 +483,37 @@ void init_homedir(void)
EMSG(_(e_prev_dir));
}
}
+ }
+
+ // Fall back to current working directory if home is not found
+ if ((var == NULL || *var == NUL)
+ && os_dirname((char_u *)os_buf, sizeof(os_buf)) == OK) {
+ var = os_buf;
+ }
#endif
+ if (var != NULL) {
homedir = xstrdup(var);
}
}
+static char homedir_buf[MAXPATHL];
+
+static char *os_homedir(void)
+{
+ homedir_buf[0] = NUL;
+ size_t homedir_size = MAXPATHL;
+ uv_mutex_lock(&mutex);
+ // http://docs.libuv.org/en/v1.x/misc.html#c.uv_os_homedir
+ int ret_value = uv_os_homedir(homedir_buf, &homedir_size);
+ uv_mutex_unlock(&mutex);
+ if (ret_value == 0 && homedir_size < MAXPATHL) {
+ return homedir_buf;
+ }
+ ELOG("uv_os_homedir() failed %d: %s", ret_value, os_strerror(ret_value));
+ homedir_buf[0] = NUL;
+ return NULL;
+}
+
#if defined(EXITFREE)
void free_homedir(void)
diff --git a/test/functional/eval/environ_spec.lua b/test/functional/eval/environ_spec.lua
index 54d2dc960b..9e19568249 100644
--- a/test/functional/eval/environ_spec.lua
+++ b/test/functional/eval/environ_spec.lua
@@ -3,6 +3,11 @@ local clear = helpers.clear
local eq = helpers.eq
local environ = helpers.funcs.environ
local exists = helpers.funcs.exists
+local system = helpers.funcs.system
+local nvim_prog = helpers.nvim_prog
+local command = helpers.command
+local eval = helpers.eval
+local setenv = helpers.funcs.setenv
describe('environment variables', function()
it('environ() handles empty env variable', function()
@@ -17,3 +22,59 @@ describe('environment variables', function()
eq(0, exists('$DOES_NOT_EXIST'))
end)
end)
+
+describe('empty $HOME', function()
+ local original_home = os.getenv('HOME')
+
+ -- recover $HOME after each test
+ after_each(function()
+ if original_home ~= nil then
+ setenv('HOME', original_home)
+ end
+ os.remove('test_empty_home')
+ os.remove('./~')
+ end)
+
+ local function tilde_in_cwd()
+ -- get files in cwd
+ command("let test_empty_home_cwd_files = split(globpath('.', '*'), '\n')")
+ -- get the index of the file named '~'
+ command('let test_empty_home_tilde_index = index(test_empty_home_cwd_files, "./~")')
+ return eval('test_empty_home_tilde_index') ~= -1
+ end
+
+ local function write_and_test_tilde()
+ system({nvim_prog, '-u', 'NONE', '-i', 'NONE', '--headless',
+ '-c', 'write test_empty_home', '+q'})
+ eq(false, tilde_in_cwd())
+ end
+
+ it("'~' folder not created in cwd if $HOME and related env not defined", function()
+ command("unlet $HOME")
+ write_and_test_tilde()
+
+ command("let $HOMEDRIVE='C:'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+
+ command("unlet $HOMEDRIVE")
+ write_and_test_tilde()
+
+ command("unlet $USERPROFILE")
+ write_and_test_tilde()
+
+ command("let $HOME='%USERPROFILE%'")
+ command("let $USERPROFILE='C:\\'")
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with invalid $HOME", function()
+ setenv('HOME', '/path/does/not/exist')
+ write_and_test_tilde()
+ end)
+
+ it("'~' folder not created in cwd if writing a file with $HOME=''", function()
+ command("let $HOME=''")
+ write_and_test_tilde()
+ end)
+end)