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
impl FileBackend
Sourcepub fn new(root: impl Into<PathBuf>) -> Self
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 yetTrait Implementations§
Source§impl KeychainBackend for FileBackend
impl KeychainBackend for FileBackend
Source§fn read(&self, key: &BackendKey) -> Result<Vec<u8>>
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<()>
fn write(&self, key: &BackendKey, data: &[u8]) -> Result<()>
Atomically write data to <root>/<key>.dks.
Steps:
- Ensure
rootexists. - Create sibling
<key>.dks.tmp.<random>file, mode0600on Unix. - Write
data,fsyncthe file handle. renamethe tmp file onto the final name.- On Unix,
fsyncthe containing directory so the rename is durable. - 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<()>
fn delete(&self, key: &BackendKey) -> Result<()>
Best-effort secure delete, then unlink.
Steps:
- No-op if file does not exist (idempotent).
- Open the file for writing; overwrite with zeros in 4 KiB chunks.
fsyncthe overwritten file so zeros hit storage.unlinkthe 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.