Use execvp in fs::RecursiveDelete()

This commit is contained in:
sfan5 2024-10-10 17:40:06 +02:00 committed by GitHub
parent 3f5a58a4e5
commit c8f1efebea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 35 deletions

@ -35,6 +35,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include <IFileArchive.h> #include <IFileArchive.h>
#include <IFileSystem.h> #include <IFileSystem.h>
#endif #endif
#ifdef __linux__ #ifdef __linux__
#include <fcntl.h> #include <fcntl.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -43,6 +44,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#endif #endif
#endif #endif
#ifdef _WIN32
#include <windows.h>
#include <shlwapi.h>
#include <io.h>
#include <direct.h>
#else
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
#endif
// Error from last OS call as string // Error from last OS call as string
#ifdef _WIN32 #ifdef _WIN32
#define LAST_OS_ERROR() porting::ConvertError(GetLastError()) #define LAST_OS_ERROR() porting::ConvertError(GetLastError())
@ -59,11 +73,6 @@ namespace fs
* Windows * * Windows *
***********/ ***********/
#include <windows.h>
#include <shlwapi.h>
#include <io.h>
#include <direct.h>
std::vector<DirListNode> GetDirListing(const std::string &pathstring) std::vector<DirListNode> GetDirListing(const std::string &pathstring)
{ {
std::vector<DirListNode> listing; std::vector<DirListNode> listing;
@ -273,12 +282,6 @@ bool CopyFileContents(const std::string &source, const std::string &target)
* POSIX * * POSIX *
*********/ *********/
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/wait.h>
#include <unistd.h>
std::vector<DirListNode> GetDirListing(const std::string &pathstring) std::vector<DirListNode> GetDirListing(const std::string &pathstring)
{ {
std::vector<DirListNode> listing; std::vector<DirListNode> listing;
@ -383,39 +386,39 @@ bool RecursiveDelete(const std::string &path)
infostream << "Removing \"" << path << "\"" << std::endl; infostream << "Removing \"" << path << "\"" << std::endl;
pid_t child_pid = fork(); assert(IsPathAbsolute(path));
if(child_pid == 0) const pid_t child_pid = fork();
{
if (child_pid == -1) {
errorstream << "fork errno: " << errno << ": " << strerror(errno)
<< std::endl;
return false;
}
if (child_pid == 0) {
// Child // Child
const char *argv[4] = { std::array<const char*, 4> argv = {
#ifdef __ANDROID__ "rm",
"/system/bin/rm",
#else
"/bin/rm",
#endif
"-rf", "-rf",
path.c_str(), path.c_str(),
NULL nullptr
}; };
verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '" execvp(argv[0], const_cast<char**>(argv.data()));
<<argv[2]<<"'"<<std::endl;
execv(argv[0], const_cast<char**>(argv)); // note: use cerr because our logging won't flush in forked process
std::cerr << "exec errno: " << errno << ": " << strerror(errno)
// Execv shouldn't return. Failed. << std::endl;
_exit(1); _exit(1);
} } else {
else
{
// Parent // Parent
int child_status; int status;
pid_t tpid; pid_t tpid;
do{ do
tpid = wait(&child_status); tpid = waitpid(child_pid, &status, 0);
}while(tpid != child_pid); while (tpid != child_pid);
return (child_status == 0); return WIFEXITED(status) && WEXITSTATUS(status) == 0;
} }
} }

@ -42,6 +42,7 @@ public:
void testSafeWriteToFile(); void testSafeWriteToFile();
void testCopyFileContents(); void testCopyFileContents();
void testNonExist(); void testNonExist();
void testRecursiveDelete();
}; };
static TestFileSys g_test_instance; static TestFileSys g_test_instance;
@ -56,6 +57,7 @@ void TestFileSys::runTests(IGameDef *gamedef)
TEST(testSafeWriteToFile); TEST(testSafeWriteToFile);
TEST(testCopyFileContents); TEST(testCopyFileContents);
TEST(testNonExist); TEST(testNonExist);
TEST(testRecursiveDelete);
} }
//////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////
@ -338,3 +340,32 @@ void TestFileSys::testNonExist()
auto ifs = open_ifstream(path.c_str(), false); auto ifs = open_ifstream(path.c_str(), false);
UASSERT(!ifs.good()); UASSERT(!ifs.good());
} }
void TestFileSys::testRecursiveDelete()
{
std::string dirs[2];
dirs[0] = getTestTempDirectory() + DIR_DELIM "a";
dirs[1] = dirs[0] + DIR_DELIM "b";
std::string files[2] = {
dirs[0] + DIR_DELIM "file1",
dirs[1] + DIR_DELIM "file2"
};
for (auto &it : dirs)
fs::CreateDir(it);
for (auto &it : files)
open_ofstream(it.c_str(), false).close();
for (auto &it : dirs)
UASSERT(fs::IsDir(it));
for (auto &it : files)
UASSERT(fs::IsFile(it));
UASSERT(fs::RecursiveDelete(dirs[0]));
for (auto &it : dirs)
UASSERT(!fs::IsDir(it));
for (auto &it : files)
UASSERT(!fs::IsFile(it));
}