Reputation: 347
I made a simple program that deletes files, however, I don't know how to delete a directory. I saw a few posts saying I need to list all of the files in that directory, delete those files, and then delete the directory/folder itself. However, somebody suggested using _rmdir which as far as I understand, deletes a directory without any problems, however, it doesn't. Do I still need to list all of the files in a directory in order to delete it with _rmdir? Thanks!
Code:
#include <iostream>
#include <string>
#include <sys/stat.h>
#include <Windows.h>
#include <direct.h>
using namespace std;
HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
inline bool fileExists(const string& filepath) {
struct stat buffer;
return (stat(filepath.c_str(), &buffer) == 0);
}
int main()
{
string filePath;
string fileAttribute;
cout << "[~] Enter a path to delete: ";
getline(cin, filePath);
cout << "\n[#] Checking if path exists..";
if (fileExists(filePath) == 1)
{
if (GetFileAttributes(filePath.c_str()) == FILE_ATTRIBUTE_DIRECTORY)
{
cout << "\n[!] Directory found!";
_rmdir(filePath.c_str());
cout << "\n[#] Deleting directory..";
}
else
{
cout << "\n[!] File found!";
remove(filePath.c_str());
cout << "\n[#] Deleting file..";
}
if (fileExists(filePath) == 0)
{
SetConsoleTextAttribute(h, 10);
cout << "\n[!] Deletetion successful!";
SetConsoleTextAttribute(h, 15);
}
else
{
SetConsoleTextAttribute(h, 12);
cout << "\n[!] Deletion unsuccessful!";
SetConsoleTextAttribute(h, 15);
}
}
}
Upvotes: 1
Views: 1701
Reputation: 117238
You probably want the C++17 function std::filesystem::remove_all which deletes the contents of the directory and the contents of all its subdirectories, recursively, then deletes the directory itself as if by repeatedly applying the POSIX remove. Symlinks are not followed (symlink is removed, not its target).
Edit: As Eryk Sun pointed out in the comments, it's good to test that the recursive removal does not follow Windows junctions, which would lead to unwanted removal of everything the junction points at.
I made a test that used std::filesystem::create_directory_symlink
to create a symlink and then use the WinAPI to check if that symlink became a junction, which it reportedly did - a junction has the FILE_ATTRIBUTE_REPARSE_POINT
attribute and the reparse point tag IO_REPARSE_TAG_MOUNT_POINT
. Interestingly it also had the IO_REPARSE_TAG_SYMLINK
tag. When using normal DOS
commands I noticed that the link was indeed reported as a plain <SYMLINKD>
and not a <JUNCTION>
.
I then used MKLINK /J
to create a junction. That junction was indeed reported as a <JUNCTION>
by DOS
and running std::filesystem::remove_all()
on it removed it, but not what it pointed at.
I also downloaded the sysinternals Junction utility and used that to create a junction.
That junction was also reported as a <JUNCTION>
by DOS
, but running std::filesystem::remove_all()
on it had another effect. It did not remove it (or what it pointed at).
So remove_all()
should be safe with regards to junctions - but perhaps even too safe. I didn't try to find out what the difference was between the MKLINK
junction and the junction created by the sysinternals utility.
Upvotes: 4
Reputation: 385108
Do I still need to list all of the files in a directory in order to delete it with _rmdir?
Why don't you simply read the documentation?
It says:
The _rmdir function deletes the directory specified by dirname. The directory must be empty, and it must not be the current working directory or the root directory.
That's pretty much the case for any "remove directory" functionality. It's what your Windows Explorer UI is doing behind the scenes when you hit delete on your keyboard.
This is also the case for std::filesystem::remove
, but std::filesystem::remove_all
will do all that recursion for you.
Upvotes: 1