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