# Path component validation

> Reject hostile tree and worktree path components the same way Git fsck and verify_path do.

# Path component validation

Grit centralizes Git’s path-component rules in [`grit_lib::path_validate`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/index.html). Use it before writing tree entries, populating the index, or checking out files so NTFS/HFS spellings and `.git` aliases cannot slip through.

## Protection options

[`ProtectOptions`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/struct.ProtectOptions.html) mirrors `core.protectNTFS` (default **true**) and `core.protectHFS` (default **true** on macOS, **false** elsewhere). Load them from a merged [`ConfigSet`](https://docs.rs/grit-lib/latest/grit_lib/config/struct.ConfigSet.html):

```rust
use grit_lib::config::ConfigSet;
use grit_lib::path_validate::ProtectOptions;

let opts = ProtectOptions::from_config(&config);
```

Object fsck always enables both flags via [`ProtectOptions::fsck`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/struct.ProtectOptions.html#method.fsck).

## Validating components and paths

[`validate_component`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/fn.validate_component.html) checks a single tree/index segment (no `/` inside). Pass the Git mode and a [`PathValidationKind`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/enum.PathValidationKind.html). Worktree population and checkout use **`Worktree`**. On Windows with `core.protectNTFS` (default), each segment is checked with Git’s `is_valid_win32_path` rules: forbidden characters (`:*?"<>|` and controls), trailing spaces or periods (except `.` and `..`), DOS device names (`CON`, `AUX`, `COM1`, …), plus NTFS drive prefixes and backslash-`.git` spellings. Symlink names reject **`.gitmodules`** on worktree; object fsck uses **`Fsck`** (all four symlink dot-files):

```rust
use grit_lib::path_validate::{validate_component, EntryMode, PathValidationKind, ProtectOptions};

let opts = ProtectOptions::fsck();
validate_component(b"src", EntryMode::new(0o100644), opts, PathValidationKind::Worktree)?;
```

Fsck checks all symlink dot-files (`.gitmodules`, `.gitattributes`, `.gitignore`, `.mailmap`):

```rust
use grit_lib::path_validate::{validate_component, EntryMode, PathValidationKind, ProtectOptions};

let opts = ProtectOptions::fsck();
validate_component(
    b".gitignore",
    EntryMode::new(0o120000),
    opts,
    PathValidationKind::Fsck,
)?;
```

## `.git` aliases

With `core.protectNTFS` on, every platform rejects the NTFS spellings of `.git` for both kinds, because a repository checked out on Linux may later be used from Windows. These are `.git` and its 8.3 short name `git~1` in any case, each optionally followed by spaces and periods (which NTFS strips) or by a `:` stream suffix. Examples are `.git.`, `GIT~1.`, `git~1  ` and `.git::$INDEX_ALLOCATION`. A `\`-separated segment that spells `.git`, such as `.git\config`, is rejected too. System git refuses the same names on Linux, so a hostile tree cannot plant a second `.git` directory through either implementation.

[`validate_path`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/fn.validate_path.html) splits on `/` and validates each segment. [`audit_tree_entry_name`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/fn.audit_tree_entry_name.html) returns a bitmask-style summary for fsck-style reporting when several rules fire on one name.

## Errors

[`PathComponentError`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/enum.PathComponentError.html) is a typed, non-exhaustive enum (empty, `.`, `..`, slash/NUL, ASCII and platform `.git` aliases, NTFS backslash/drive/stream spellings, NTFS illegal characters, trailing space/period, reserved DOS device names, and symlinked dot-files). Checkout and index population return [`Error::InvalidPathComponent`](https://docs.rs/grit-lib/latest/grit_lib/error/enum.Error.html#variant.InvalidPathComponent) with the full path and reason. User-facing `add`/`mv` path arguments use the same typed error; legacy [`Error::InvalidPath`](https://docs.rs/grit-lib/latest/grit_lib/error/enum.Error.html) remains for empty or escaping paths.

## Related

- Tree object fsck uses the same rules via `grit-lib` maintenance APIs.
- Index population, checkout, restore, and `grit add` staging run these validators internally with [`ProtectOptions::from_config`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/struct.ProtectOptions.html#method.from_config). Code that writes its own tree or index entries calls [`validate_path`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/fn.validate_path.html) or [`validate_component`](https://docs.rs/grit-lib/latest/grit_lib/path_validate/fn.validate_component.html) directly.
