Repository: iterative/dvc

Issue:
Hardlinks not correctly detected on SMB network share (NTFS?)
Using DVC version 0.80, with repo and cache both on the same network drive.
Windows setup.

I'm testing the `unprotect` command, but I assume other commands relying on the same check will also exhibit strange failures.

```
PS Q:\dvc-test> dvc --version
0.80.0
PS Q:\dvc-test> cat .dvc\config
[cache]
dir = 'Q:\DVC cache (test)'
type = "reflink,symlink,hardlink,copy"
protected = true
PS Q:\dvc-test> dir


    Directory: Q:\dvc-test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       06/01/2020     16:58                .dvc
-a----       06/01/2020     14:57             24 .gitignore
-a----       06/01/2020     14:57            155 big_file.dvc
-ar---       27/12/2019     16:42      134217728 big_file

PS Q:\dvc-test> fsutil.exe hardlink list big_file
Error:  The request is not supported.
```
As you can see, I checked out my files from git at 14:57 today; dvc checkout created a protected link to the original 128Mb file created 10 days ago, rather than a copy (as requested), but Windows can't tell me that it is a link.  Trust me, it is 😉
```
PS Q:\dvc-test> dvc unprotect big_file
PS Q:\dvc-test> dir


    Directory: Q:\dvc-test


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       06/01/2020     16:58                .dvc
-a----       06/01/2020     14:57             24 .gitignore
-a----       06/01/2020     14:57            155 big_file.dvc
-a----       27/12/2019     16:42      134217728 big_file

```
Strange - the `unprotect` operation was very fast, and the creation date of the file is still last year rather than today.
```
PS Q:\dvc-test> echo Hello >> big_file
PS Q:\dvc-test> dvc status
WARNING: corrupted cache file '..\DVC cache (test)\1d\cca63ad430e16fa12716d1a9bb3a6c'.
big_file_3.dvc:
     changed outs:
                                                                                                                       not in cache:       big_file_3
```
Sure enough, modifying `big_file` corrupts the cache, since I was not modifying a copy.

Discussion:
rxxg: Hi @efiop, I just tested this PR on my setup and I think it has discovered a latent bug.
```
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg> mkdir dvc_repo


    Directory: \\network.drive\rxxg


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       21/01/2020     13:47                dvc_repo


(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg> mkdir dvc_cache


    Directory: \\network.drive\rxxg


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
d-----       21/01/2020     13:47                dvc_cache


(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg> cd dvc_repo
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> git init -q
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> dvc init -q
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> echo Hello > file
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> dvc config cache.type reflink,symlink,hardlink,copy
WARNING: You have changed the 'cache.type' option. This doesn't update any existing workspace file links, but it can be done with:
             dvc checkout --relink
Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> dvc config cache.dir \\network.drive\rxxg\dvc_cache
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> cat .\.dvc\config
[cache]
type = "reflink,symlink,hardlink,copy"
dir = \\network.drive\rxxg\dvc_cache
```
So repo and cache are both on the network drive (SMB).  The user cannot create symlinks.  The network protocol doesn't support creating reflinks.  The network drive, although capable of creating hardlinks, cannot tell the difference between an ordinary file and a hardlink (as seen with #3080).  So we expect that only the copy type will be used.
```
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> dvc add file -v
DEBUG: Trying to spawn '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: Spawned '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
ERROR: unexpected error - unable to open database file
------------------------------------------------------------
Traceback (most recent call last):
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\main.py", line 47, in main
    ret = cmd.run()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\add.py", line 23, in run
    fname=self.args.file,
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\repo\__init__.py", line 31, in wrapper
    with repo.lock, repo.state:
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\state.py", line 133, in __enter__
    self.load()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\state.py", line 225, in load
    self.database = _connect_sqlite(self.state_file, {"nolock": 1})
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\state.py", line 489, in _connect_sqlite
    return sqlite3.connect(uri, uri=True)
sqlite3.OperationalError: unable to open database file
------------------------------------------------------------


Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
```
First problem:  DVC (actually sqlite3) doesn't like having its local config on a network drive.  Let's try a workaround to make it less obvious and try again.
```
(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> net use x: \\network.drive\rxxg
The command completed successfully.

(dvc-3080) PS Microsoft.PowerShell.Core\FileSystem::\\network.drive\rxxg\dvc_repo> x:
(dvc-3080) PS X:\dvc_repo> dvc add file -v
DEBUG: Trying to spawn '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: Spawned '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: CREATE TABLE IF NOT EXISTS state (inode INTEGER PRIMARY KEY, mtime TEXT NOT NULL, size TEXT NOT NULL, md5 TEXT NOT NULL, timestamp TEXT NOT NULL)
DEBUG: CREATE TABLE IF NOT EXISTS state_info (count INTEGER)
DEBUG: CREATE TABLE IF NOT EXISTS link_state (path TEXT PRIMARY KEY, inode INTEGER NOT NULL, mtime TEXT NOT NULL)
DEBUG: INSERT OR IGNORE INTO state_info (count) SELECT 0 WHERE NOT EXISTS (SELECT * FROM state_info)
DEBUG: PRAGMA user_version = 3;
DEBUG: Adding 'file' to '.gitignore'.
DEBUG: Path file inode 849120961163171990
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: Path file inode 849120961163171990
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: INSERT INTO state(inode, mtime, size, md5, timestamp) VALUES (?, ?, ?, ?, ?)
DEBUG: {'file': 'modified'}
DEBUG: Path file inode 849120961163171990
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579610897368964864', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579611241895180288')]
DEBUG: UPDATE state SET timestamp = ? WHERE inode = ?
DEBUG: Computed stage 'file.dvc' md5: 'a404616fc083f4e9e5ebfc7dd725faf0'
DEBUG: Saving 'file' to '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc'.
DEBUG: cache '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc' expected 'de7511b07cd72b25dc78aa472ee21cbc' actual 'None'
DEBUG: Cache type 'reflink' is not supported: reflink is not supported
DEBUG: Cache type 'symlink' is not supported: failed to symlink
DEBUG: Cache type 'hardlink' is not supported: hardlink validation failed
DEBUG: Cache type 'copy' is not supported: Link 'file' already exists!
100% Add|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|1.00/1.00 [00:00<00:00,  1.06file/s]
DEBUG: SELECT count from state_info WHERE rowid=?
DEBUG: fetched: [(0,)]
DEBUG: UPDATE state_info SET count = ? WHERE rowid = ?
ERROR: no possible cache types left to try out.
------------------------------------------------------------
Traceback (most recent call last):
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\add.py", line 23, in run
    fname=self.args.file,
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\repo\__init__.py", line 32, in wrapper
    ret = f(repo, *args, **kwargs)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\repo\scm_context.py", line 4, in run
    result = method(repo, *args, **kw)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\repo\add.py", line 53, in add
    stage.commit()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\funcy\decorators.py", line 39, in wrapper
    return deco(call, *dargs, **dkwargs)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\stage.py", line 161, in rwlocked
    return call()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\funcy\decorators.py", line 60, in __call__
    return self._func(*self._args, **self._kwargs)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\stage.py", line 824, in commit
    out.commit()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\output\base.py", line 246, in commit
    self.cache.save(self.path_info, self.info)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 507, in save
    self._save(path_info, checksum)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 515, in _save
    self._save_file(path_info, checksum)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 417, in _save_file
    self.link(cache_info, path_info)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 369, in link
    self._link(from_info, to_info, self.cache_types)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 376, in _link
    self._try_links(from_info, to_info, link_types)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\slow_link_detection.py", line 39, in wrapper
    return f(remote, *args, **kwargs)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\remote\base.py", line 392, in _try_links
    raise DvcException("no possible cache types left to try out.")
dvc.exceptions.DvcException: no possible cache types left to try out.
------------------------------------------------------------


Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
```
Note two things:
1) We don't get any complaints about the cache being on a network drive, just the repo.
2) The cache file is created, but the operation still doesn't succeed.
```
(dvc-3080) PS X:\dvc_repo> dvc version -v
DVC version: 0.80.0+6fce86
Python version: 3.7.1
Platform: Windows-10-10.0.16299-SP0
Binary: False
Package: None
Cache: reflink - False, hardlink - False, symlink - False
```
Note that I can workaround the issue by setting the cache type to be `copy` directly.  So something still isn't detecting that links aren't supported.
```
(dvc-3080) PS X:\dvc_repo> rmdir ..\dvc_cache\

Confirm
The item at X:\dvc_cache\ has children and the Recurse parameter was not specified. If you continue, all children will be removed with the item. Are you sure you want to
continue?
[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "Y"):
(dvc-3080) PS X:\dvc_repo> dvc config cache.type copy
WARNING: You have changed the 'cache.type' option. This doesn't update any existing workspace file links, but it can be done with:
             dvc checkout --relink
(dvc-3080) PS X:\dvc_repo> dvc add file -v
DEBUG: Trying to spawn '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: Spawned '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: PRAGMA user_version;
DEBUG: fetched: [(3,)]
DEBUG: CREATE TABLE IF NOT EXISTS state (inode INTEGER PRIMARY KEY, mtime TEXT NOT NULL, size TEXT NOT NULL, md5 TEXT NOT NULL, timestamp TEXT NOT NULL)
DEBUG: CREATE TABLE IF NOT EXISTS state_info (count INTEGER)
DEBUG: CREATE TABLE IF NOT EXISTS link_state (path TEXT PRIMARY KEY, inode INTEGER NOT NULL, mtime TEXT NOT NULL)
DEBUG: INSERT OR IGNORE INTO state_info (count) SELECT 0 WHERE NOT EXISTS (SELECT * FROM state_info)
DEBUG: PRAGMA user_version = 3;
DEBUG: Adding 'file' to '.gitignore'.
DEBUG: Path file inode 4326578069353857046
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579613151295783168', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579613416460647424')]
DEBUG: UPDATE state SET timestamp = ? WHERE inode = ?
DEBUG: {'file': 'modified'}
DEBUG: Path file inode 4326578069353857046
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579613151295783168', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579613447218944512')]
DEBUG: UPDATE state SET timestamp = ? WHERE inode = ?
DEBUG: Computed stage 'file.dvc' md5: 'a404616fc083f4e9e5ebfc7dd725faf0'
DEBUG: Saving 'file' to '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc'.
DEBUG: cache '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc' expected 'de7511b07cd72b25dc78aa472ee21cbc' actual 'None'
DEBUG: Created 'copy': \\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc -> file
DEBUG: Path file inode 3695209259957233900
DEBUG: REPLACE INTO link_state(path, inode, mtime) VALUES (?, ?, ?)
DEBUG: Path file inode 3695209259957233900
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: INSERT INTO state(inode, mtime, size, md5, timestamp) VALUES (?, ?, ?, ?, ?)
DEBUG: Path \\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc inode 4326578069353857046
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579613151295783168', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579613447238496768')]
DEBUG: UPDATE state SET mtime = ?, size = ?, md5 = ?, timestamp = ? WHERE inode = ?
DEBUG: Saving information to 'file.dvc'.
100% Add|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|1.00/1.00 [00:02<00:00,  2.03s/file]

To track the changes with git, run:

        git add .gitignore file.dvc
DEBUG: SELECT count from state_info WHERE rowid=?
DEBUG: fetched: [(1,)]
DEBUG: UPDATE state_info SET count = ? WHERE rowid = ?
```
rxxg: Or maybe the problem is just that on link validation failure the link needs to be deleted (remember that this FS can create hardlinks but not see them).
efiop: @rxxg Thanks for trying it out! Correct, current patch doesn't delete the link, it was just created as a POC. I'm working on an updated version right now, that will actually delete the hardlink/symlink if it doesn't pass verification. Thanks for the heads up! 🙂 
rxxg: `dvc add` is working fine with the latest version, but there is a crash just after on first call of `dvc version`.  Second call works fine.
```
(dvc-3080) PS Z:\dvc_repo> dvc version -v
DVC version: 0.82.1+dc344f
Python version: 3.7.1
Platform: Windows-10-10.0.16299-SP0
Binary: False
Package: None
Cache: reflink - not supported, hardlink - broken, symlink - not supported
(dvc-3080) PS Z:\dvc_repo> dvc add file
100% Add|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|1.00/1.00 [00:02<00:00,  2.41s/file]

To track the changes with git, run:

        git add file.dvc
(dvc-3080) PS Z:\dvc_repo> dvc version -v
ERROR: unexpected error - [WinError 5] Access is denied: '\\\\network.drive\\rxxg\\dvc_cache\\.f2612e58-173f-4e92-8a04-0a4cc473a916'
------------------------------------------------------------
Traceback (most recent call last):
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\main.py", line 48, in main
    ret = cmd.run()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\version.py", line 46, in run
    "Cache: {}".format(self.get_linktype_support_info(repo))
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\version.py", line 111, in get_linktype_support_info
    os.remove(src)
PermissionError: [WinError 5] Access is denied: '\\\\network.drive\\rxxg\\dvc_cache\\.f2612e58-173f-4e92-8a04-0a4cc473a916'
------------------------------------------------------------


Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
(dvc-3080) PS Z:\dvc_repo> dvc version -v
DVC version: 0.82.1+dc344f
Python version: 3.7.1
Platform: Windows-10-10.0.16299-SP0
Binary: False
Package: None
Cache: reflink - not supported, hardlink - broken, symlink - not supported
```
efiop: @rxxg Oh, thanks for trying it out! Pushed a new version that should handle that more gracefully. Please give it a try 🙂 
rxxg: ```
(dvc-3080) PS \\network.drive\rxxg> dvc add file -v
DEBUG: Trying to spawn '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: Spawned '['c:\\users\\rxxg\\dvc-3080\\scripts\\python.exe', 'C:\\Users\\rxxg\\dvc-3080\\Scripts\\dvc', 'daemon', '-q', 'updater']'
DEBUG: CREATE TABLE IF NOT EXISTS state (inode INTEGER PRIMARY KEY, mtime TEXT NOT NULL, size TEXT NOT NULL, md5 TEXT NOT NULL, timestamp TEXT NOT NULL)
DEBUG: CREATE TABLE IF NOT EXISTS state_info (count INTEGER)
DEBUG: CREATE TABLE IF NOT EXISTS link_state (path TEXT PRIMARY KEY, inode INTEGER NOT NULL, mtime TEXT NOT NULL)
DEBUG: INSERT OR IGNORE INTO state_info (count) SELECT 0 WHERE NOT EXISTS (SELECT * FROM state_info)
DEBUG: PRAGMA user_version = 3;
DEBUG: Adding 'file' to '.gitignore'.
DEBUG: Path file inode 5667741391016463476
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: Path file inode 5667741391016463476
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: INSERT INTO state(inode, mtime, size, md5, timestamp) VALUES (?, ?, ?, ?, ?)
DEBUG: {'file': 'modified'}
DEBUG: Path file inode 5667741391016463476
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579709801785156096', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579709813082017792')]
DEBUG: UPDATE state SET timestamp = ? WHERE inode = ?
DEBUG: Computed stage 'file.dvc' md5: 'a404616fc083f4e9e5ebfc7dd725faf0'
DEBUG: Saving 'file' to '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc'.
DEBUG: cache '\\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc' expected 'de7511b07cd72b25dc78aa472ee21cbc' actual 'None'
DEBUG: Cache type 'reflink' is not supported: reflink is not supported
DEBUG: Cache type 'symlink' is not supported: failed to symlink
DEBUG: Created 'hardlink': \\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc -> file
DEBUG: Removing '\\network.drive\rxxg\file'
DEBUG: Cache type 'hardlink' is not supported: failed to verify hardlink
DEBUG: Created 'copy': \\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc -> file
DEBUG: Path file inode 5666308902420454206
DEBUG: REPLACE INTO link_state(path, inode, mtime) VALUES (?, ?, ?)
DEBUG: Path file inode 5666308902420454206
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: []
DEBUG: INSERT INTO state(inode, mtime, size, md5, timestamp) VALUES (?, ?, ?, ?, ?)
DEBUG: Path \\network.drive\rxxg\dvc_cache\de\7511b07cd72b25dc78aa472ee21cbc inode 5667741391016463476
DEBUG: SELECT mtime, size, md5, timestamp from state WHERE inode=?
DEBUG: fetched: [('1579709801785156096', '16', 'de7511b07cd72b25dc78aa472ee21cbc', '1579709813109092096')]
DEBUG: UPDATE state SET mtime = ?, size = ?, md5 = ?, timestamp = ? WHERE inode = ?
DEBUG: Saving information to 'file.dvc'.
100% Add|███████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████|1.00/1.00 [00:01<00:00,  1.48s/file]

To track the changes with git, run:

        git add .gitignore file.dvc
DEBUG: SELECT count from state_info WHERE rowid=?
DEBUG: fetched: [(0,)]
DEBUG: UPDATE state_info SET count = ? WHERE rowid = ?
(dvc-3080) PS \\network.drive\rxxg> dvc version -v
DEBUG: Removing '\\network.drive\rxxg\.dccd8f66-73d1-4822-9c18-91cd46123f09'
DEBUG: Removing '\\network.drive\rxxg\dvc_cache\.dccd8f66-73d1-4822-9c18-91cd46123f09'
ERROR: unexpected error - [WinError 5] Access is denied: '\\\\network.drive\\rxxg\\dvc_cache\\.dccd8f66-73d1-4822-9c18-91cd46123f09'
------------------------------------------------------------
Traceback (most recent call last):
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\main.py", line 48, in main
    ret = cmd.run()
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\version.py", line 48, in run
    "Cache: {}".format(self.get_linktype_support_info(repo))
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\command\version.py", line 114, in get_linktype_support_info
    remove(src)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\utils\fs.py", line 140, in remove
    _chmod(os.unlink, path, None)
  File "c:\users\rxxg\dvc-3080\lib\site-packages\dvc\utils\fs.py", line 119, in _chmod
    perm = os.lstat(p).st_mode
PermissionError: [WinError 5] Access is denied: '\\\\network.drive\\rxxg\\dvc_cache\\.dccd8f66-73d1-4822-9c18-91cd46123f09'
------------------------------------------------------------


Having any troubles? Hit us up at https://dvc.org/support, we are always happy to help!
(dvc-3080) PS \\network.drive\rxxg> dvc version -v
DEBUG: Removing '\\network.drive\rxxg\.04afda28-153f-4255-bfdd-27edacea2de5'
DEBUG: Removing '\\network.drive\rxxg\dvc_cache\.04afda28-153f-4255-bfdd-27edacea2de5'
DVC version: 0.82.1+d3c711
Python version: 3.7.1
Platform: Windows-10-10.0.16299-SP0
Binary: False
Package: None
Cache: reflink - not supported, hardlink - broken, symlink - not supported
(dvc-3080) PS \\network.drive\rxxg>
```
efiop: @rxxg Very interesting. It allows us to create the file and doesn't allow to stat it. Very odd. Something is very broken in your setup, I'm not sure I understand the reasons...
efiop: @rxxg Maybe there is anything about the mounting parameters that you use?
rxxg: > 
> 
> @rxxg Maybe there is anything about the mounting parameters that you use?

Sorry, no idea.  The strange thing is that the file can be easily deleted by explorer or `rm` command.  And of course, the second call succeeds.
efiop: @rxxg Got it. But `dvc add` and other stuff works fine now, right?
rxxg: > 
> 
> @rxxg Got it. But `dvc add` and other stuff works fine now, right?

Fine in my limited testing.
efiop: @rxxg Got it. I think we could leave it as is, until new problems arise or someone else runs into the same issues, at which point we will need to do an in-depth investigation.

Patch:
diff --git a/dvc/command/version.py b/dvc/command/version.py
index aa7d630af..60c6109d3 100644
--- a/dvc/command/version.py
+++ b/dvc/command/version.py
@@ -86,9 +86,9 @@ class CmdVersion(CmdBaseNoRepo):
     @staticmethod
     def get_linktype_support_info(repo):
         links = {
-            "reflink": System.reflink,
-            "hardlink": System.hardlink,
-            "symlink": System.symlink,
+            "reflink": (System.reflink, None),
+            "hardlink": (System.hardlink, System.is_hardlink),
+            "symlink": (System.symlink, System.is_symlink),
         }
 
         fname = "." + str(uuid.uuid4())
@@ -98,18 +98,16 @@ class CmdVersion(CmdBaseNoRepo):
 
         cache = []
 
-        for name, link in links.items():
+        for name, (link, is_link) in links.items():
             try:
                 link(src, dst)
+                status = "supported"
+                if is_link and not is_link(dst):
+                    status = "broken"
                 os.unlink(dst)
-                supported = True
             except DvcException:
-                supported = False
-            cache.append(
-                "{name} - {supported}".format(
-                    name=name, supported=True if supported else False
-                )
-            )
+                status = "not supported"
+            cache.append("{name} - {status}".format(name=name, status=status))
         os.remove(src)
 
         return ", ".join(cache)
diff --git a/dvc/remote/base.py b/dvc/remote/base.py
index 7262ba1a9..1f466dad2 100644
--- a/dvc/remote/base.py
+++ b/dvc/remote/base.py
@@ -392,13 +392,24 @@ class RemoteBASE(object):
 
         self._try_links(from_info, to_info, link_types)
 
+    def _verify_link(self, path_info, link_type):
+        if self.cache_type_confirmed:
+            return
+
+        is_link = getattr(self, "is_{}".format(link_type), None)
+        if is_link and not is_link(path_info):
+            self.remove(path_info)
+            raise DvcException("failed to verify {}".format(link_type))
+
+        self.cache_type_confirmed = True
+
     @slow_link_guard
     def _try_links(self, from_info, to_info, link_types):
         while link_types:
             link_method = getattr(self, link_types[0])
             try:
                 self._do_link(from_info, to_info, link_method)
-                self.cache_type_confirmed = True
+                self._verify_link(to_info, link_types[0])
                 return
 
             except DvcException as exc:
diff --git a/dvc/remote/local.py b/dvc/remote/local.py
index d9e0bc69c..ba06e4a1c 100644
--- a/dvc/remote/local.py
+++ b/dvc/remote/local.py
@@ -178,6 +178,10 @@ class RemoteLOCAL(RemoteBASE):
     def symlink(from_info, to_info):
         System.symlink(from_info, to_info)
 
+    @staticmethod
+    def is_symlink(path_info):
+        return System.is_symlink(path_info)
+
     def hardlink(self, from_info, to_info):
         # If there are a lot of empty files (which happens a lot in datasets),
         # and the cache type is `hardlink`, we might reach link limits and
@@ -204,6 +208,10 @@ class RemoteLOCAL(RemoteBASE):
 
         System.hardlink(from_info, to_info)
 
+    @staticmethod
+    def is_hardlink(path_info):
+        return System.is_hardlink(path_info)
+
     @staticmethod
     def reflink(from_info, to_info):
         System.reflink(from_info, to_info)


Test patch:
diff --git a/tests/func/test_version.py b/tests/func/test_version.py
index 5af7dba4e..31d0d7e66 100644
--- a/tests/func/test_version.py
+++ b/tests/func/test_version.py
@@ -17,7 +17,9 @@ def test_info_in_repo(tmp_dir, dvc, caplog):
     assert re.search(r"Platform: .*", caplog.text)
     assert re.search(r"Binary: (True|False)", caplog.text)
     assert re.search(r"Package: .*", caplog.text)
-    assert re.search(r"(Cache: (.*link - (True|False)(,\s)?){3})", caplog.text)
+    assert re.search(
+        r"(Cache: (.*link - (not )?supported(,\s)?){3})", caplog.text
+    )
 
 
 @pytest.mark.skipif(psutil is None, reason="No psutil.")
@@ -37,9 +39,7 @@ def test_info_outside_of_repo(tmp_dir, caplog):
     assert re.search(r"Platform: .*", caplog.text)
     assert re.search(r"Binary: (True|False)", caplog.text)
     assert re.search(r"Package: .*", caplog.text)
-    assert not re.search(
-        r"(Cache: (.*link - (True|False)(,\s)?){3})", caplog.text
-    )
+    assert not re.search(r"(Cache: (.*link - (not )?(,\s)?){3})", caplog.text)
 
 
 @pytest.mark.skipif(psutil is None, reason="No psutil.")