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