<p align="center">
  <img src="logo.png" alt="" width="300"/>
</p>

<h1 align="center">💥 Obliterate - Force Removal on Linux</h1>
<h3 align="center">Force-remove Files and Directories on Linux Including Paths with 000 Permissions.</h3>

<p align="center">
    <img src="https://img.shields.io/badge/Platform-POSIX-FCC624?&logo=linux&style=flat-square"/>
    <img src="https://img.shields.io/github/actions/workflow/status/LinuxProativo/obliterate/rust.yml?label=Test&style=flat-square&logo=github"/>
    <img src="https://img.shields.io/badge/RustC-1.85+-orange?style=flat-square&logo=rust"/>
    <img src="https://img.shields.io/github/languages/code-size/LinuxProativo/obliterate?style=flat-square&logo=rust&label=Code%20Size"/>
</p>

## 🔍 Overview

`obliterate` is a **Linux-only Rust crate** designed to aggressively and safely
remove files and directories — even in scenarios where traditional tools fail.
It handles edge cases like `000` permissions, nested mount points, and deeply
recursive trees without stack overflows.

Unlike traditional approaches, this crate:

- Fixes permissions automatically before deletion;
- Detects and lazily unmounts nested mount points;
- Avoids dangerous path patterns like `..`;
- Uses controlled recursion with stack growth protection;

## 🚀 Features

* 🔒 **Handles `000` permissions**  
  removes trees that `std::fs::remove_dir_all` cannot.

* 🧩 **Mount-point aware**  
  lazily unmounts nested filesystems before deleting.

* 🧱 **Stack-safe recursion**  
  uses `stacker` to safely handle deeply nested trees.

* 🛡️ **Basic safety guards**  
  prevents invalid paths like `..`.

* 📦 **Structured errors**  
  clear error types for invalid targets, I/O failures, and unmount issues.

* 🐧 **Linux-only**  
  relies on `/proc/self/mountinfo` and `umount2`.

## 📖 Usage

This section demonstrates how to integrate and use `obliterate` in your Rust 
project. The crate provides two main entry points:

* `remove` ➜ strict removal (fails if the path does not exist)
* `ensure_removed` ➜ forgiving removal (behaves like `rm -rf`)

Add the dependency to your `Cargo.toml`:

```toml
[dependencies]
obliterate = "1.0"
```

Then use it in your code:

```rust
use obliterate::{remove, ensure_removed, Error};

// Strict removal (fails if not found)
remove("target")?;

// Idempotent removal (like rm -rf)
ensure_removed("build")?;

match remove("some/path") {
    Ok(()) => {}
    Err(Error::NotFound) => eprintln!("already gone"),
    Err(Error::UnmountFailed { path, fstype, reason }) => {
        eprintln!("failed to unmount {} ({}): {}", path.display(), fstype, reason)
    }
    Err(e) => return Err(e.into()),
}
```

### 💡 When to use each function

* Use `remove` when you **expect the path to exist** and want strict error handling.
* Use `ensure_removed` when you want **idempotent cleanup**, especially in build
scripts, CI pipelines, or temporary directory management.

Both functions guarantee safe, race-resistant removal using file-descriptor-based 
operations under the hood.

## ⚙️ How it works

### 🔓 Permission handling

Before deletion, the crate ensures the current process has sufficient
permissions by setting mode `0o700` when necessary. `std::fs::remove_dir_all` fails
on directories with `000` permissions because the kernel checks execute permission
on the directory before allowing iteration.

### 🧷 Mount-point handling

Before touching any directory, `obliterate` reads `/proc/self/mountinfo` and
collects every mount-point nested inside the target tree. They are unmounted
**deepest-first** using a three-tier strategy:

1. `umount2(MNT_DETACH)` via libc
2. `fusermount3 -u -z`
3. `fusermount -u -z`

Mounts are processed **deepest-first** to avoid dependency issues. If unmounting
fails, an error is returned and deletion is aborted.

### 🧵 Recursive removal

The crate recursively deletes files and directories while:

- Fixing permissions
- Avoiding stack overflow via `stacker`
- Handling both files and directories correctly

## ❗ Error variants

```rust
pub enum Error {
    /// Path does not exist (only from `remove`, not `ensure_removed`).
    NotFound,

    /// Path ends in ".." or is otherwise invalid.
    InvalidTarget(String),

    /// OS-level I/O failure, with the path that triggered it.
    IoError(std::io::Error),

    /// A nested mount-point could not be unmounted.
    UnmountFailed {
        path: PathBuf,
        fstype: String,
        reason: String,
    },
}
```

## 🧪 Notes

Some unmount operations may require elevated privileges (`CAP_SYS_ADMIN`).

## 📜 MIT License

This project is licensed under the MIT License.

## 📬 Contact

* 📧 m10ferrari1200@gmail.com
* 📧 contatolinuxdicaspro@gmail.com

