Skip to main content

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<ObjectKeyDataV43> for ObjectKeyDataV54 {
11    fn from(item: ObjectKeyDataV43) -> Self {
12        match item {
13            ObjectKeyDataV43::Object => Self::Object,
14            ObjectKeyDataV43::Keys => Self::Keys,
15            ObjectKeyDataV43::Attribute(a, b) => Self::Attribute(a, b),
16            ObjectKeyDataV43::Child { name } => Self::Child { name },
17            ObjectKeyDataV43::GraveyardEntry { object_id } => Self::GraveyardEntry { object_id },
18            ObjectKeyDataV43::Project { project_id, property } => {
19                Self::Project { project_id, property }
20            }
21            ObjectKeyDataV43::ExtendedAttribute { name } => Self::ExtendedAttribute { name },
22            ObjectKeyDataV43::GraveyardAttributeEntry { object_id, attribute_id } => {
23                Self::GraveyardAttributeEntry { object_id, attribute_id }
24            }
25            ObjectKeyDataV43::EncryptedCasefoldChild(c) => Self::EncryptedCasefoldChild(c),
26            ObjectKeyDataV43::CasefoldChild { name } => Self::LegacyCasefoldChild(name),
27            ObjectKeyDataV43::EncryptedChild(c) => Self::EncryptedChild(c),
28        }
29    }
30}
31
32#[derive(Eq, Ord, Hash, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint)]
33#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
34pub enum ObjectKeyDataV43 {
35    Object,
36    Keys,
37    Attribute(u64, AttributeKeyV32),
38    Child {
39        name: String,
40    },
41    GraveyardEntry {
42        object_id: u64,
43    },
44    Project {
45        project_id: u64,
46        property: ProjectPropertyV32,
47    },
48    ExtendedAttribute {
49        #[serde(with = "crate::zerocopy_serialization")]
50        name: Vec<u8>,
51    },
52    GraveyardAttributeEntry {
53        object_id: u64,
54        attribute_id: u64,
55    },
56    EncryptedCasefoldChild(EncryptedCasefoldChild),
57    CasefoldChild {
58        name: CasefoldString,
59    },
60    EncryptedChild(EncryptedChild),
61}
62
63#[derive(
64    Eq,
65    Ord,
66    Hash,
67    PartialEq,
68    PartialOrd,
69    Migrate,
70    Serialize,
71    Deserialize,
72    TypeFingerprint,
73    Versioned,
74)]
75#[migrate_to_version(ObjectKeyV54)]
76#[migrate_nodefault]
77#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
78pub struct ObjectKeyV43 {
79    pub object_id: u64,
80    pub data: ObjectKeyDataV43,
81}
82
83impl From<ObjectKeyDataV40> for ObjectKeyDataV43 {
84    fn from(item: ObjectKeyDataV40) -> Self {
85        match item {
86            ObjectKeyDataV40::Object => Self::Object,
87            ObjectKeyDataV40::Keys => Self::Keys,
88            ObjectKeyDataV40::Attribute(a, b) => Self::Attribute(a, b),
89            ObjectKeyDataV40::Child { name } => Self::Child { name },
90            ObjectKeyDataV40::GraveyardEntry { object_id } => Self::GraveyardEntry { object_id },
91            ObjectKeyDataV40::Project { project_id, property } => {
92                Self::Project { project_id, property }
93            }
94            ObjectKeyDataV40::ExtendedAttribute { name } => Self::ExtendedAttribute { name },
95            ObjectKeyDataV40::GraveyardAttributeEntry { object_id, attribute_id } => {
96                Self::GraveyardAttributeEntry { object_id, attribute_id }
97            }
98            ObjectKeyDataV40::EncryptedChild { name } => {
99                Self::EncryptedCasefoldChild(EncryptedCasefoldChild { hash_code: 0, name })
100            }
101            ObjectKeyDataV40::CasefoldChild { name } => Self::CasefoldChild { name },
102        }
103    }
104}
105
106#[derive(Serialize, Deserialize, TypeFingerprint)]
107#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
108pub enum ObjectKeyDataV40 {
109    Object,
110    Keys,
111    Attribute(u64, AttributeKeyV32),
112    Child { name: String },
113    GraveyardEntry { object_id: u64 },
114    Project { project_id: u64, property: ProjectPropertyV32 },
115    ExtendedAttribute { name: Vec<u8> },
116    GraveyardAttributeEntry { object_id: u64, attribute_id: u64 },
117    EncryptedChild { name: Vec<u8> },
118    CasefoldChild { name: CasefoldString },
119}
120
121#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
122#[migrate_to_version(ObjectKeyV43)]
123#[migrate_nodefault]
124pub struct ObjectKeyV40 {
125    pub object_id: u64,
126    pub data: ObjectKeyDataV40,
127}
128
129impl From<ObjectKindV49> for ObjectKindV54 {
130    fn from(kind: ObjectKindV49) -> Self {
131        match kind {
132            ObjectKindV49::File { refs } => ObjectKindV54::File { refs },
133            ObjectKindV49::Directory { sub_dirs, wrapping_key_id, casefold } => {
134                let dir_type = match (casefold, wrapping_key_id) {
135                    (true, Some(id)) => DirType::EncryptedCasefold(id),
136                    (true, None) => DirType::LegacyCasefold, // Existing casefold dirs use Legacy
137                    (false, Some(id)) => DirType::Encrypted(id),
138                    (false, None) => DirType::Normal,
139                };
140                ObjectKindV54::Directory { sub_dirs, dir_type }
141            }
142            ObjectKindV49::Graveyard => ObjectKindV54::Graveyard,
143            ObjectKindV49::Symlink { refs, link } => ObjectKindV54::Symlink { refs, link },
144            ObjectKindV49::EncryptedSymlink { refs, link } => {
145                ObjectKindV54::EncryptedSymlink { refs, link }
146            }
147        }
148    }
149}
150
151impl From<ObjectKindV46> for ObjectKindV49 {
152    fn from(value: ObjectKindV46) -> Self {
153        match value {
154            ObjectKindV46::File { refs } => Self::File { refs },
155            ObjectKindV46::Directory { sub_dirs, wrapping_key_id, casefold } => Self::Directory {
156                sub_dirs,
157                wrapping_key_id: wrapping_key_id.map(u128::to_le_bytes),
158                casefold,
159            },
160            ObjectKindV46::Graveyard => Self::Graveyard,
161            ObjectKindV46::Symlink { refs, link } => Self::Symlink { refs, link: link.into() },
162            ObjectKindV46::EncryptedSymlink { refs, link } => {
163                Self::EncryptedSymlink { refs, link: link.into() }
164            }
165        }
166    }
167}
168
169#[derive(Serialize, Deserialize, TypeFingerprint)]
170pub enum ObjectKindV46 {
171    File { refs: u64 },
172    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
173    Graveyard,
174    Symlink { refs: u64, link: Vec<u8> },
175    EncryptedSymlink { refs: u64, link: Vec<u8> },
176}
177
178#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
179#[migrate_to_version(ObjectKindV46)]
180pub enum ObjectKindV41 {
181    File { refs: u64 },
182    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
183    Graveyard,
184    Symlink { refs: u64, link: Vec<u8> },
185}
186
187#[derive(Serialize, Deserialize, TypeFingerprint)]
188pub enum ObjectKindV40 {
189    File { refs: u64, has_overwrite_extents: bool },
190    Directory { sub_dirs: u64, wrapping_key_id: Option<u128>, casefold: bool },
191    Graveyard,
192    Symlink { refs: u64, link: Vec<u8> },
193}
194
195impl From<ObjectKindV40> for ObjectKindV41 {
196    fn from(value: ObjectKindV40) -> Self {
197        match value {
198            // Ignore has_overwrite_extents - it wasn't used here and we are moving it.
199            ObjectKindV40::File { refs, .. } => ObjectKindV41::File { refs },
200            ObjectKindV40::Directory { sub_dirs, wrapping_key_id, casefold } => {
201                ObjectKindV41::Directory { sub_dirs, wrapping_key_id, casefold }
202            }
203            ObjectKindV40::Graveyard => ObjectKindV41::Graveyard,
204            ObjectKindV40::Symlink { refs, link } => ObjectKindV41::Symlink { refs, link },
205        }
206    }
207}
208
209#[derive(Serialize, Deserialize, TypeFingerprint, Versioned)]
210pub struct FsverityMetadataV33 {
211    pub root_digest: RootDigestV33,
212    pub salt: Vec<u8>,
213}
214
215impl From<FsverityMetadataV33> for FsverityMetadataV50 {
216    fn from(value: FsverityMetadataV33) -> Self {
217        Self::Internal(value.root_digest, value.salt)
218    }
219}
220
221#[derive(Serialize, Deserialize, TypeFingerprint)]
222pub struct FxfsKeyV40 {
223    pub wrapping_key_id: u128,
224    pub key: WrappedKeyBytes,
225}
226
227impl From<FxfsKeyV40> for FxfsKeyV49 {
228    fn from(value: FxfsKeyV40) -> Self {
229        Self { wrapping_key_id: value.wrapping_key_id.to_le_bytes(), key: value.key }
230    }
231}
232
233#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
234#[migrate_to_version(EncryptionKeyV49)]
235pub enum EncryptionKeyV47 {
236    Fxfs(FxfsKeyV40),
237    FscryptInoLblk32File { key_identifier: [u8; 16] },
238    FscryptInoLblk32Dir { key_identifier: [u8; 16], nonce: [u8; 16] },
239}
240
241#[derive(Serialize, Deserialize, TypeFingerprint)]
242pub struct EncryptionKeysV47(Vec<(u64, EncryptionKeyV47)>);
243
244impl From<EncryptionKeysV47> for EncryptionKeysV49 {
245    fn from(value: EncryptionKeysV47) -> Self {
246        Self(value.0.into_iter().map(|(id, key)| (id, key.into())).collect())
247    }
248}
249
250#[derive(Serialize, Deserialize, TypeFingerprint)]
251pub enum EncryptionKeysV40 {
252    AES256XTS(WrappedKeysV40),
253}
254
255impl From<EncryptionKeysV40> for EncryptionKeysV47 {
256    fn from(EncryptionKeysV40::AES256XTS(WrappedKeysV40(keys)): EncryptionKeysV40) -> Self {
257        EncryptionKeysV47(
258            keys.into_iter().map(|(id, key)| (id, EncryptionKeyV47::Fxfs(key))).collect(),
259        )
260    }
261}
262
263#[derive(Serialize, Deserialize, TypeFingerprint)]
264pub struct WrappedKeysV40(pub Vec<(u64, FxfsKeyV40)>);
265
266#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
267#[migrate_to_version(ObjectValueV50)]
268pub enum ObjectValueV49 {
269    None,
270    Some,
271    Object { kind: ObjectKindV49, attributes: ObjectAttributesV49 },
272    Keys(EncryptionKeysV49),
273    Attribute { size: u64, has_overwrite_extents: bool },
274    Extent(ExtentValueV38),
275    Child(ChildValueV32),
276    Trim,
277    BytesAndNodes { bytes: i64, nodes: i64 },
278    ExtendedAttribute(ExtendedAttributeValueV32),
279    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
280}
281
282#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
283#[migrate_to_version(ObjectValueV49)]
284pub enum ObjectValueV47 {
285    None,
286    Some,
287    Object { kind: ObjectKindV46, attributes: ObjectAttributesV32 },
288    Keys(EncryptionKeysV47),
289    Attribute { size: u64, has_overwrite_extents: bool },
290    Extent(ExtentValueV38),
291    Child(ChildValueV32),
292    Trim,
293    BytesAndNodes { bytes: i64, nodes: i64 },
294    ExtendedAttribute(ExtendedAttributeValueV32),
295    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
296}
297
298#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
299#[migrate_to_version(ObjectValueV47)]
300pub enum ObjectValueV46 {
301    None,
302    Some,
303    Object { kind: ObjectKindV46, attributes: ObjectAttributesV32 },
304    Keys(EncryptionKeysV40),
305    Attribute { size: u64, has_overwrite_extents: bool },
306    Extent(ExtentValueV38),
307    Child(ChildValueV32),
308    Trim,
309    BytesAndNodes { bytes: i64, nodes: i64 },
310    ExtendedAttribute(ExtendedAttributeValueV32),
311    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
312}
313
314#[derive(Migrate, Serialize, Deserialize, TypeFingerprint, Versioned)]
315#[migrate_to_version(ObjectValueV46)]
316pub enum ObjectValueV41 {
317    None,
318    Some,
319    Object { kind: ObjectKindV41, attributes: ObjectAttributesV32 },
320    Keys(EncryptionKeysV40),
321    Attribute { size: u64, has_overwrite_extents: bool },
322    Extent(ExtentValueV38),
323    Child(ChildValueV32),
324    Trim,
325    BytesAndNodes { bytes: i64, nodes: i64 },
326    ExtendedAttribute(ExtendedAttributeValueV32),
327    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
328}
329
330impl From<ObjectValueV40> for ObjectValueV41 {
331    fn from(value: ObjectValueV40) -> Self {
332        match value {
333            ObjectValueV40::None => ObjectValueV41::None,
334            ObjectValueV40::Some => ObjectValueV41::Some,
335            ObjectValueV40::Object { kind, attributes } => {
336                ObjectValueV41::Object { kind: kind.into(), attributes }
337            }
338            ObjectValueV40::Keys(keys) => ObjectValueV41::Keys(keys),
339            ObjectValueV40::Attribute { size } => {
340                ObjectValueV41::Attribute { size, has_overwrite_extents: false }
341            }
342            ObjectValueV40::Extent(extent_value) => ObjectValueV41::Extent(extent_value),
343            ObjectValueV40::Child(child) => ObjectValueV41::Child(child),
344            ObjectValueV40::Trim => ObjectValueV41::Trim,
345            ObjectValueV40::BytesAndNodes { bytes, nodes } => {
346                ObjectValueV41::BytesAndNodes { bytes, nodes }
347            }
348            ObjectValueV40::ExtendedAttribute(xattr) => ObjectValueV41::ExtendedAttribute(xattr),
349            ObjectValueV40::VerifiedAttribute { size, fsverity_metadata } => {
350                ObjectValueV41::VerifiedAttribute { size, fsverity_metadata }
351            }
352        }
353    }
354}
355
356#[derive(Serialize, Deserialize, TypeFingerprint, Versioned)]
357pub enum ObjectValueV40 {
358    None,
359    Some,
360    Object { kind: ObjectKindV40, attributes: ObjectAttributesV32 },
361    Keys(EncryptionKeysV40),
362    Attribute { size: u64 },
363    Extent(ExtentValueV38),
364    Child(ChildValueV32),
365    Trim,
366    BytesAndNodes { bytes: i64, nodes: i64 },
367    ExtendedAttribute(ExtendedAttributeValueV32),
368    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV33 },
369}
370
371#[derive(Migrate, Serialize, Deserialize, TypeFingerprint)]
372#[migrate_to_version(ObjectAttributesV49)]
373pub struct ObjectAttributesV32 {
374    pub creation_time: TimestampV32,
375    pub modification_time: TimestampV32,
376    pub project_id: u64,
377    pub posix_attributes: Option<PosixAttributesV32>,
378    pub allocated_size: u64,
379    pub access_time: TimestampV32,
380    pub change_time: TimestampV32,
381}
382
383impl From<TimestampV32> for TimestampV49 {
384    fn from(timestamp: TimestampV32) -> Self {
385        Self::from_secs_and_nanos(timestamp.secs, timestamp.nanos)
386    }
387}
388
389#[derive(Copy, Clone, Serialize, Deserialize, TypeFingerprint)]
390pub struct TimestampV32 {
391    pub secs: u64,
392    pub nanos: u32,
393}
394
395pub type ObjectItemV49 = LegacyItem<ObjectKeyV43, ObjectValueV49>;
396pub type ObjectItemV47 = LegacyItem<ObjectKeyV43, ObjectValueV47>;
397pub type ObjectItemV46 = LegacyItem<ObjectKeyV43, ObjectValueV46>;
398pub type ObjectItemV43 = LegacyItem<ObjectKeyV43, ObjectValueV41>;
399pub type ObjectItemV41 = LegacyItem<ObjectKeyV40, ObjectValueV41>;
400pub type ObjectItemV40 = LegacyItem<ObjectKeyV40, ObjectValueV40>;
401
402impl From<ObjectItemV50> for ObjectItemV54 {
403    fn from(item: ObjectItemV50) -> Self {
404        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
405    }
406}
407
408impl From<ObjectItemV49> for ObjectItemV50 {
409    fn from(item: ObjectItemV49) -> Self {
410        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
411    }
412}
413impl From<ObjectItemV47> for ObjectItemV49 {
414    fn from(item: ObjectItemV47) -> Self {
415        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
416    }
417}
418impl From<ObjectItemV46> for ObjectItemV47 {
419    fn from(item: ObjectItemV46) -> Self {
420        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
421    }
422}
423impl From<ObjectItemV43> for ObjectItemV46 {
424    fn from(item: ObjectItemV43) -> Self {
425        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
426    }
427}
428impl From<ObjectItemV41> for ObjectItemV43 {
429    fn from(item: ObjectItemV41) -> Self {
430        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
431    }
432}
433impl From<ObjectItemV40> for ObjectItemV41 {
434    fn from(item: ObjectItemV40) -> Self {
435        Self { key: item.key.into(), value: item.value.into(), sequence: item.sequence }
436    }
437}
438
439#[cfg(test)]
440mod tests {
441    use super::*;
442
443    #[test]
444    fn test_timestamp_v32_to_v49() {
445        let v32 = TimestampV32 { secs: 100, nanos: 200 };
446        let v49: TimestampV49 = v32.into();
447        assert_eq!(v32.secs * 1_000_000_000 + v32.nanos as u64, v49.nanos);
448    }
449}