microsoft / STL

MSVC's implementation of the C++ Standard Library.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

<filesystem>: remove does not delete read-only files

SibiSiddharthan opened this issue · comments

Descibe the bug
std::filesystem::remove() does not remove read-only files
The issue with this is that STL sets the FILE_ATTRIBUTE_READONLY bit when we remove the write permissions for a file.
remove should remove such files also.

Command-line test case

C:\Temp>type repro.cpp
#include <filesystem>
#include <iostream>
#include <fstream>

using namespace std;
namespace fs = std::filesystem;

int main()
{
	fs::path testfile("testfile");

	// Create the file
	fstream file;
	file.open(testfile, ios::out);
	file.close();

	// Remove write permissions
	fs::permissions(testfile,
				fs::perms::owner_write | fs::perms::group_write | fs::perms::others_write,
				fs::perm_options::remove);

	error_code E;
	//POSIX remove should remove this as well.
	fs::remove(testfile, E);
	//Should print '5 Access is denied.'
	cout << E.value() << " " << E.message() << endl;
}


C:\Temp>cl /EHsc /std:c++17 /W4 /WX .\repro.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.23.28019.1 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

repro.cpp
Microsoft (R) Incremental Linker Version 14.23.28019.1
Copyright (C) Microsoft Corporation.  All rights reserved.

/out:repro.exe
repro.obj

C:\Temp>.\repro.exe
5 Access is denied.

Expected behavior
std::filesystem::remove() should remove 'testfile'

STL version
Versions that support std::filesystem

Bug confirmed. I assume we could fix this by clearing the read-only attribute and retrying when access is denied, but hopefully there's a more elegant way.

I think we should try and clear the read-only attribute before setting FILE_FLAG_DELETE_ON_CLOSE. In this way we avoid retrying for the failure case.

I think we should try and clear the read-only attribute before setting FILE_FLAG_DELETE_ON_CLOSE. In this way we avoid retrying for the failure case.

I expect remove is used at least two orders of magnitude more frequently on non-readonly files, in which case it would be better on average to avoid extra work for the non-readonly case at the expense of the readonly case.

If I understand correctly, the file is being deleted when the destructor for _Fs_file is being called at the end of __std_fs_remove function. Then to retry in case of failure, the changes have to done to the 2 overloads of remove in the filesystem header file. Is this correct/acceptable?

This is not completely fixed.
The issue especially happens on .git folder after some time of using that repo.
fs::remove() returns true for some .git/objects/anynumber/anyfile, but further check in fs::remove_all() finds that not all files were removed.

Such files are indeed readonly, so I'll reactivate this bug:

C:\GitHub\STL\.git\objects\f3>attrib
A    R               C:\GitHub\STL\.git\objects\f3\28589c3326fa4f97566f1e1c3386ebe05f14d8
A    R               C:\GitHub\STL\.git\objects\f3\44ea8a1d4994f2a27733410a671d36b1916817
A    R               C:\GitHub\STL\.git\objects\f3\5d7661c0c87a71a152ed0b09ea69fa8efc1d67
A    R               C:\GitHub\STL\.git\objects\f3\8d2f7ad8debd6b0d75257b538a40f09b77122d
A    R               C:\GitHub\STL\.git\objects\f3\df360f3a4b8220fc897b5faac38b54dee537bd

Hey, I am trying to debug this. But the objects inside the git folder are getting deleted with fs::remove. I am not sure how some objects aren't getting deleted. Maybe some external process is holding file contents in memory relinking the files.