Repository: borgbackup/borg

Issue:
Borg prints out "Repository XXX does not exist" if the read/write permissions are not granted
## Have you checked borgbackup docs, FAQ, and open Github issues?

Yes

## Is this a BUG / ISSUE report or a QUESTION?

BUG / ISSUE

## System information. For client/server mode post info for both machines.
Linux x64

#### Your borg version (borg -V).
1.1.9

#### Operating system (distribution) and version.
Ubuntu 18.04LTS

#### Hardware / network configuration, and filesystems used.
Ext4 / Cryptsetup

#### How much data is handled by borg?
8TB

#### Full borg commandline that lead to the problem (leave away excludes and passwords)
All borg commands

## Describe the problem you're observing.
I attached my harddrive including the Borg repository to a different server with more perfomance. Apparently the folder settings were set incorrectly, therefore Borg was unable to create a new archive. It always gave the error "Repository XXXXX does not exist.", it would be a lot better however if it put out some thing that tells the user that the permissions were denied. I tried finding out why it thinks that the repository doesn't exist for almost an hour, until I saw that the permissions were set incorrectly.


#### Can you reproduce the problem? If so, describe how. If not, describe troubleshooting steps 

Chown the folder with the repository to a different user, so borg cannot access it.

#### Include any warning/errors/backtraces from the system logs
Repository XXXXX does not exist.


Discussion:
I can't reproduce:

```
$ ls -ld noperms
drwxrwx--- 2 root root 4096 Jul 28 14:59 noperms/

$ id
uid=1000(user) gid=1000(user) groups=1000(user)

$ borg -V
borg 1.1.9

$ borg init -e none noperms/repo
Local Exception
Traceback (most recent call last):
  File "/home/user/w/borg/src/borg/archiver.py", line 4455, in main
    exit_code = archiver.run(args)
  File "/home/user/w/borg/src/borg/archiver.py", line 4387, in run
    return set_ec(func(args))
  File "/home/user/w/borg/src/borg/archiver.py", line 139, in wrapper
    with repository:
  File "/home/user/w/borg/src/borg/repository.py", line 187, in __enter__
    self.create(self.path)
  File "/home/user/w/borg/src/borg/repository.py", line 262, in create
    os.mkdir(path)
PermissionError: [Errno 13] Permission denied: '/home/user/w/borg/noperms/repo'

Platform: Linux development 4.14.119-2.pvops.qubes.x86_64 #1 SMP Wed May 15 06:43:11 UTC 2019 x86_64
Linux: debian 9.6 
Borg: 1.1.9  Python: CPython 3.5.6
PID: 2924  CWD: /home/user/w/borg
sys.argv: ['/home/user/w/borg-env/bin/borg', 'init', '-e', 'none', 'noperms/repo']
SSH_ORIGINAL_COMMAND: None
```

It clearly says "permission denied".
No I was writing in regards to creating a new archive, not repo.

```
borg init -e none noperm/repo
sudo chown root:root noperm
sudo chmod 700 noperm
borg create noperm/repo::Test /tmp

>Repository /home/force/noperm/repo does not exist.
```

This happened, as I used a drive from a different server with the repo, where the UID for the backup user was different however
Confirmed.

The problem here is that it uses `os.path.isdir(path)` and that just returns False if it has no permissions, thus borg told that the repo does not exist.

I will change this to:
- use `st = os.stat(path)` and catch `FileNotFoundError` -> repo does not exist.
- do not catch other exceptions, so it will just blow up on permission and other errors (like lots of other places).
- check for path being a directory with `stat.S_ISDIR(st.st_mode)`, if not -> invalid repository.

Resolving patch:
diff --git a/src/borg/repository.py b/src/borg/repository.py
--- a/src/borg/repository.py
+++ b/src/borg/repository.py
@@ -2,6 +2,7 @@
 import mmap
 import os
 import shutil
+import stat
 import struct
 import time
 from binascii import hexlify, unhexlify
@@ -233,11 +234,17 @@ def check_can_create_repository(self, path):
             repository, user's can only use the quota'd repository, when their --restrict-to-path points
             at the user's repository.
         """
-        if os.path.exists(path):
+        try:
+            st = os.stat(path)
+        except FileNotFoundError:
+            pass  # nothing there!
+        else:
+            # there is something already there!
             if self.is_repository(path):
                 raise self.AlreadyExists(path)
-            if not os.path.isdir(path) or os.listdir(path):
+            if not stat.S_ISDIR(st.st_mode) or os.listdir(path):
                 raise self.PathAlreadyExists(path)
+            # an empty directory is acceptable for us.
 
         while True:
             # Check all parent directories for Borg's repository README
@@ -386,8 +393,12 @@ def migrate_lock(self, old_id, new_id):
 
     def open(self, path, exclusive, lock_wait=None, lock=True):
         self.path = path
-        if not os.path.isdir(path):
+        try:
+            st = os.stat(path)
+        except FileNotFoundError:
             raise self.DoesNotExist(path)
+        if not stat.S_ISDIR(st.st_mode):
+            raise self.InvalidRepository(path)
         if lock:
             self.lock = Lock(os.path.join(path, 'lock'), exclusive, timeout=lock_wait, kill_stale_locks=hostname_is_unique()).acquire()
         else:


Test patch: