#app-dirs #path #no-alloc #known-folders

no-std sysdir

Rust bindings to sysdir(3) on macOS, iOS, tvOS, and watchOS

9 stable releases

Uses new Rust 2024

1.3.3 Mar 30, 2026
1.3.2 Mar 17, 2026
1.3.1 Feb 22, 2026
1.3.0 Jun 19, 2025
1.2.1 May 14, 2023

#37 in macOS and iOS APIs

Apache-2.0 OR MIT

18KB
210 lines

sysdir-rs

GitHub Actions Twitter
Crate API API trunk

Enumeration of the filesystem paths for the various standard system directories where apps, resources, etc. get installed.

This crate exposes Rust bindings to the sysdir(3) library functions provided by libSystem.dylib on macOS, iOS, tvOS, and watchOS.

The sysdir API first appeared in OS X 10.12, iOS 10, watchOS 3 and tvOS 10 replacing the deprecated NSSystemDirectories(3) API.

Usage

Add this to your Cargo.toml:

[dependencies]
sysdir = "1.3.3"

Then resolve well-known directories like this:

use core::ffi::{c_char, CStr};

use sysdir::*;

let mut path = [0; PATH_MAX as usize];

let dir = sysdir_search_path_directory_t::SYSDIR_DIRECTORY_USER;
let domain_mask = SYSDIR_DOMAIN_MASK_LOCAL;

unsafe {
    let mut state = sysdir_start_search_path_enumeration(dir, domain_mask);
    loop {
        let path = path.as_mut_ptr().cast::<c_char>();
        state = sysdir_get_next_search_path_enumeration(state, path);
        if state == 0 {
            break;
        }
        let path = CStr::from_ptr(path);
        let bytes = path.to_bytes();
        assert!(bytes.ends_with(b"/Users"));
    }
}

sysdir-rs exposes raw sysdir(3) search-path strings from Darwin. Those values are not always normalized filesystem paths:

  • user-domain results may contain a literal ~ instead of an expanded home directory
  • if NEXT_ROOT is set and honored by the process, many local, network, and system-domain results are prefixed by that directory
  • returned values are not guaranteed to be UTF-8 if NEXT_ROOT contains non-UTF-8 bytes

If you intend to use returned values with filesystem APIs, expand ~, account for NEXT_ROOT, and validate UTF-8 before opening or creating files.

You can test this crate works on your platform by running the example:

cargo run --example enumerate_system_dirs

Development

sysdir-rs uses mise to manage its local development toolchain. Install mise, then install the tools declared in mise.toml:

mise install

mise.toml installs Node.js, Python, Ruby, stable Rust with clippy and rustfmt, uv, cargo-deny, zizmor, and the bindgen CLI used to regenerate src/sys.rs.

Install the repository-local Node.js and Ruby dependencies with:

npm ci
bundle install

YAML linting runs through uv:

uv run yamllint --strict --format github .

rake doc still uses rustup run --install nightly cargo doc --workspace to install nightly Rust on demand for documentation builds.

Implementation

sysdir-rs binds directly to libSystem with vendored bindings generated by bindgen. This crate has no dependencies other than libSystem.

Note that this crate is completely empty on non-Apple platforms.

no_std

sysdir-rs is no_std and only requires core.

Minimum Supported Rust Version

This crate requires at least Rust 1.85.0. This version can be bumped in minor releases.

License

sysdir-rs is distributed under the terms of either the MIT License or the Apache License (Version 2.0).

No runtime deps