From d9fdd267027d6bf3b8265c18279a7f50c2b62081 Mon Sep 17 00:00:00 2001 From: chenjiayi Date: Wed, 21 Jun 2023 21:27:38 +0800 Subject: [PATCH] feature(libbasic): add remove_dir_until remove_dir_until is used to recursively remove parent directories which contains nothing until specific directory. --- libs/basic/src/fs_util.rs | 64 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 62 insertions(+), 2 deletions(-) diff --git a/libs/basic/src/fs_util.rs b/libs/basic/src/fs_util.rs index 63c43ca..5f34e9a 100644 --- a/libs/basic/src/fs_util.rs +++ b/libs/basic/src/fs_util.rs @@ -20,7 +20,7 @@ use nix::{ unistd::{Gid, Uid}, }; use pathdiff::diff_paths; -use std::{os::unix::prelude::PermissionsExt, path::Path}; +use std::{fs::remove_dir, io::ErrorKind, os::unix::prelude::PermissionsExt, path::Path}; /// open the parent directory of path pub fn open_parent(path: &Path, flags: OFlag, mode: Mode) -> Result { @@ -164,12 +164,55 @@ pub fn futimens_opath(fd: i32, ts: Option<[timespec; 2]>) -> Result<()> { } } +/// recursively remove parent directories until specific directory +pub fn remove_dir_until(path: &str, stop: &str) -> Result<()> { + let path = Path::new(path); + + let mut dir = if path.is_dir() { + Path::new(path) + } else { + match path.parent() { + Some(p) => p, + None => { + return Ok(()); + } + } + }; + + loop { + if let Err(e) = remove_dir(dir) { + match e.kind() { + ErrorKind::NotFound => break, + _ => { + return Err(Error::Io { source: e }); + } + } + } + + match dir.parent() { + Some(p) => { + if p.ends_with(stop) { + break; + } + dir = p; + } + None => break, + }; + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; use crate::fs_util::symlink; use nix::unistd::{self}; - use std::{fs::File, os::unix::prelude::MetadataExt, time::SystemTime}; + use std::{ + fs::{create_dir_all, File}, + os::unix::prelude::MetadataExt, + time::SystemTime, + }; #[test] fn test_symlink() { @@ -267,4 +310,21 @@ mod tests { std::fs::remove_file("/tmp/test_futimens_opath").unwrap(); } + + #[test] + fn test_remove_dir_until() { + create_dir_all("/tmp/test_remove_dir_until_1/test1").unwrap(); + assert!(Path::new("/tmp/test_remove_dir_until_1/test1").exists()); + remove_dir_until("/tmp/test_remove_dir_until_1/test1", "/tmp").unwrap(); + assert!(!Path::new("/tmp/test_remove_dir_until_1/test1").exists()); + assert!(!Path::new("/tmp/test_remove_dir_until_1").exists()); + + create_dir_all("/tmp/test_remove_dir_until_2/test2").unwrap(); + File::create("/tmp/test_remove_dir_until_2/test_file").unwrap(); + assert!(Path::new("/tmp/test_remove_dir_until_2/test2").exists()); + assert!(Path::new("/tmp/test_remove_dir_until_2/test_file").exists()); + assert!(remove_dir_until("/tmp/test_remove_dir_until_2/test2", "/tmp").is_err()); + assert!(!Path::new("/tmp/test_remove_dir_until_2/test2").exists()); + assert!(Path::new("/tmp/test_remove_dir_until_2/test_file").exists()); + } } -- 2.33.0