in src/client/trash_cleaner/src/main.rs [384:497]
fn scan_trash<P: AsRef<Path>>(trash_root: &P) -> nix::Result<()> {
let trash_root = trash_root.as_ref();
let mut dir = Dir::open(
trash_root,
OFlag::O_DIRECTORY | OFlag::O_RDONLY,
nix::sys::stat::Mode::empty(),
)
.map_err(|err| {
error!("open trash root {:?} failed, {}", trash_root, err);
err
})?;
let dir_fd = dir.as_raw_fd();
let dir_stat = nix::sys::stat::fstat(dir_fd)?;
if dir_stat.st_uid != 0 || dir_stat.st_gid != 0 {
error!(
"trash root {:?} is not owned by root user, {}:{}",
trash_root, dir_stat.st_uid, dir_stat.st_gid
);
abort();
}
for entry in dir.iter() {
let entry = entry.map_err(|err| {
error!("scan trash root {:?} failed, {}", trash_root, err);
err
})?;
let entry_name = match entry.file_name().to_str() {
Ok(name) => name,
Err(err) => {
error!(
"trash directory name {:?} is not utf8, {}",
entry.file_name(),
err
);
continue;
}
};
if entry_name == "." || entry_name == ".." {
continue;
}
let entry_stat = match nix::sys::stat::fstatat(
Some(dir_fd),
entry.file_name(),
nix::fcntl::AtFlags::AT_SYMLINK_NOFOLLOW,
) {
Ok(stat) => stat,
Err(err) => {
error!(
"stat trash direstory {:?} failed, {}",
entry.file_name(),
err
);
continue;
}
};
if !nix::sys::stat::SFlag::from_bits_truncate(entry_stat.st_mode)
.contains(nix::sys::stat::SFlag::S_IFDIR)
{
error!("trash directory {:?} is not directory", entry.file_name());
continue;
}
if entry_stat.st_uid == 0 || entry_stat.st_gid == 0 {
error!("trash directory {:?} owned by root user", entry.file_name());
continue;
}
// create user context
let _user_ctx = UserContext::new(
Uid::from_raw(entry_stat.st_uid),
Gid::from_raw(entry_stat.st_gid),
);
// open trash
let trash = match Trash::open(entry_stat.st_uid, entry_name, trash_root.join(entry_name)) {
Ok(trash) => trash,
Err(errno) => {
error!(
"open trash directory {:?} failed, errno {}",
entry_name, errno
);
continue;
}
};
// clean trash
match trash.clean(false) {
Ok(n) => {
if n > 0 {
info!(
"clean trash directory {} success, cleaned {} item",
entry_name, n
);
} else {
trace!(
"clean trash directory {} success, cleaned {} item",
entry_name,
n
);
}
}
Err(errno) => {
error!(
"clean trash directory {} failed, errno {}",
entry_name, errno
);
}
}
}
Ok(())
}