Skip to content

Commit

Permalink
Fix #2234, make copies writable.
Browse files Browse the repository at this point in the history
  • Loading branch information
veelo authored and WebFreak001 committed Jun 13, 2022
1 parent 21c875a commit 96d2536
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 14 deletions.
8 changes: 8 additions & 0 deletions changelog/make-copies-writable.dd
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
When `copyFiles` is used to copy read-only files, it now makes the copy writable.

Previously, if the target file would already exist due to a prior run of Dub, `copyFiles` would produce an access
denied error because the read-only target could not be overwritten. Note that if you were affected by this behaviour,
you will need to remove those files by hand once to eliminate these errors.

It is common for version control systems to mark binary files read-only in the working copy, to prevent concurrent
edits of files in unmergeable formats.
75 changes: 62 additions & 13 deletions source/dub/internal/vibecompat/core/file.d
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,52 @@ private bool sameFile(NativePath a, NativePath b)
}
}

private bool isWritable(NativePath name)
{
version (Windows)
{
import core.sys.windows.windows;

return (name.toNativeString.getAttributes & FILE_ATTRIBUTE_READONLY) == 0;
}
else version (Posix)
{
import core.sys.posix.sys.stat;

return (name.toNativeString.getAttributes & S_IWUSR) != 0;
}
else
static assert(false, "Needs implementation.");
}

private void makeWritable(NativePath name)
{
makeWritable(name.toNativeString);
}

private void makeWritable(string name)
{
version (Windows)
{
import core.sys.windows.windows;

name.setAttributes(name.getAttributes & ~FILE_ATTRIBUTE_READONLY);
}
else version (Posix)
{
import core.sys.posix.sys.stat;

name.setAttributes(name.getAttributes | S_IWUSR);
}
else
static assert(false, "Needs implementation.");
}

/**
Creates a hardlink.
Creates a hardlink if possible, a copy otherwise.
If `from` is read-only and `overwrite` is true, then a copy is made instead
and `to` is made writable; so that repeating the command will not fail.
*/
void hardLinkFile(NativePath from, NativePath to, bool overwrite = false)
{
Expand All @@ -168,22 +212,27 @@ void hardLinkFile(NativePath from, NativePath to, bool overwrite = false)
throw fe;
}
}

version (Windows)
{
alias cstr = toUTFz!(const(wchar)*);
if (CreateHardLinkW(cstr(to.toNativeString), cstr(from.toNativeString)))
return;
}
else
const writeAccessChangeRequired = overwrite && !isWritable(from);
if (!writeAccessChangeRequired)
{
import core.sys.posix.unistd : link;
alias cstr = toUTFz!(const(char)*);
if (!link(cstr(from.toNativeString), cstr(to.toNativeString)))
return;
version (Windows)
{
alias cstr = toUTFz!(const(wchar)*);
if (CreateHardLinkW(cstr(to.toNativeString), cstr(from.toNativeString)))
return;
}
else
{
import core.sys.posix.unistd : link;
alias cstr = toUTFz!(const(char)*);
if (!link(cstr(from.toNativeString), cstr(to.toNativeString)))
return;
}
}
// fallback to copy
copyFile(from, to, overwrite);
if (writeAccessChangeRequired)
to.makeWritable;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion test/issue2234-copy-read-only-files.script.d
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ void makeWritable(string name)
{
import core.sys.posix.sys.stat;

name.setAttributes(name.getAttributes() | (S_IWUSR | S_IWGRP | S_IWOTH));
name.setAttributes(name.getAttributes() | S_IWUSR);
}
else
static assert("Needs implementation.");
Expand Down

0 comments on commit 96d2536

Please sign in to comment.