Import photographs from a card
Distinct from a scan, and the distinction is the whole reason the crate exists: a scan catalogues files where they already are, where an import moves them from a card into the library. A scan that fails halfway has read nothing; an import that fails halfway has written something. So the failure paths are the design. Bytes stream at 1 MiB and are hashed on the way past, so an 80 MB RAW never sits in memory. The second destination (FR-CAT-10's backup copy) is written from the same read rather than copied from the primary afterwards — a backup made by re-reading the primary would inherit a bad write rather than catch it, and re-reading the card doubles the wear on the one copy that still exists. Verification re-reads the destination, because hashing what is still in memory would pass on a full disk, a dying card and a truncated write alike. Anything that fails past the point of creating the file takes the file back, or the next scan catalogues a truncated RAW as though it were fine. Three things the crate refuses to know. It never deletes from the card: a move-import records what is now redundant and a separate retire() does the deleting, because on a syncing library "safe" means the upload was confirmed (FR-NC-7b). It does not decode, so capture metadata arrives through a probe and a card of unreadable files costs no demosaic. And it does not know what a duplicate is, since that is a catalog query — FR-CAT-11's two tiers arrive as one closure asked twice, once before any transfer and once with the digest. Camera serial would be the stronger metadata key and is absent, because nothing in the tree reads it yet; make and model plus capture time and the original filename is what is available, and the digest tier covers the gap. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
[package]
|
||||
name = "dr-ingest"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
||||
[dependencies]
|
||||
dr-types.workspace = true
|
||||
# The `Storage` and `WritableStorage` traits. An import reads a real card and
|
||||
# writes a real destination, and this is how `core/` reaches the platform
|
||||
# without a `#[cfg(target_os)]` of its own (ARCH §4.1) — the same dependency
|
||||
# `dr-catalog` takes, for the same reason.
|
||||
dr-plat.workspace = true
|
||||
thiserror.workspace = true
|
||||
log.workspace = true
|
||||
|
||||
# Content hashing: copy verification (FR-CAT-10) and the second duplicate tier
|
||||
# (FR-CAT-11). Pure Rust, no C, so it cross-compiles under the NDK like every
|
||||
# other choice in this tree — and it is already in the lock file as a
|
||||
# transitive dependency, so it costs no new build.
|
||||
#
|
||||
# SHA-256 rather than a fast non-cryptographic hash, which would be sufficient
|
||||
# for verifying a copy: the digest is *stored* and compared across devices and
|
||||
# across years, so it wants to be a named standard someone can recompute with
|
||||
# `sha256sum` rather than whatever we happened to implement.
|
||||
sha2 = "0.10"
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger.workspace = true
|
||||
Reference in New Issue
Block a user