Removing readonly files on windows with std.file
Vladimir Panteleev
thecybershadow.lists at gmail.com
Sun Mar 8 01:35:15 UTC 2020
On Saturday, 7 March 2020 at 20:01:07 UTC, Jonathan Marler wrote:
> After dealing with annoying failures to remove directories on
> windows with std.file.rmdirRecurse for too long, I finally
> decided to look into it.
>
> It looks like rmdirRecurse fails because I'm trying to remove a
> directory that contains a git repository in it. It turns out
> that git marks some files as READONLY to indicate that they
> shouldn't be modified. However, this will cause the DeleteFile
> function (which is what rmdirRecurse will eventually call) to
> fail. The docs say that you must remove the READONLY attribute
> before the file can be deleted.
This sounds right to me.
> Note that deleting a directory/file from Windows Explorer or
> calling `del` from the command-line will remove READONLY files
> no problem.
I don't think this should affect what Phobos does, as the above
are interfaces for humans and Phobos is an OS API wrapper.
(Though, in the case of rmdirRecurse, it's not as clear because
it is an utility function.)
> I could create a pull request to modify std.file to handle
> this, however, I'm not sure what the right solution is. We
> could modify std.file.remove to be able to remove readonly
> files, but maybe there's use cases where people want the
> removal to fail if it is marked as readonly?
I think the function should do no more than the OS primitive API.
As far as I can see, the steps to create such a file from with in
D would be:
1. Create the file.
2. Mark it read-only.
The inverse operation, again from D, would then be:
2. Unmark it as read-only.
1. Delete the file.
No problem here.
If you begin to do "magic" and "do what I mean" things, you open
yourself up to questions like "why only the readonly attribute?
why not also the ACL lists? and what about other platforms?" and
it goes downhill from there. One similar example of this is that
Tango's initial directory iteration primitive skipped hidden and
system files (because that's what the shell does, duh), which as
you can imagine caused a lot of pain should one such file ever
come across your program.
I think the correct solution is to make sure that it is easy to
recursively delete a directory (while clearing the readonly
attribute if that's what the user wants) using only Phobos
directory iteration primitives (dirEntries). If it's not then
that is where the improvements ought to be done.
The current dirEntries API is definitely suboptimal in that error
handling is difficult if you want to skip parts of the tree that
fail to iterate, and that you can't selectively choose which
directories to recurse into. I tried to address these with an
alternative approach in my library
(https://github.com/CyberShadow/ae/blob/6177cd442d9737b8e8141e30197fe124c5aaba18/sys/file.d#L176), which is also many times faster than dirEntries in many cases due to allocating less and not needing to stat unless absolutely necessary.
I also have a few "improved" rmdirRecurse variants which solve
this problem as well:
https://github.com/CyberShadow/ae/blob/6177cd442d9737b8e8141e30197fe124c5aaba18/sys/file.d#L1002
However, I don't think they are suitable for Phobos, because
there is just too much variation in what exactly "recursively
delete a directory" should mean - so, in your case, a variant of
rmdirRecurse which now works on git directories will fail due to
ACLs, or not do what the user expects if the given path is a
symlink, or other of many such questions.
Therefore, I think we should ensure that the primitives are there
and easily accessible and programs should build their own utility
functions to delete directory trees with whatever properties they
need to care about.
More information about the Digitalmars-d
mailing list