1

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); } } } 

3 Answers 3

4

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I don't have filesystem. I think it's only for C++14 or 17
@Frappy Yes, it's for C++17. Which C++ version are you using? If you are using Visual Studio 2019 (and I think even in Visual Studio 2017), you can switch to C++17 to enable std::filesystem.
Yes, I just switched to the latest available version of C++ and it works! Thanks!
It would be worth testing what VC++ considers to be a symlink in Windows. Is it only an actual symbolic link that's created via CreateSymbolicLinkW -- i.e. strict POSIX compliance -- or does it also skip traversing directory mount points (i.e. junctions), which a Unix implementation would typically traverse? System shells in Windows (e.g. CMD, Explorer) do not traverse directory mount points (or any name-surrogate reparse point) when recursively deleting a tree. I would guess that VC++ remove_all behaves the same as a system shell.
1

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.

Comments

0

You can use:

std::filesystem::remove_all("path/myDirectory"); 

5 Comments

filesystem library is not an experimental - it's a part of C++17: en.cppreference.com/w/cpp/experimental/fs .
Doesn't matter, has the same "problem".
Ok you can use like std::filesystem::remove
@Val_MagicStar remove_all ;) And you should edit your answer...
@Lightness Races with Monica I agree with you, but since you and others already did an exhaustive comment, I didn't want to repeat the same things, and i just corrected what I wrote before.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.