From b3806f4533fda4343ee346b23926864f4b2f9e35 Mon Sep 17 00:00:00 2001 From: Luflosi Date: Tue, 3 Dec 2019 11:46:07 +0100 Subject: [PATCH] Fix OSError when failing to create config directory on read-only file system When calling the completion code, kitty tries to access the config directory and create it if it does not exist. If kitty has no permission to create it, a temporary directory will be created instead. This will fail on a read-only file system because that raises an `OSError` and not a `PermissionError`. In practice this happens when building kitty on macOS Catalina using Nix because `HOME` is set to `/homeless-shelter` for purity and `/` is a read-only filesystem. --- kitty/constants.py | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/kitty/constants.py b/kitty/constants.py index 73b0ba468..96578e874 100644 --- a/kitty/constants.py +++ b/kitty/constants.py @@ -5,6 +5,7 @@ import os import pwd import sys +import errno from collections import namedtuple from contextlib import suppress @@ -57,13 +58,7 @@ def _get_config_dir(): if os.access(q, os.W_OK) and os.path.exists(os.path.join(q, 'kitty.conf')): return q - candidate = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME') or '~/.config')) - ans = os.path.join(candidate, appname) - try: - os.makedirs(ans, exist_ok=True) - except FileExistsError: - raise SystemExit('A file {} already exists. It must be a directory, not a file.'.format(ans)) - except PermissionError: + def make_tmp_conf(): import tempfile import atexit ans = tempfile.mkdtemp(prefix='kitty-conf-') @@ -73,6 +68,19 @@ def _get_config_dir(): with suppress(Exception): shutil.rmtree(ans) atexit.register(cleanup) + + candidate = os.path.abspath(os.path.expanduser(os.environ.get('XDG_CONFIG_HOME') or '~/.config')) + ans = os.path.join(candidate, appname) + try: + os.makedirs(ans, exist_ok=True) + except FileExistsError: + raise SystemExit('A file {} already exists. It must be a directory, not a file.'.format(ans)) + except PermissionError: + make_tmp_conf() + except OSError as err: + if err.errno != errno.EROFS: # Error other than read-only file system + raise + make_tmp_conf() return ans