aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libbutl/filesystem.cxx26
-rw-r--r--tests/mventry/testscript6
2 files changed, 28 insertions, 4 deletions
diff --git a/libbutl/filesystem.cxx b/libbutl/filesystem.cxx
index 7b340f6..70597b9 100644
--- a/libbutl/filesystem.cxx
+++ b/libbutl/filesystem.cxx
@@ -295,7 +295,31 @@ namespace butl
if (!CreateHardLinkA (link.string ().c_str (),
target.string ().c_str (),
nullptr))
- throw_system_error (GetLastError ());
+ {
+ // If creation fails because hardlinks are not supported for the
+ // specified target/link paths combination, then throw system_error of
+ // the generic category with an approximate POSIX errno code. This way
+ // the caller could recognize such a case and, for example, fallback
+ // to the copy operation. For other error codes use the system
+ // category.
+ //
+ DWORD ec (GetLastError ());
+ switch (ec)
+ {
+ // Target and link are on different drives.
+ //
+ case ERROR_NOT_SAME_DEVICE: throw_generic_error (EXDEV);
+
+ // Target and link are on the same drive, which doesn't support
+ // hardlinks.
+ //
+ case ERROR_ACCESS_DENIED: throw_generic_error (EPERM);
+
+ // Some other failure reason. Fallback to the system category.
+ //
+ default: throw_system_error (ec);
+ }
+ }
}
else
throw_generic_error (ENOSYS, "directory hard links not supported");
diff --git a/tests/mventry/testscript b/tests/mventry/testscript
index 0a0aaa0..826aeef 100644
--- a/tests/mventry/testscript
+++ b/tests/mventry/testscript
@@ -118,7 +118,7 @@ if ($test.target == $build.host)
: rename.
:
echo 'foo' >=a;
- $lns;
+ $lns &!b;
$* b c &c;
test -f a;
test -f b == 1;
@@ -131,7 +131,7 @@ if ($test.target == $build.host)
: target stays intact.
:
echo 'foo' >=a;
- $lns &b;
+ $lns;
echo 'bar' >=c &!c;
$* c b;
cat a >'foo';
@@ -156,7 +156,7 @@ if ($test.target == $build.host)
: rename.
:
mkdir -p a;
- $lns;
+ $lns &!b;
$* b c &c;
touch a/b;
test -f c/b;