aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRory Nesbitt <ranesbitt@live.co.uk>2023-09-27 18:09:55 +0100
committerGitHub <noreply@github.com>2023-09-27 10:09:55 -0700
commita66b0fdfaa35715c832b98b8941cc5673505e0c2 (patch)
treec61ba5de9fcbcccb9209657cbe3013a0881a385d
parentbfdec5b0e71991ebc0a8ad7c12d39f7a9cc56f07 (diff)
downloadrneovim-a66b0fdfaa35715c832b98b8941cc5673505e0c2.tar.gz
rneovim-a66b0fdfaa35715c832b98b8941cc5673505e0c2.tar.bz2
rneovim-a66b0fdfaa35715c832b98b8941cc5673505e0c2.zip
feat: NVIM_APPNAME supports relative paths #25233
Problem: NVIM_APPNAME does not allow path separators in the name, so relative paths can't be used: NVIM_APPNAME="neovim-configs/first-config" nvim NVIM_APPNAME="neovim-configs/second-config" nvim Solution: Let NVIM_APPNAME be a relative path. Absolute paths are not supported. fix #23056 fix #24966
-rw-r--r--runtime/doc/news.txt2
-rw-r--r--runtime/doc/starting.txt15
-rw-r--r--src/nvim/fileio.c7
-rw-r--r--src/nvim/main.c2
-rw-r--r--src/nvim/os/stdpaths.c20
-rw-r--r--test/functional/core/fileio_spec.lua10
-rw-r--r--test/functional/options/defaults_spec.lua25
7 files changed, 60 insertions, 21 deletions
diff --git a/runtime/doc/news.txt b/runtime/doc/news.txt
index 05a2d35f9a..ff0ccfb08f 100644
--- a/runtime/doc/news.txt
+++ b/runtime/doc/news.txt
@@ -169,6 +169,8 @@ The following new APIs and features were added.
• |vim.lsp.util.locations_to_items()| sets the `user_data` of each item to the
original LSP `Location` or `LocationLink`.
+• |$NVIM_APPNAME| can be set to a relative path instead of only a name.
+
==============================================================================
CHANGED FEATURES *news-changed*
diff --git a/runtime/doc/starting.txt b/runtime/doc/starting.txt
index 17d5b4668d..d38712b067 100644
--- a/runtime/doc/starting.txt
+++ b/runtime/doc/starting.txt
@@ -1366,6 +1366,9 @@ The $XDG_CONFIG_HOME, $XDG_DATA_HOME, $XDG_RUNTIME_DIR, $XDG_STATE_HOME,
$XDG_CACHE_HOME, $XDG_CONFIG_DIRS and $XDG_DATA_DIRS environment variables
are used if defined, else default values (listed below) are used.
+Throughout the help pages these defaults are used as placeholders, e.g.
+"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
+
CONFIG DIRECTORY (DEFAULT) ~
*$XDG_CONFIG_HOME* Nvim: stdpath("config")
Unix: ~/.config ~/.config/nvim
@@ -1392,10 +1395,12 @@ CACHE DIRECTORY (DEFAULT) ~
Windows: ~/AppData/Local/Temp ~/AppData/Local/Temp/nvim-data
LOG FILE (DEFAULT) ~
- `$NVIM_LOG_FILE` Nvim: stdpath("log")
+ `$NVIM_LOG_FILE` Nvim: stdpath("log")/log
Unix: ~/.local/state/nvim ~/.local/state/nvim/log
Windows: ~/AppData/Local/nvim-data ~/AppData/Local/nvim-data/log
+Note that stdpath("log") is currently an alias for stdpath("state").
+
ADDITIONAL CONFIGS DIRECTORY (DEFAULT) ~
*$XDG_CONFIG_DIRS* Nvim: stdpath("config_dirs")
Unix: /etc/xdg/ /etc/xdg/nvim
@@ -1407,18 +1412,14 @@ ADDITIONAL DATA DIRECTORY (DEFAULT) ~
/usr/share /usr/share/nvim
Windows: Not applicable Not applicable
-Note: Throughout the help pages these defaults are used as placeholders, e.g.
-"~/.config" is understood to mean "$XDG_CONFIG_HOME or ~/.config".
-
-Note: The log file directory is controlled by `$XDG_STATE_HOME`.
-
NVIM_APPNAME *$NVIM_APPNAME*
The standard directories can be further configured by the `$NVIM_APPNAME`
environment variable. This variable controls the sub-directory that Nvim will
read from (and auto-create) in each of the base directories. For example,
setting `$NVIM_APPNAME` to "foo" before starting will cause Nvim to look for
configuration files in `$XDG_CONFIG_HOME/foo` instead of
-`$XDG_CONFIG_HOME/nvim`.
+`$XDG_CONFIG_HOME/nvim`. `$NVIM_APPNAME` must be a name, such as "foo", or a
+relative path, such as "foo/bar".
One use-case for $NVIM_APPNAME is to "isolate" Nvim applications.
Alternatively, for true isolation, on Linux you can use cgroups namespaces: >
diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c
index 7ff3e0ec6e..7609eb12b4 100644
--- a/src/nvim/fileio.c
+++ b/src/nvim/fileio.c
@@ -3279,12 +3279,18 @@ static void vim_mktempdir(void)
char tmp[TEMP_FILE_PATH_MAXLEN];
char path[TEMP_FILE_PATH_MAXLEN];
char user[40] = { 0 };
+ char appname[40] = { 0 };
(void)os_get_username(user, sizeof(user));
// Usernames may contain slashes! #19240
memchrsub(user, '/', '_', sizeof(user));
memchrsub(user, '\\', '_', sizeof(user));
+ // Appname may be a relative path, replace slashes to make it name-like.
+ xstrlcpy(appname, get_appname(), sizeof(appname));
+ memchrsub(appname, '/', '%', sizeof(appname));
+ memchrsub(appname, '\\', '%', sizeof(appname));
+
// Make sure the umask doesn't remove the executable bit.
// "repl" has been reported to use "0177".
mode_t umask_save = umask(0077);
@@ -3298,7 +3304,6 @@ static void vim_mktempdir(void)
// "/tmp/" exists, now try to create "/tmp/nvim.<user>/".
add_pathsep(tmp);
- const char *appname = get_appname();
xstrlcat(tmp, appname, sizeof(tmp));
xstrlcat(tmp, ".", sizeof(tmp));
xstrlcat(tmp, user, sizeof(tmp));
diff --git a/src/nvim/main.c b/src/nvim/main.c
index 4b3244de12..720387cb17 100644
--- a/src/nvim/main.c
+++ b/src/nvim/main.c
@@ -251,7 +251,7 @@ int main(int argc, char **argv)
argv0 = argv[0];
if (!appname_is_valid()) {
- os_errmsg("$NVIM_APPNAME is not a valid file name.\n");
+ os_errmsg("$NVIM_APPNAME must be a name or relative path.\n");
exit(1);
}
diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c
index 53ddda22fa..b129eb445a 100644
--- a/src/nvim/os/stdpaths.c
+++ b/src/nvim/os/stdpaths.c
@@ -69,15 +69,23 @@ const char *get_appname(void)
return env_val;
}
-/// Ensure that APPNAME is valid. In particular, it cannot contain directory separators.
+/// Ensure that APPNAME is valid. Must be a name or relative path.
bool appname_is_valid(void)
{
const char *appname = get_appname();
- const size_t appname_len = strlen(appname);
- for (size_t i = 0; i < appname_len; i++) {
- if (appname[i] == PATHSEP) {
- return false;
- }
+ if (path_is_absolute(appname)
+ // TODO(justinmk): on Windows, path_is_absolute says "/" is NOT absolute. Should it?
+ || strequal(appname, "/")
+ || strequal(appname, "\\")
+ || strequal(appname, ".")
+ || strequal(appname, "..")
+#ifdef BACKSLASH_IN_FILENAME
+ || strstr(appname, "\\..") != NULL
+ || strstr(appname, "..\\") != NULL
+#endif
+ || strstr(appname, "/..") != NULL
+ || strstr(appname, "../") != NULL) {
+ return false;
}
return true;
}
diff --git a/test/functional/core/fileio_spec.lua b/test/functional/core/fileio_spec.lua
index 8de78234ce..f2b360f0d8 100644
--- a/test/functional/core/fileio_spec.lua
+++ b/test/functional/core/fileio_spec.lua
@@ -377,4 +377,14 @@ describe('tmpdir', function()
rm_tmpdir()
eq('E5431: tempdir disappeared (3 times)', meths.get_vvar('errmsg'))
end)
+
+ it('$NVIM_APPNAME relative path', function()
+ clear({ env={
+ NVIM_APPNAME='a/b',
+ NVIM_LOG_FILE=testlog,
+ TMPDIR=os_tmpdir,
+ } })
+ matches([=[.*[/\\]a%%b%.[^/\\]+]=], funcs.tempname())
+ end)
+
end)
diff --git a/test/functional/options/defaults_spec.lua b/test/functional/options/defaults_spec.lua
index 9b531bcafc..7858b626de 100644
--- a/test/functional/options/defaults_spec.lua
+++ b/test/functional/options/defaults_spec.lua
@@ -598,8 +598,7 @@ describe('stdpath()', function()
end)
it('reacts to $NVIM_APPNAME', function()
- local appname = "NVIM_APPNAME_TEST____________________________________" ..
- "______________________________________________________________________"
+ local appname = 'NVIM_APPNAME_TEST' .. ('_'):rep(106)
clear({env={ NVIM_APPNAME=appname }})
eq(appname, funcs.fnamemodify(funcs.stdpath('config'), ':t'))
eq(appname, funcs.fnamemodify(funcs.stdpath('cache'), ':t'))
@@ -616,10 +615,24 @@ describe('stdpath()', function()
-- Check that Nvim rejects invalid APPNAMEs
-- Call jobstart() and jobwait() in the same RPC request to reduce flakiness.
- eq(1, exec_lua([[
- local child = vim.fn.jobstart({ vim.v.progpath }, { env = { NVIM_APPNAME = 'a/b\\c' } })
- return vim.fn.jobwait({ child }, 3000)[1]
- ]]))
+ local function test_appname(testAppname, expected_exitcode)
+ local lua_code = string.format([[
+ local child = vim.fn.jobstart({ vim.v.progpath, '--clean', '--headless', '+qall!' }, { env = { NVIM_APPNAME = %q } })
+ return vim.fn.jobwait({ child }, %d)[1]
+ ]], alter_slashes(testAppname), 3000)
+ eq(expected_exitcode, exec_lua(lua_code))
+ end
+ -- Invalid appnames:
+ test_appname('a/../b', 1)
+ test_appname('../a', 1)
+ test_appname('a/..', 1)
+ test_appname('..', 1)
+ test_appname('.', 1)
+ test_appname('/', 1)
+ test_appname(is_os('win') and 'C:/a/b' or '/a/b', 1)
+ -- Valid appnames:
+ test_appname('a/b', 0)
+ test_appname('a/b\\c', 0)
end)
describe('returns a String', function()