Skip to main content

FileBackend

Struct FileBackend 

Source
pub struct FileBackend { /* private fields */ }
Expand description

Filesystem-backed keychain.

Thread-safe — KeychainBackend is Send + Sync, and all operations use OS-level atomic primitives (rename, unlink). Multiple FileBackend instances pointing at the same root directory coexist without mutual serialization; the tmp-file names include a random suffix so concurrent writes to the same BackendKey do not step on each other’s tmp files.

§Example

use std::sync::Arc;
use dig_keystore::{
    backend::{FileBackend, BackendKey, KeychainBackend},
};

let backend: Arc<dyn KeychainBackend> = Arc::new(
    FileBackend::new("/var/lib/dig/keys")
);
backend.write(&BackendKey::new("v1"), b"...").unwrap();

Implementations§

Source§

impl FileBackend

Source

pub fn new(root: impl Into<PathBuf>) -> Self

Create a new file backend rooted at root.

The directory is not created immediately — it is lazily created on the first write call (with mode 0700 on Unix). This lets callers construct a FileBackend in tests without side effects; no files are written until the first write.

§Example
use dig_keystore::backend::FileBackend;
let be = FileBackend::new("/var/lib/dig/keys");
let _ = be;  // directory not created yet
Source

pub fn root(&self) -> &Path

The root directory this backend writes to.

Trait Implementations§

Source§

impl KeychainBackend for FileBackend

Source§

fn read(&self, key: &BackendKey) -> Result<Vec<u8>>

Read the entire file at <root>/<key>.dks.

Returns KeystoreError::Backend wrapping an io::Error with ErrorKind::NotFound if the file does not exist.

Source§

fn write(&self, key: &BackendKey, data: &[u8]) -> Result<()>

Atomically write data to <root>/<key>.dks.

Steps:

  1. Ensure root exists.
  2. Create sibling <key>.dks.tmp.<random> file, mode 0600 on Unix.
  3. Write data, fsync the file handle.
  4. rename the tmp file onto the final name.
  5. On Unix, fsync the containing directory so the rename is durable.
  6. On error in step 4, best-effort unlink the tmp file.

The random suffix in step 2 is not cryptographic — it exists only to disambiguate two concurrent writes to the same key from the same process. Uses a hash of (nanoseconds_since_epoch, pid).

Source§

fn delete(&self, key: &BackendKey) -> Result<()>

Best-effort secure delete, then unlink.

Steps:

  1. No-op if file does not exist (idempotent).
  2. Open the file for writing; overwrite with zeros in 4 KiB chunks.
  3. fsync the overwritten file so zeros hit storage.
  4. unlink the file.

Step 2 is best-effort. On SSDs with flash translation layer or on copy-on-write filesystems (btrfs, ZFS), the zero pass may not reach the sectors that held the ciphertext. Use full-disk encryption for stronger guarantees.

Source§

fn list(&self, prefix: &str) -> Result<Vec<BackendKey>>

Enumerate keys whose names start with prefix.

Scans the root directory; skips any file that:

  • does not end in .dks
  • has a non-UTF-8 name
  • does not start with prefix

Returns an empty vec if the root directory does not exist.

Source§

fn exists(&self, key: &BackendKey) -> Result<bool>

Cheap override — Path::exists stats without opening the file.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.