diff --git a/source/core/slang-io.cpp b/source/core/slang-io.cpp index ffbb5fa98e..23b6ac93df 100644 --- a/source/core/slang-io.cpp +++ b/source/core/slang-io.cpp @@ -17,6 +17,7 @@ #ifdef _WIN32 # include # include +# include #endif #if defined(__linux__) || defined(__CYGWIN__) || SLANG_APPLE_FAMILY @@ -27,6 +28,7 @@ # include # include # include +# include // for nftw #endif #if SLANG_APPLE_FAMILY @@ -777,6 +779,61 @@ namespace Slang #endif } + /* static */SlangResult Path::removeNonEmpty(const String& path) + { + if (File::exists(path) == false) + { + return SLANG_OK; + } + + StringBuilder msgBuilder; + // Path::remove() doesn't support remove a non-empty directory, so we need to implement + // a simple function to remove the directory recursively. +#ifdef _WIN32 + // https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shfileoperationa + // Note: the fromPath requires a double-null-terminated string. + String newPath = path; + newPath.append('\0'); + SHFILEOPSTRUCTA file_op = { + NULL, + FO_DELETE, + newPath.begin(), + "", + FOF_NOCONFIRMATION | + FOF_NOERRORUI | + FOF_SILENT, + false, + 0, + "" }; + int ret = SHFileOperationA(&file_op); + if (ret) + { + return SLANG_FAIL; + } +#else + auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int + { + SLANG_UNUSED(sb) + SLANG_UNUSED(typeflag) + SLANG_UNUSED(ftwbuf) + int rv = ::remove(fpath); + if (rv) + { + perror(fpath); + } + return rv; + }; + // https://linux.die.net/man/3/nftw + int ret = ::nftw(path.begin(), unlink_cb, 64, FTW_DEPTH | FTW_PHYS); + if (ret) + { + return SLANG_FAIL; + } +#endif + + return SLANG_OK; + } + #if defined(_WIN32) /* static */SlangResult Path::find(const String& directoryPath, const char* pattern, Visitor* visitor) { diff --git a/source/core/slang-io.h b/source/core/slang-io.h index 763907c983..676635a36b 100644 --- a/source/core/slang-io.h +++ b/source/core/slang-io.h @@ -217,6 +217,11 @@ namespace Slang /// @return SLANG_OK if file or directory is removed static SlangResult remove(const String& path); + /// Remove a file or directory at specified path. The directory can be non-empty. + /// @param path + /// @return SLANG_OK if file or directory is removed + static SlangResult removeNonEmpty(const String& path); + static bool equals(String path1, String path2); /// Turn `path` into a relative path from base. diff --git a/tools/slang-unit-test/unit-test-record-replay.cpp b/tools/slang-unit-test/unit-test-record-replay.cpp index d775e1421d..33bbab0c38 100644 --- a/tools/slang-unit-test/unit-test-record-replay.cpp +++ b/tools/slang-unit-test/unit-test-record-replay.cpp @@ -9,13 +9,6 @@ #include "tools/unit-test/slang-unit-test.h" -#ifdef _WIN32 -#include -#include -#else -#include -#endif - #include #include @@ -355,55 +348,13 @@ static SlangResult resultCompare(List const& expectHashes, Listmessage(TestMessageType::TestFailure, msgBuilder.toString().getBuffer()); - return SLANG_FAIL; - } -#else - auto unlink_cb = [](const char* fpath, const struct stat* sb, int typeflag, struct FTW* ftwbuf) -> int - { - int rv = ::remove(fpath); - if (rv) - { - perror(fpath); - } - return rv; - }; - // https://linux.die.net/man/3/nftw - int ret = nftw("slang-record", unlink_cb, 64, FTW_DEPTH | FTW_PHYS); - if (ret) + SlangResult res = Path::removeNonEmpty("slang-record"); + if (SLANG_FAILED(res)) { - msgBuilder << "fail to remove 'slang-record' dir, error: " << ret << ", " << strerror(errno) << "\n"; - getTestReporter()->message(TestMessageType::TestFailure, msgBuilder.toString().getBuffer()); - return SLANG_FAIL; + getTestReporter()->message(TestMessageType::TestFailure, "Failed to remove 'slang-record' directory\n"); } -#endif - return SLANG_OK; + return res; } static SlangResult runTest(UnitTestContext* context, const char* testName) @@ -427,7 +378,7 @@ static SlangResult runTest(UnitTestContext* context, const char* testName) } error: - cleanupRecordFiles(); + res = cleanupRecordFiles(); return res; }