@@ -1234,25 +1234,150 @@ static void Unlink(const FunctionCallbackInfo<Value>& args) {
12341234 }
12351235}
12361236
1237+ int RMDirrSync (uv_loop_t * loop, uv_fs_t * req, const std::string& path,
1238+ uv_fs_cb cb = nullptr ) {
1239+ FSContinuationData continuation_data (req, 0 , cb);
1240+ continuation_data.PushPath (std::move (path));
1241+
1242+ while (continuation_data.paths .size () > 0 ) {
1243+ std::string next_path = continuation_data.PopPath ();
1244+ int err = uv_fs_rmdir (loop, req, next_path.c_str (), nullptr );
1245+ switch (err) {
1246+ case 0 :
1247+ if (continuation_data.paths .size () == 0 ) {
1248+ return 0 ;
1249+ }
1250+ break ;
1251+ case UV_ENOTEMPTY : {
1252+ uv_fs_scandir (loop, req, next_path.c_str (), 0 , nullptr );
1253+
1254+ uv_dirent_t entry;
1255+ uv_fs_scandir_next (req, &entry);
1256+
1257+ std::string dirname (next_path + ' /' + entry.name );
1258+ if (next_path != dirname) {
1259+ continuation_data.PushPath (std::move (next_path));
1260+ continuation_data.PushPath (std::move (dirname));
1261+ } else if (continuation_data.paths .size () == 0 ) {
1262+ err = UV_EEXIST ;
1263+ }
1264+ break ;
1265+ }
1266+ case UV_ENOTDIR : {
1267+ uv_fs_unlink (loop, req, next_path.c_str (), nullptr );
1268+ break ;
1269+ }
1270+ case UV_EPERM : {
1271+ return err;
1272+ }
1273+ default :
1274+ uv_fs_req_cleanup (req);
1275+ break ;
1276+ }
1277+ uv_fs_req_cleanup (req);
1278+ }
1279+
1280+ return 0 ;
1281+ }
1282+
1283+ int RMDirrAsync (uv_loop_t * loop,
1284+ uv_fs_t * req,
1285+ const char * path,
1286+ uv_fs_cb cb) {
1287+ FSReqBase* req_wrap = FSReqBase::from_req (req);
1288+ // on the first iteration of algorithm, stash state information.
1289+ if (req_wrap->continuation_data == nullptr ) {
1290+ req_wrap->continuation_data = std::unique_ptr<FSContinuationData>{
1291+ new FSContinuationData (req, 0 , cb)};
1292+ req_wrap->continuation_data ->PushPath (std::move (path));
1293+ }
1294+
1295+ std::string next_path = req_wrap->continuation_data ->PopPath ();
1296+ int err = uv_fs_rmdir (loop, req, next_path.c_str (),
1297+ uv_fs_callback_t {[](uv_fs_t * req) {
1298+ FSReqBase* req_wrap = FSReqBase::from_req (req);
1299+ Environment* env = req_wrap->env ();
1300+ uv_loop_t * loop = env->event_loop ();
1301+ std::string path = req->path ;
1302+ int err = req->result ;
1303+ switch (err) {
1304+ case 0 : {
1305+ if (req_wrap->continuation_data ->paths .size () == 0 ) {
1306+ req_wrap->continuation_data ->Done (0 );
1307+ } else {
1308+ uv_fs_req_cleanup (req);
1309+ RMDirrAsync (loop, req, path.c_str (), nullptr );
1310+ }
1311+ break ;
1312+ }
1313+ case UV_ENOTEMPTY : {
1314+ uv_fs_req_cleanup (req);
1315+ uv_fs_scandir (loop, req, path.c_str (), 0 , nullptr );
1316+
1317+ uv_dirent_t entry;
1318+ uv_fs_scandir_next (req, &entry);
1319+
1320+ std::string dirname (path + ' /' + entry.name );
1321+ if (dirname != path) {
1322+ req_wrap->continuation_data ->PushPath (std::move (path));
1323+ req_wrap->continuation_data ->PushPath (std::move (dirname));
1324+ } else if (req_wrap->continuation_data ->paths .size () == 0 ) {
1325+ err = UV_EEXIST ;
1326+ break ;
1327+ }
1328+ uv_fs_req_cleanup (req);
1329+ RMDirrAsync (loop, req, path.c_str (), nullptr );
1330+ break ;
1331+ }
1332+ case UV_ENOTDIR : {
1333+ uv_fs_req_cleanup (req);
1334+ uv_fs_unlink (loop, req, path.c_str (), nullptr );
1335+ RMDirrAsync (loop, req, path.c_str (), nullptr );
1336+ break ;
1337+ }
1338+ case UV_EPERM : {
1339+ req_wrap->continuation_data ->Done (err);
1340+ break ;
1341+ }
1342+ default :
1343+ if (req_wrap->continuation_data ->paths .size () > 0 ) {
1344+ uv_fs_req_cleanup (req);
1345+ RMDirrAsync (loop, req, path.c_str (), nullptr );
1346+ }
1347+ break ;
1348+ }
1349+ }});
1350+
1351+ return err;
1352+ }
1353+
12371354static void RMDir (const FunctionCallbackInfo<Value>& args) {
12381355 Environment* env = Environment::GetCurrent (args);
12391356
12401357 const int argc = args.Length ();
1241- CHECK_GE (argc, 2 );
1358+ CHECK_GE (argc, 3 );
12421359
12431360 BufferValue path (env->isolate (), args[0 ]);
12441361 CHECK_NOT_NULL (*path);
12451362
1246- FSReqBase* req_wrap_async = GetReqWrap (env, args[1 ]); // rmdir(path, req)
1363+ CHECK (args[1 ]->IsBoolean ());
1364+ bool recursive = args[1 ]->IsTrue ();
1365+
1366+ FSReqBase* req_wrap_async = GetReqWrap (env, args[2 ]); // rmdir(path, req)
12471367 if (req_wrap_async != nullptr ) {
12481368 AsyncCall (env, req_wrap_async, args, " rmdir" , UTF8 , AfterNoArgs,
1249- uv_fs_rmdir, *path);
1369+ recursive ? RMDirrAsync : uv_fs_rmdir, *path);
12501370 } else { // rmdir(path, undefined, ctx)
1251- CHECK_EQ (argc, 3 );
1371+ CHECK_EQ (argc, 4 );
12521372 FSReqWrapSync req_wrap_sync;
12531373 FS_SYNC_TRACE_BEGIN (rmdir);
1254- SyncCall (env, args[2 ], &req_wrap_sync, " rmdir" ,
1255- uv_fs_rmdir, *path);
1374+ if (recursive) {
1375+ SyncCall (env, args[3 ], &req_wrap_sync, " rmdir" ,
1376+ RMDirrSync, *path);
1377+ } else {
1378+ SyncCall (env, args[3 ], &req_wrap_sync, " rmdir" ,
1379+ uv_fs_rmdir, *path);
1380+ }
12561381 FS_SYNC_TRACE_END (rmdir);
12571382 }
12581383}
0 commit comments