Repository: borgbackup/borg

Issue:
Borg demands a BORG_CONFIG_DIR even if SECURITY and KEYS dirs are both set
On Borg 1.1.16, the following used to work:

```
$ mkdir security cache
$ BORG_SECURITY_DIR=security BORG_CACHE_DIR=cache BORG_CONFIG_DIR=/dev/null borg init -e none borg
```

But on Borg 1.1.17 it doesn't:

```
Error: File exists
Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/borg/helpers.py", line 528, in ensure_dir
    os.makedirs(path, mode=mode, exist_ok=True)
  File "/usr/lib/python3.9/os.py", line 225, in makedirs
    mkdir(name, mode)
FileExistsError: [Errno 17] File exists: '/dev/null'

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/lib/python3/dist-packages/borg/archiver.py", line 4703, in main
    exit_code = archiver.run(args)
  File "/usr/lib/python3/dist-packages/borg/archiver.py", line 4635, in run
    return set_ec(func(args))
  File "/usr/lib/python3/dist-packages/borg/archiver.py", line 177, in wrapper
    return method(self, args, repository=repository, **kwargs)
  File "/usr/lib/python3/dist-packages/borg/archiver.py", line 301, in do_init
    with Cache(repository, key, manifest, warn_if_unencrypted=False):
  File "/usr/lib/python3/dist-packages/borg/cache.py", line 387, in __new__
    return local()
  File "/usr/lib/python3/dist-packages/borg/cache.py", line 379, in local
    return LocalCache(repository=repository, key=key, manifest=manifest, path=path, sync=sync,
  File "/usr/lib/python3/dist-packages/borg/cache.py", line 456, in __init__
    self.security_manager = SecurityManager(repository)
  File "/usr/lib/python3/dist-packages/borg/cache.py", line 64, in __init__
    self.dir = get_security_dir(repository.id_str)
  File "/usr/lib/python3/dist-packages/borg/helpers.py", line 564, in get_security_dir
    security_dir = os.environ.get('BORG_SECURITY_DIR', os.path.join(get_config_dir(), 'security'))
  File "/usr/lib/python3/dist-packages/borg/helpers.py", line 604, in get_config_dir
    ensure_dir(config_dir)
  File "/usr/lib/python3/dist-packages/borg/helpers.py", line 531, in ensure_dir
    raise Error(e.args[1])
borg.helpers.Error: Error: File exists
```

I suspect the culprit is aa7a76cf3597be951508a87273e90df8720221c3.

Borg should not demand a valid `BORG_CONFIG_DIR` when it doesn't actually need one (in this case, because `BORG_SECURITY_DIR` and `BORG_CACHE_DIR` have both been set). Perhaps the `get_config_dir()` call should occur after the `os.environ.get()` check.


Discussion:
these _DIR env vars need to point to a directory, `/dev/null` is a file, not a directory.

also, although the security dir is inside the config dir, it is not necessarily (now or forever) the only directory in there.

that said, I'll have a look at the code now to check whether something can be improved...

Resolving patch:
diff --git a/src/borg/helpers/fs.py b/src/borg/helpers/fs.py
--- a/src/borg/helpers/fs.py
+++ b/src/borg/helpers/fs.py
@@ -61,15 +61,20 @@ def get_base_dir():
 
 def get_keys_dir():
     """Determine where to repository keys and cache"""
-
-    keys_dir = os.environ.get('BORG_KEYS_DIR', os.path.join(get_config_dir(), 'keys'))
+    keys_dir = os.environ.get('BORG_KEYS_DIR')
+    if keys_dir is None:
+        # note: do not just give this as default to the environment.get(), see issue #5979.
+        keys_dir = os.path.join(get_config_dir(), 'keys')
     ensure_dir(keys_dir)
     return keys_dir
 
 
 def get_security_dir(repository_id=None):
     """Determine where to store local security information."""
-    security_dir = os.environ.get('BORG_SECURITY_DIR', os.path.join(get_config_dir(), 'security'))
+    security_dir = os.environ.get('BORG_SECURITY_DIR')
+    if security_dir is None:
+        # note: do not just give this as default to the environment.get(), see issue #5979.
+        security_dir = os.path.join(get_config_dir(), 'security')
     if repository_id:
         security_dir = os.path.join(security_dir, repository_id)
     ensure_dir(security_dir)


Test patch: