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 <IFileSystem.h>
#endif
#ifdef __linux__
#include <fcntl.h>
#include <sys/ioctl.h>
@ -43,6 +44,19 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#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
#ifdef _WIN32
#define LAST_OS_ERROR() porting::ConvertError(GetLastError())
@ -59,11 +73,6 @@ namespace fs
* Windows *
***********/
#include <windows.h>
#include <shlwapi.h>
#include <io.h>
#include <direct.h>
std::vector<DirListNode> GetDirListing(const std::string &pathstring)
{
std::vector<DirListNode> listing;
@ -273,12 +282,6 @@ bool CopyFileContents(const std::string &source, const std::string &target)
* 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> listing;
@ -381,41 +384,41 @@ bool RecursiveDelete(const std::string &path)
Execute the 'rm' command directly, by fork() and execve()
*/
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
const char *argv[4] = {
#ifdef __ANDROID__
"/system/bin/rm",
#else
"/bin/rm",
#endif
std::array<const char*, 4> argv = {
"rm",
"-rf",
path.c_str(),
NULL
nullptr
};
verbosestream<<"Executing '"<<argv[0]<<"' '"<<argv[1]<<"' '"
<<argv[2]<<"'"<<std::endl;
execvp(argv[0], const_cast<char**>(argv.data()));
execv(argv[0], const_cast<char**>(argv));
// Execv shouldn't return. Failed.
// note: use cerr because our logging won't flush in forked process
std::cerr << "exec errno: " << errno << ": " << strerror(errno)
<< std::endl;
_exit(1);
}
else
{
} else {
// Parent
int child_status;
int status;
pid_t tpid;
do{
tpid = wait(&child_status);
}while(tpid != child_pid);
return (child_status == 0);
do
tpid = waitpid(child_pid, &status, 0);
while (tpid != child_pid);
return WIFEXITED(status) && WEXITSTATUS(status) == 0;
}
}

@ -42,6 +42,7 @@ public:
void testSafeWriteToFile();
void testCopyFileContents();
void testNonExist();
void testRecursiveDelete();
};
static TestFileSys g_test_instance;
@ -56,6 +57,7 @@ void TestFileSys::runTests(IGameDef *gamedef)
TEST(testSafeWriteToFile);
TEST(testCopyFileContents);
TEST(testNonExist);
TEST(testRecursiveDelete);
}
////////////////////////////////////////////////////////////////////////////////
@ -338,3 +340,32 @@ void TestFileSys::testNonExist()
auto ifs = open_ifstream(path.c_str(), false);
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));
}