fxfs/object_store/object_record/
legacy.rs

1// Copyright 2025 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5//! Contains all legacy data structures and migration code.
6
7use super::*;
8use fxfs_crypto::WrappedKeyBytes;
9
10impl From<ObjectKeyDataV40> for ObjectKeyDataV43 {
11    fn from(item: ObjectKeyDataV40) -> Self {
12        match item {
13            ObjectKeyDataV40::Object => Self::Object,
14            ObjectKeyDataV40::Keys => Self::Keys,
15            ObjectKeyDataV40::Attribute(a, b) => Self::Attribute(a, b),
16            ObjectKeyDataV40::Child { name } => Self::Child { name },
17            ObjectKeyDataV40::GraveyardEntry { object_id } => Self::GraveyardEntry { object_id },
18            ObjectKeyDataV40::Project { project_id, property } => {
19                Self::Project { project_id, property }
20            }
21            ObjectKeyDataV40::ExtendedAttribute { name } => Self::ExtendedAttribute { name },
22            ObjectKeyDataV40::GraveyardAttributeEntry { object_id, attribute_id } => {
23                Self::GraveyardAttributeEntry { object_id, attribute_id }
24            }
25            ObjectKeyDataV40::EncryptedChild { name } => {
26                Self::EncryptedChild { hash_code: 0, name }
27            }
28            ObjectKeyDataV40::CasefoldChild { name } => Self::CasefoldChild { name },
29        }
30    }
31}
32
33#[derive(Serialize, Deserialize, TypeFingerprint)]
34#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
35pub enum ObjectKeyDataV40 {
36    Object,
37    Keys,
38    Attribute(u64, AttributeKeyV32),
39    Child { name: String },
40    GraveyardEntry { object_id: u64 },
41    Project { project_id: u64, property: ProjectPropertyV32 },
42    ExtendedAttribute { name: Vec<u8> },
43    GraveyardAttributeEntry { object_id: u64, attribute_id: u64 },
44    EncryptedChild { name: Vec<u8> },
45    CasefoldChild { name: CasefoldString },
46}
47
48#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
49#[migrate_to_version(ObjectKeyV43)]
50#[migrate_nodefault]
51pub struct ObjectKeyV40 {
52    pub object_id: u64,
53    pub data: ObjectKeyDataV40,
54}
55
56impl From<ObjectKindV46> for ObjectKindV49 {
57    fn from(value: ObjectKindV46) -> Self {
58        match value {
59            ObjectKindV46::File { refs } => Self::File { refs },
60            ObjectKindV46::Directory { sub_dirs, wrapping_key_id, casefold } => Self::Directory {
61                sub_dirs,
62                wrapping_key_id: wrapping_key_id.map(u128::to_le_bytes),
63                casefold,
64            },
65            ObjectKindV46::Graveyard => Self::Graveyard,
66            ObjectKindV46::Symlink { refs, link } => Self::Symlink { refs, link: link.into() },
67            ObjectKindV46::EncryptedSymlink { refs, link } => {
68                Self::EncryptedSymlink { refs, link: link.into() }
69            }
70        }
71    }
72}
73
74#[derive(Serialize, Deserialize, TypeFingerprint)]
75pub enum ObjectKindV46 {
76    File { refs: u64 },
77    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
78    Graveyard,
79    Symlink { refs: u64, link: Vec<u8> },
80    EncryptedSymlink { refs: u64, link: Vec<u8> },
81}
82
83#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
84#[migrate_to_version(ObjectKindV46)]
85pub enum ObjectKindV41 {
86    File { refs: u64 },
87    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
88    Graveyard,
89    Symlink { refs: u64, link: Vec<u8> },
90}
91
92#[derive(Serialize, Deserialize, TypeFingerprint)]
93pub enum ObjectKindV40 {
94    File { refs: u64, has_overwrite_extents: bool },
95    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
96    Graveyard,
97    Symlink { refs: u64, link: Vec<u8> },
98}
99
100impl From<ObjectKindV40> for ObjectKindV41 {
101    fn from(value: ObjectKindV40) -> Self {
102        match value {
103            // Ignore has_overwrite_extents - it wasn't used here and we are moving it.
104            ObjectKindV40::File { refs, .. } => ObjectKindV41::File { refs },
105            ObjectKindV40::Directory { sub_dirs, wrapping_key_id, casefold } => {
106                ObjectKindV41::Directory { sub_dirs, wrapping_key_id, casefold }
107            }
108            ObjectKindV40::Graveyard => ObjectKindV41::Graveyard,
109            ObjectKindV40::Symlink { refs, link } => ObjectKindV41::Symlink { refs, link },
110        }
111    }
112}
113
114#[derive(Serialize, Deserialize, TypeFingerprint, Versioned)]
115pub struct FsverityMetadataV33 {
116    pub root_digest: RootDigestV33,
117    pub salt: Vec<u8>,
118}
119
120impl From<FsverityMetadataV33> for FsverityMetadataV50 {
121    fn from(value: FsverityMetadataV33) -> Self {
122        Self::Internal(value.root_digest, value.salt)
123    }
124}
125
126#[derive(Serialize, Deserialize, TypeFingerprint)]
127pub struct FxfsKeyV40 {
128    pub wrapping_key_id: u128,
129    pub key: WrappedKeyBytes,
130}
131
132impl From<FxfsKeyV40> for FxfsKeyV49 {
133    fn from(value: FxfsKeyV40) -> Self {
134        Self { wrapping_key_id: value.wrapping_key_id.to_le_bytes(), key: value.key }
135    }
136}
137
138#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
139#[migrate_to_version(EncryptionKeyV49)]
140pub enum EncryptionKeyV47 {
141    Fxfs(FxfsKeyV40),
142    FscryptInoLblk32File { key_identifier: [u8; 16] },
143    FscryptInoLblk32Dir { key_identifier: [u8; 16], nonce: [u8; 16] },
144}
145
146#[derive(Serialize, Deserialize, TypeFingerprint)]
147pub struct EncryptionKeysV47(Vec<(u64, EncryptionKeyV47)>);
148
149impl From<EncryptionKeysV47> for EncryptionKeysV49 {
150    fn from(value: EncryptionKeysV47) -> Self {
151        Self(value.0.into_iter().map(|(id, key)| (id, key.into())).collect())
152    }
153}
154
155#[derive(Serialize, Deserialize, TypeFingerprint)]
156pub enum EncryptionKeysV40 {
157    AES256XTS(WrappedKeysV40),
158}
159
160impl From<EncryptionKeysV40> for EncryptionKeysV47 {
161    fn from(EncryptionKeysV40::AES256XTS(WrappedKeysV40(keys)): EncryptionKeysV40) -> Self {
162        EncryptionKeysV47(
163            keys.into_iter().map(|(id, key)| (id, EncryptionKeyV47::Fxfs(key))).collect(),
164        )
165    }
166}
167
168#[derive(Serialize, Deserialize, TypeFingerprint)]
169pub struct WrappedKeysV40(pub Vec<(u64, FxfsKeyV40)>);
170
171#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
172#[migrate_to_version(ObjectValueV50)]
173pub enum ObjectValueV49 {
174    None,
175    Some,
176    Object { kind: ObjectKindV49, attributes: ObjectAttributesV49 },
177    Keys(EncryptionKeysV49),
178    Attribute { size: u64, has_overwrite_extents: bool },
179    Extent(ExtentValueV38),
180    Child(ChildValueV32),
181    Trim,
182    BytesAndNodes { bytes: i64, nodes: i64 },
183    ExtendedAttribute(ExtendedAttributeValueV32),
184    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
185}
186
187#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
188#[migrate_to_version(ObjectValueV49)]
189pub enum ObjectValueV47 {
190    None,
191    Some,
192    Object { kind: ObjectKindV46, attributes: ObjectAttributesV32 },
193    Keys(EncryptionKeysV47),
194    Attribute { size: u64, has_overwrite_extents: bool },
195    Extent(ExtentValueV38),
196    Child(ChildValueV32),
197    Trim,
198    BytesAndNodes { bytes: i64, nodes: i64 },
199    ExtendedAttribute(ExtendedAttributeValueV32),
200    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
201}
202
203#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
204#[migrate_to_version(ObjectValueV47)]
205pub enum ObjectValueV46 {
206    None,
207    Some,
208    Object { kind: ObjectKindV46, attributes: ObjectAttributesV32 },
209    Keys(EncryptionKeysV40),
210    Attribute { size: u64, has_overwrite_extents: bool },
211    Extent(ExtentValueV38),
212    Child(ChildValueV32),
213    Trim,
214    BytesAndNodes { bytes: i64, nodes: i64 },
215    ExtendedAttribute(ExtendedAttributeValueV32),
216    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
217}
218
219#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
220#[migrate_to_version(ObjectValueV46)]
221pub enum ObjectValueV41 {
222    None,
223    Some,
224    Object { kind: ObjectKindV41, attributes: ObjectAttributesV32 },
225    Keys(EncryptionKeysV40),
226    Attribute { size: u64, has_overwrite_extents: bool },
227    Extent(ExtentValueV38),
228    Child(ChildValueV32),
229    Trim,
230    BytesAndNodes { bytes: i64, nodes: i64 },
231    ExtendedAttribute(ExtendedAttributeValueV32),
232    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
233}
234
235impl From<ObjectValueV40> for ObjectValueV41 {
236    fn from(value: ObjectValueV40) -> Self {
237        match value {
238            ObjectValueV40::None => ObjectValueV41::None,
239            ObjectValueV40::Some => ObjectValueV41::Some,
240            ObjectValueV40::Object { kind, attributes } => {
241                ObjectValueV41::Object { kind: kind.into(), attributes }
242            }
243            ObjectValueV40::Keys(keys) => ObjectValueV41::Keys(keys),
244            ObjectValueV40::Attribute { size } => {
245                ObjectValueV41::Attribute { size, has_overwrite_extents: false }
246            }
247            ObjectValueV40::Extent(extent_value) => ObjectValueV41::Extent(extent_value),
248            ObjectValueV40::Child(child) => ObjectValueV41::Child(child),
249            ObjectValueV40::Trim => ObjectValueV41::Trim,
250            ObjectValueV40::BytesAndNodes { bytes, nodes } => {
251                ObjectValueV41::BytesAndNodes { bytes, nodes }
252            }
253            ObjectValueV40::ExtendedAttribute(xattr) => ObjectValueV41::ExtendedAttribute(xattr),
254            ObjectValueV40::VerifiedAttribute { size, fsverity_metadata } => {
255                ObjectValueV41::VerifiedAttribute { size, fsverity_metadata }
256            }
257        }
258    }
259}
260
261#[derive(Serialize, Deserialize, TypeFingerprint, Versioned)]
262pub enum ObjectValueV40 {
263    None,
264    Some,
265    Object { kind: ObjectKindV40, attributes: ObjectAttributesV32 },
266    Keys(EncryptionKeysV40),
267    Attribute { size: u64 },
268    Extent(ExtentValueV38),
269    Child(ChildValueV32),
270    Trim,
271    BytesAndNodes { bytes: i64, nodes: i64 },
272    ExtendedAttribute(ExtendedAttributeValueV32),
273    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
274}
275
276#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
277#[migrate_to_version(ObjectAttributesV49)]
278pub struct ObjectAttributesV32 {
279    pub creation_time: TimestampV32,
280    pub modification_time: TimestampV32,
281    pub project_id: u64,
282    pub posix_attributes: Option<PosixAttributesV32>,
283    pub allocated_size: u64,
284    pub access_time: TimestampV32,
285    pub change_time: TimestampV32,
286}
287
288impl From<TimestampV32> for TimestampV49 {
289    fn from(timestamp: TimestampV32) -> Self {
290        Self::from_secs_and_nanos(timestamp.secs, timestamp.nanos)
291    }
292}
293
294#[derive(Copy, Clone, Serialize, Deserialize, TypeFingerprint)]
295pub struct TimestampV32 {
296    pub secs: u64,
297    pub nanos: u32,
298}
299
300pub type ObjectItemV49 = Item<ObjectKeyV43, ObjectValueV49>;
301pub type ObjectItemV47 = Item<ObjectKeyV43, ObjectValueV47>;
302pub type ObjectItemV46 = Item<ObjectKeyV43, ObjectValueV46>;
303pub type ObjectItemV43 = Item<ObjectKeyV43, ObjectValueV41>;
304pub type ObjectItemV41 = Item<ObjectKeyV40, ObjectValueV41>;
305pub type ObjectItemV40 = Item<ObjectKeyV40, ObjectValueV40>;
306
307impl From<ObjectItemV49> for ObjectItemV50 {
308    fn from(item: ObjectItemV49) -> Self {
309        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
310    }
311}
312impl From<ObjectItemV47> for ObjectItemV49 {
313    fn from(item: ObjectItemV47) -> Self {
314        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
315    }
316}
317impl From<ObjectItemV46> for ObjectItemV47 {
318    fn from(item: ObjectItemV46) -> Self {
319        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
320    }
321}
322impl From<ObjectItemV43> for ObjectItemV46 {
323    fn from(item: ObjectItemV43) -> Self {
324        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
325    }
326}
327impl From<ObjectItemV41> for ObjectItemV43 {
328    fn from(item: ObjectItemV41) -> Self {
329        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
330    }
331}
332impl From<ObjectItemV40> for ObjectItemV41 {
333    fn from(item: ObjectItemV40) -> Self {
334        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
335    }
336}
337
338#[cfg(test)]
339mod tests {
340    use super::*;
341
342    #[test]
343    fn test_timestamp_v32_to_v49() {
344        let v32 = TimestampV32 { secs: 100, nanos: 200 };
345        let v49: TimestampV49 = v32.into();
346        assert_eq!(v32.secs * 1_000_000_000 + v32.nanos as u64, v49.nanos);
347    }
348}