Better file/directory removal platform code and utilities

This commit is contained in:
Perttu Ahola 2012-03-26 00:21:38 +03:00
parent dcef5183f7
commit 5b31d32da8
2 changed files with 129 additions and 24 deletions

@ -138,32 +138,75 @@ bool PathExists(std::string path)
return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES); return (GetFileAttributes(path.c_str()) != INVALID_FILE_ATTRIBUTES);
} }
bool IsDir(std::string path)
{
DWORD attr = GetFileAttributes(path.c_str());
return (attr != INVALID_FILE_ATTRIBUTES &&
(attr & FILE_ATTRIBUTE_DIRECTORY));
}
bool RecursiveDelete(std::string path) bool RecursiveDelete(std::string path)
{ {
infostream<<"Removing \""<<path<<"\""<<std::endl; infostream<<"Recursively deleting \""<<path<<"\""<<std::endl;
//return false; DWORD attr = GetFileAttributes(path.c_str());
bool is_directory = (attr != INVALID_FILE_ATTRIBUTES &&
// This silly function needs a double-null terminated string... (attr & FILE_ATTRIBUTE_DIRECTORY));
// Well, we'll just make sure it has at least two, then. if(!is_directory)
path += "\0\0"; {
infostream<<"RecursiveDelete: Deleting file "<<path<<std::endl;
SHFILEOPSTRUCT sfo; //bool did = DeleteFile(path.c_str());
sfo.hwnd = NULL; bool did = true;
sfo.wFunc = FO_DELETE; if(!did){
sfo.pFrom = path.c_str(); errorstream<<"RecursiveDelete: Failed to delete file "
sfo.pTo = NULL; <<path<<std::endl;
sfo.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR; return false;
}
int r = SHFileOperation(&sfo); }
else
if(r != 0) {
errorstream<<"SHFileOperation returned "<<r<<std::endl; infostream<<"RecursiveDelete: Deleting content of directory "
<<path<<std::endl;
//return (r == 0); std::vector<DirListNode> content = GetDirListing(path);
for(int i=0; i<content.size(); i++){
const DirListNode &n = content[i];
std::string fullpath = path + DIR_DELIM + n.name;
bool did = RecursiveDelete(fullpath);
if(!did){
errorstream<<"RecursiveDelete: Failed to recurse to "
<<fullpath<<std::endl;
return false;
}
}
infostream<<"RecursiveDelete: Deleting directory "<<path<<std::endl;
//bool did = RemoveDirectory(path.c_str();
bool did = true;
if(!did){
errorstream<<"Failed to recursively delete directory "
<<path<<std::endl;
return false;
}
}
return true; return true;
} }
bool DeleteSingleFileOrEmptyDirectory(std::string path)
{
DWORD attr = GetFileAttributes(path.c_str());
bool is_directory = (attr != INVALID_FILE_ATTRIBUTES &&
(attr & FILE_ATTRIBUTE_DIRECTORY));
if(!is_directory)
{
bool did = DeleteFile(path.c_str());
return did;
}
else
{
bool did = RemoveDirectory(path.c_str());
return did;
}
}
#else // POSIX #else // POSIX
#include <sys/types.h> #include <sys/types.h>
@ -249,6 +292,14 @@ bool PathExists(std::string path)
return (stat(path.c_str(),&st) == 0); return (stat(path.c_str(),&st) == 0);
} }
bool IsDir(std::string path)
{
struct stat statbuf;
if(stat(path.c_str(), &statbuf))
return false; // Actually error; but certainly not a directory
return ((statbuf.st_mode & S_IFDIR) == S_IFDIR);
}
bool RecursiveDelete(std::string path) bool RecursiveDelete(std::string path)
{ {
/* /*
@ -295,8 +346,51 @@ bool RecursiveDelete(std::string path)
} }
} }
bool DeleteSingleFileOrEmptyDirectory(std::string path)
{
if(IsDir(path)){
bool did = (rmdir(path.c_str()) == 0);
if(!did)
errorstream<<"rmdir errno: "<<errno<<": "<<strerror(errno)
<<std::endl;
return did;
} else {
bool did = (unlink(path.c_str()) == 0);
if(!did)
errorstream<<"unlink errno: "<<errno<<": "<<strerror(errno)
<<std::endl;
return did;
}
}
#endif #endif
void GetRecursiveSubPaths(std::string path, std::vector<std::string> &dst)
{
std::vector<DirListNode> content = GetDirListing(path);
for(unsigned int i=0; i<content.size(); i++){
const DirListNode &n = content[i];
std::string fullpath = path + DIR_DELIM + n.name;
dst.push_back(fullpath);
GetRecursiveSubPaths(fullpath, dst);
}
}
bool DeletePaths(const std::vector<std::string> &paths)
{
bool success = true;
// Go backwards to succesfully delete the output of GetRecursiveSubPaths
for(int i=paths.size()-1; i>=0; i--){
const std::string &path = paths[i];
bool did = DeleteSingleFileOrEmptyDirectory(path);
if(!did){
errorstream<<"Failed to delete "<<path<<std::endl;
success = false;
}
}
return success;
}
bool RecursiveDeleteContent(std::string path) bool RecursiveDeleteContent(std::string path)
{ {
infostream<<"Removing content of \""<<path<<"\""<<std::endl; infostream<<"Removing content of \""<<path<<"\""<<std::endl;

@ -40,24 +40,35 @@ struct DirListNode
std::string name; std::string name;
bool dir; bool dir;
}; };
std::vector<DirListNode> GetDirListing(std::string path); std::vector<DirListNode> GetDirListing(std::string path);
// Returns true if already exists // Returns true if already exists
bool CreateDir(std::string path); bool CreateDir(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
bool PathExists(std::string path); bool PathExists(std::string path);
bool IsDir(std::string path);
// Only pass full paths to this one. True on success. // Only pass full paths to this one. True on success.
// NOTE: The WIN32 version returns always true. // NOTE: The WIN32 version returns always true.
bool RecursiveDelete(std::string path); bool RecursiveDelete(std::string path);
bool DeleteSingleFileOrEmptyDirectory(std::string path);
/* Multiplatform */
// The path itself not included
void GetRecursiveSubPaths(std::string path, std::vector<std::string> &dst);
// Tries to delete all, returns false if any failed
bool DeletePaths(const std::vector<std::string> &paths);
// Only pass full paths to this one. True on success. // Only pass full paths to this one. True on success.
bool RecursiveDeleteContent(std::string path); bool RecursiveDeleteContent(std::string path);
// Create all directories on the given path that don't already exist.
bool CreateAllDirs(std::string path);
}//fs }//fs
#endif #endif