Skip to content

Commit 70c037c

Browse files
committed
fs: fix unhandled busy errors in rmSync
This fixes the unhandled busy errors in rmSync in the symlink_status call, because the allowed/retryable errors in rmSync could be thrown as early as symlink_status call, but it is only handled in the remove/remove_all calls and can only be retried from there This also fixes overridden errors that might happen in the symlink_status right before the remove/remove_all calls, that might mask the true cause of the error happening in rmSync Refs: #55555 Signed-off-by: louiellan <louie.lou.llaneta@gmail.com>
1 parent e775989 commit 70c037c

File tree

1 file changed

+54
-30
lines changed

1 file changed

+54
-30
lines changed

src/node_file.cc

Lines changed: 54 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1760,19 +1760,10 @@ static void RmSync(const FunctionCallbackInfo<Value>& args) {
17601760
std::error_code error;
17611761
auto file_status = std::filesystem::symlink_status(file_path, error);
17621762

1763-
if (file_status.type() == std::filesystem::file_type::not_found) {
1764-
return;
1765-
}
1766-
17671763
int maxRetries = args[1].As<Int32>()->Value();
17681764
int recursive = args[2]->IsTrue();
17691765
int retryDelay = args[3].As<Int32>()->Value();
1770-
1771-
// File is a directory and recursive is false
1772-
if (file_status.type() == std::filesystem::file_type::directory &&
1773-
!recursive) {
1774-
return THROW_ERR_FS_EISDIR(isolate, "Path is a directory: %s", path);
1775-
}
1766+
int i = 1;
17761767

17771768
// Allowed errors are:
17781769
// - EBUSY: std::errc::device_or_resource_busy
@@ -1788,30 +1779,63 @@ static void RmSync(const FunctionCallbackInfo<Value>& args) {
17881779
error == std::errc::operation_not_permitted);
17891780
};
17901781

1791-
int i = 1;
1792-
1793-
while (maxRetries >= 0) {
1794-
if (recursive) {
1795-
std::filesystem::remove_all(file_path, error);
1796-
} else {
1797-
std::filesystem::remove(file_path, error);
1782+
if (error && can_omit_error(error)) { // on std::filesystem::symlink_status
1783+
while (maxRetries >= 0) {
1784+
file_status = std::filesystem::symlink_status(file_path, error);
1785+
if (!error || !can_omit_error(error)) {
1786+
break;
1787+
}
1788+
if (can_omit_error(error)) {
1789+
if (retryDelay > 0) {
1790+
#ifdef WIN32
1791+
Sleep(i * retryDelay);
1792+
#else
1793+
sleep(i * retryDelay / 1000);
1794+
#endif
1795+
}
1796+
}
1797+
maxRetries--;
1798+
i++;
17981799
}
1800+
}
17991801

1800-
if (!error || error == std::errc::no_such_file_or_directory) {
1801-
return;
1802-
} else if (!can_omit_error(error)) {
1803-
break;
1804-
}
1802+
if (file_status.type() == std::filesystem::file_type::not_found) {
1803+
return;
1804+
}
18051805

1806-
if (retryDelay > 0) {
1807-
#ifdef _WIN32
1808-
Sleep(i * retryDelay / 1000);
1809-
#else
1810-
sleep(i * retryDelay / 1000);
1811-
#endif
1806+
// File is a directory and recursive is false
1807+
if (file_status.type() == std::filesystem::file_type::directory &&
1808+
!recursive) {
1809+
return THROW_ERR_FS_EISDIR(isolate, "Path is a directory: %s", path);
1810+
}
1811+
1812+
// We could only do this operation if there's no errors in symlink_status()
1813+
// as the operations here might override the true cause of the error caused
1814+
// by symlink_status
1815+
if (!error) {
1816+
while (maxRetries >= 0) {
1817+
if (recursive) {
1818+
std::filesystem::remove_all(file_path, error);
1819+
} else {
1820+
std::filesystem::remove(file_path, error);
1821+
}
1822+
1823+
if (!error || error == std::errc::no_such_file_or_directory) {
1824+
return;
1825+
} else if (!can_omit_error(error)) {
1826+
break;
1827+
}
1828+
1829+
if (retryDelay > 0) {
1830+
#ifdef _WIN32
1831+
Sleep(i * retryDelay);
1832+
#else
1833+
sleep(i * retryDelay / 1000);
1834+
#endif
1835+
}
1836+
maxRetries--;
1837+
i++;
18121838
}
1813-
maxRetries--;
1814-
i++;
18151839
}
18161840

18171841
// On Windows path::c_str() returns wide char, convert to std::string first.

0 commit comments

Comments
 (0)