|
48 | 48 | # include <io.h> |
49 | 49 | #endif |
50 | 50 |
|
| 51 | +#ifdef _WIN32 |
| 52 | +#include <windows.h> |
| 53 | +#else |
| 54 | +#include <unistd.h> |
| 55 | +#endif |
| 56 | + |
51 | 57 | namespace node { |
52 | 58 |
|
53 | 59 | namespace fs { |
@@ -1605,6 +1611,92 @@ static void RMDir(const FunctionCallbackInfo<Value>& args) { |
1605 | 1611 | } |
1606 | 1612 | } |
1607 | 1613 |
|
| 1614 | +static void RmSync(const FunctionCallbackInfo<Value>& args) { |
| 1615 | + Environment* env = Environment::GetCurrent(args); |
| 1616 | + Isolate* isolate = env->isolate(); |
| 1617 | + |
| 1618 | + CHECK_EQ(args.Length(), 4); // path, maxRetries, recursive, retryDelay |
| 1619 | + |
| 1620 | + BufferValue path(isolate, args[0]); |
| 1621 | + CHECK_NOT_NULL(*path); |
| 1622 | + ToNamespacedPath(env, &path); |
| 1623 | + THROW_IF_INSUFFICIENT_PERMISSIONS( |
| 1624 | + env, permission::PermissionScope::kFileSystemWrite, path.ToStringView()); |
| 1625 | + auto file_path = std::filesystem::path(path.ToStringView()); |
| 1626 | + std::error_code error; |
| 1627 | + auto file_status = std::filesystem::status(file_path, error); |
| 1628 | + |
| 1629 | + if (file_status.type() == std::filesystem::file_type::not_found) { |
| 1630 | + return; |
| 1631 | + } |
| 1632 | + |
| 1633 | + int maxRetries = args[1].As<Int32>()->Value(); |
| 1634 | + int recursive = args[2]->IsTrue(); |
| 1635 | + int retryDelay = args[3].As<Int32>()->Value(); |
| 1636 | + |
| 1637 | + // File is a directory and recursive is false |
| 1638 | + if (file_status.type() == std::filesystem::file_type::directory && |
| 1639 | + !recursive) { |
| 1640 | + return THROW_ERR_FS_EISDIR( |
| 1641 | + isolate, "Path is a directory: %s", file_path.c_str()); |
| 1642 | + } |
| 1643 | + |
| 1644 | + // Allowed errors are: |
| 1645 | + // - EBUSY: std::errc::device_or_resource_busy |
| 1646 | + // - EMFILE: std::errc::too_many_files_open |
| 1647 | + // - ENFILE: std::errc::too_many_files_open_in_system |
| 1648 | + // - ENOTEMPTY: std::errc::directory_not_empty |
| 1649 | + // - EPERM: std::errc::operation_not_permitted |
| 1650 | + auto can_omit_error = [](std::error_code error) -> bool { |
| 1651 | + return (error == std::errc::device_or_resource_busy || |
| 1652 | + error == std::errc::too_many_files_open || |
| 1653 | + error == std::errc::too_many_files_open_in_system || |
| 1654 | + error == std::errc::directory_not_empty || |
| 1655 | + error == std::errc::operation_not_permitted); |
| 1656 | + }; |
| 1657 | + |
| 1658 | + while (maxRetries >= 0) { |
| 1659 | + if (recursive) { |
| 1660 | + std::filesystem::remove_all(file_path, error); |
| 1661 | + } else { |
| 1662 | + std::filesystem::remove(file_path, error); |
| 1663 | + } |
| 1664 | + |
| 1665 | + if (!error || error == std::errc::no_such_file_or_directory) { |
| 1666 | + return; |
| 1667 | + } else if (!can_omit_error(error)) { |
| 1668 | + break; |
| 1669 | + } |
| 1670 | + |
| 1671 | + if (retryDelay != 0) { |
| 1672 | + sleep(retryDelay / 1000); |
| 1673 | + } |
| 1674 | + maxRetries--; |
| 1675 | + } |
| 1676 | + |
| 1677 | + if (error == std::errc::operation_not_permitted) { |
| 1678 | + std::string message = "Operation not permitted: " + file_path.string(); |
| 1679 | + return env->ThrowErrnoException( |
| 1680 | + EPERM, "rm", message.c_str(), file_path.c_str()); |
| 1681 | + } else if (error == std::errc::directory_not_empty) { |
| 1682 | + std::string message = "Directory not empty: " + file_path.string(); |
| 1683 | + return env->ThrowErrnoException( |
| 1684 | + EACCES, "rm", message.c_str(), file_path.c_str()); |
| 1685 | + } else if (error == std::errc::not_a_directory) { |
| 1686 | + std::string message = "Not a directory: " + file_path.string(); |
| 1687 | + return env->ThrowErrnoException( |
| 1688 | + ENOTDIR, "rm", message.c_str(), file_path.c_str()); |
| 1689 | + } else if (error == std::errc::permission_denied) { |
| 1690 | + std::string message = "Permission denied: " + file_path.string(); |
| 1691 | + return env->ThrowErrnoException( |
| 1692 | + EACCES, "rm", message.c_str(), file_path.c_str()); |
| 1693 | + } |
| 1694 | + |
| 1695 | + std::string message = "Unknown error: " + error.message(); |
| 1696 | + return env->ThrowErrnoException( |
| 1697 | + UV_UNKNOWN, "rm", message.c_str(), file_path.c_str()); |
| 1698 | +} |
| 1699 | + |
1608 | 1700 | int MKDirpSync(uv_loop_t* loop, |
1609 | 1701 | uv_fs_t* req, |
1610 | 1702 | const std::string& path, |
@@ -3323,6 +3415,7 @@ static void CreatePerIsolateProperties(IsolateData* isolate_data, |
3323 | 3415 | SetMethod(isolate, target, "rename", Rename); |
3324 | 3416 | SetMethod(isolate, target, "ftruncate", FTruncate); |
3325 | 3417 | SetMethod(isolate, target, "rmdir", RMDir); |
| 3418 | + SetMethod(isolate, target, "rmSync", RmSync); |
3326 | 3419 | SetMethod(isolate, target, "mkdir", MKDir); |
3327 | 3420 | SetMethod(isolate, target, "readdir", ReadDir); |
3328 | 3421 | SetFastMethod(isolate, |
@@ -3447,6 +3540,7 @@ void RegisterExternalReferences(ExternalReferenceRegistry* registry) { |
3447 | 3540 | registry->Register(Rename); |
3448 | 3541 | registry->Register(FTruncate); |
3449 | 3542 | registry->Register(RMDir); |
| 3543 | + registry->Register(RmSync); |
3450 | 3544 | registry->Register(MKDir); |
3451 | 3545 | registry->Register(ReadDir); |
3452 | 3546 | registry->Register(InternalModuleStat); |
|
0 commit comments