1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
//! FerroCrypt Archive (FCA) — native archive payload format.
//!
//! Full wire-format spec: `ferrocrypt-lib/FORMAT.md` §9.
pub
pub
pub
pub
pub
pub
pub
pub
pub
pub use ArchiveLimits;
pub
pub use unarchive;
pub use archive;
pub use ;
pub use PERMISSION_BITS_MASK;
/// Policy for the `.incomplete` working tree when decrypt fails.
///
/// During decryption the archive is staged under
/// `{output_dir}/{root_name}.incomplete` and atomically renamed to
/// `{output_dir}/{root_name}` only after every authentication and
/// validation check has passed. This policy controls what happens to
/// the staged tree when a decrypt error occurs *before* that rename:
/// payload AEAD failure on a later chunk, archive structural reject
/// (manifest tree-shape failure, path-grammar reject, duplicate
/// detection), trailing-bytes reject, or a final-name collision
/// discovered at promotion time.
///
/// [`Self::DeleteOnError`] is the default. Before commit, it avoids leaving
/// authenticated-but-incomplete plaintext that an unaware caller could pick
/// up. The post-commit exceptions are described below.
///
/// Three reports can occur *after* the output became visible at the final
/// name. The staged record leaves the cleanup slot as soon as the run
/// establishes that the entry there is its own — at the root-mode step where
/// the identity confirms it, otherwise at the final-name check that follows —
/// so this policy never removes a committed output:
///
/// - The final name no longer denotes the entry the run staged. The
/// decrypt returns `Err` and FerroCrypt does not remove the committed
/// object. If another writer moved it, it remains under that writer's chosen
/// name; an entry placed at the final name is also left alone. The check runs
/// on every supported platform, and is skipped only where the filesystem
/// supplies no identity to compare.
/// - The destination directory path no longer denotes the directory used for
/// the commit. The decrypt returns `Err` and does not remove the confirmed
/// output by name. If the directory was renamed, the complete plaintext is
/// under that new name. This check runs on the same terms. A check that
/// cannot run for a reason other than running out of open files or memory
/// also returns `Err`, and the error says that the output is complete.
/// - A committed file root carries more than one name. The count is read
/// through the retained handle for every file root, on every supported
/// platform and whatever route committed the name: a local writer can link
/// the staged plaintext before the commit, and that link survives it. A
/// hard-link fallback can also leave its staging name behind, or have its
/// removal reach the wrong entry. The decrypt returns `Err`, preserves the
/// complete commit and any additional name, and never withdraws the final
/// name after cleanup uncertainty.
///
/// A run that cannot hold a handle to the staged root fails before
/// writing any plaintext, so a low open-file limit leaves at most an
/// empty staged entry — which the removal may not be able to take
/// away either, needing a descriptor of its own; the returned error
/// then says so. A retry reports `Incomplete output already exists`.
///
/// [`Self::RetainOnError`] is the opt-in for backup-recovery and
/// forensic flows where partial plaintext is more useful than no
/// plaintext.
///
/// The enum is `#[non_exhaustive]` so future releases can add richer
/// recovery policies. It deliberately does not implement `Copy`: such a
/// policy is configuration, and one may need to carry owned data — a
/// destination directory for retained partial output, for example.
///
/// Note: this policy only governs cleanup of the `.incomplete` working
/// tree after a normal `Err` return. Process termination (crash, SIGKILL,
/// power loss) and panic unwinding bypass cleanup entirely, so a killed
/// or panicking process can leave `.incomplete` output regardless of the
/// policy. The library does not wrap extraction in `catch_unwind`; if a
/// panic propagates out of `unarchive`, treat the working tree as if the
/// process had been killed. It may contain authenticated but incomplete
/// plaintext that the caller must inspect or remove explicitly.