Skip to main content

fxfs/object_store/
object_record.rs

1// Copyright 2021 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
5mod legacy;
6pub use legacy::{
7    EncryptionKeyV56, EncryptionKeysV56, ObjectItemV56, ObjectItemV59, ObjectKindV59,
8    ObjectValueV56, ObjectValueV59,
9};
10
11// TODO(https://fxbug.dev/42178223): need validation after deserialization.
12use crate::checksum::Checksums;
13use crate::log::error;
14use crate::lsm_tree::types::{
15    FuzzyHash, Item, ItemRef, LayerKey, MergeType, OrdLowerBound, OrdUpperBound, SortByU64, Value,
16};
17use crate::object_store::ProjectId;
18use crate::object_store::extent::{Extent, ExtentPartitionIterator};
19use crate::object_store::extent_record::{ExtentValue, ExtentValueV38};
20use crate::serialized_types::Versioned;
21use fprint::TypeFingerprint;
22use fxfs_crypto::{WrappedKey, WrappingKeyId};
23use fxfs_macros::SerializeKey;
24use fxfs_unicode::CasefoldString;
25use serde::{Deserialize, Serialize};
26use static_assertions::const_assert_eq;
27use std::collections::BTreeMap;
28use std::default::Default;
29use std::hash::Hash;
30use std::time::{Duration, SystemTime, UNIX_EPOCH};
31
32/// ObjectDescriptor is the set of possible records in the object store.
33pub type ObjectDescriptor = ObjectDescriptorV32;
34
35#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
36#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
37pub enum ObjectDescriptorV32 {
38    /// A file (in the generic sense; i.e. an object with some attributes).
39    File,
40    /// A directory (in the generic sense; i.e. an object with children).
41    Directory,
42    /// A volume, which is the root of a distinct object store containing Files and Directories.
43    Volume,
44    /// A symbolic link.
45    Symlink,
46}
47
48/// For specifying what property of the project is being addressed.
49pub type ProjectProperty = ProjectPropertyV32;
50
51#[derive(
52    Clone,
53    Debug,
54    Eq,
55    Hash,
56    Ord,
57    PartialEq,
58    PartialOrd,
59    Serialize,
60    Deserialize,
61    TypeFingerprint,
62    SerializeKey,
63)]
64#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
65pub enum ProjectPropertyV32 {
66    /// The configured limit for the project.
67    Limit,
68    /// The currently tracked usage for the project.
69    Usage,
70}
71
72pub type ObjectKeyData = ObjectKeyDataV54;
73
74#[derive(
75    Clone,
76    Debug,
77    Eq,
78    Hash,
79    PartialEq,
80    PartialOrd,
81    Ord,
82    Serialize,
83    Deserialize,
84    TypeFingerprint,
85    SerializeKey,
86)]
87#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
88pub enum ObjectKeyDataV54 {
89    /// A generic, untyped object.  This must come first and sort before all other keys for a given
90    /// object because it's also used as a tombstone and it needs to merge with all following keys.
91    Object,
92    /// Encryption keys for an object.
93    Keys,
94    /// An attribute associated with an object.  It has a 64-bit ID.
95    Attribute(AttributeId, AttributeKeyV32),
96    /// A child of a directory.
97    Child { name: String },
98    /// A graveyard entry for an entire object.
99    GraveyardEntry { object_id: u64 },
100    /// Project ID info. This should only be attached to the volume's root node. Used to address the
101    /// configured limit and the usage tracking which are ordered after the `project_id` to provide
102    /// locality of the two related values.
103    Project { project_id: ProjectId, property: ProjectPropertyV32 },
104    /// An extended attribute associated with an object. It stores the name used for the extended
105    /// attribute, which has a maximum size of 255 bytes enforced by fuchsia.io.
106    ExtendedAttribute {
107        #[serde(with = "crate::zerocopy_serialization")]
108        name: Vec<u8>,
109    },
110    /// A graveyard entry for an attribute.
111    GraveyardAttributeEntry { object_id: u64, attribute_id: AttributeId },
112    /// A child of an encrypted directory.  We store the filename in its encrypted form.  hash_code
113    /// is the hash of the casefolded human-readable name if a directory is also casefolded.  In
114    /// some legacy cases, this is also used in non-casefolded cases, and in some of those cases the
115    /// hash code can be 0.  Going forward, these cases are covered by `EncryptedChild` below.
116    EncryptedCasefoldChild(EncryptedCasefoldChild),
117    /// Case-insensitive child (legacy).
118    LegacyCasefoldChild(CasefoldString),
119    /// An encrypted child that does not use case folding.
120    EncryptedChild(EncryptedChild),
121    /// A child of a directory that uses the casefold feature.
122    /// (i.e. case insensitive, case preserving names)
123    CasefoldChild { hash_code: u32, name: String },
124}
125
126#[derive(
127    Clone,
128    Debug,
129    Eq,
130    Hash,
131    PartialEq,
132    PartialOrd,
133    Ord,
134    Serialize,
135    Deserialize,
136    TypeFingerprint,
137    SerializeKey,
138)]
139#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
140pub struct EncryptedCasefoldChild {
141    pub hash_code: u32,
142    #[serde(with = "crate::zerocopy_serialization")]
143    pub name: Vec<u8>,
144}
145
146#[derive(
147    Clone,
148    Debug,
149    Eq,
150    Hash,
151    PartialEq,
152    PartialOrd,
153    Ord,
154    Serialize,
155    Deserialize,
156    TypeFingerprint,
157    SerializeKey,
158)]
159#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
160pub struct EncryptedChild(#[serde(with = "crate::zerocopy_serialization")] pub Vec<u8>);
161
162pub type AttributeKey = AttributeKeyV32;
163
164// LINT.IfChange
165#[derive(
166    Clone,
167    Debug,
168    Eq,
169    Hash,
170    Ord,
171    PartialEq,
172    PartialOrd,
173    Serialize,
174    Deserialize,
175    TypeFingerprint,
176    SerializeKey,
177)]
178#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
179pub enum AttributeKeyV32 {
180    // Order here is important: code expects Attribute to precede Extent.
181    Attribute,
182    Extent(Extent),
183}
184
185/// ObjectKey is a key in the object store.
186pub type ObjectKey = ObjectKeyV54;
187
188#[derive(
189    Clone,
190    Debug,
191    Eq,
192    Ord,
193    Hash,
194    PartialEq,
195    PartialOrd,
196    Serialize,
197    Deserialize,
198    SerializeKey,
199    TypeFingerprint,
200    Versioned,
201)]
202#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
203pub struct ObjectKeyV54 {
204    /// The ID of the object referred to.
205    pub object_id: u64,
206    /// The type and data of the key.
207    pub data: ObjectKeyDataV54,
208}
209// LINT.ThenChange(//src/storage/fxfs/src/object_store/extent_record.rs)
210
211impl SortByU64 for ObjectKey {
212    fn get_leading_u64(&self) -> u64 {
213        self.object_id
214    }
215}
216
217impl ObjectKey {
218    /// Creates a generic ObjectKey.
219    pub fn object(object_id: u64) -> Self {
220        Self { object_id: object_id, data: ObjectKeyData::Object }
221    }
222
223    /// Creates an ObjectKey for encryption keys.
224    pub fn keys(object_id: u64) -> Self {
225        Self { object_id, data: ObjectKeyData::Keys }
226    }
227
228    /// Creates an ObjectKey for an attribute.
229    pub fn attribute(object_id: u64, attribute_id: AttributeId, key: AttributeKey) -> Self {
230        Self { object_id, data: ObjectKeyData::Attribute(attribute_id, key) }
231    }
232
233    /// Creates an ObjectKey for an extent.
234    pub fn extent(object_id: u64, attribute_id: AttributeId, range: std::ops::Range<u64>) -> Self {
235        Self {
236            object_id,
237            data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(Extent(range))),
238        }
239    }
240
241    /// Creates an ObjectKey from an extent.
242    pub fn from_extent(object_id: u64, attribute_id: AttributeId, extent: Extent) -> Self {
243        Self {
244            object_id,
245            data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(extent)),
246        }
247    }
248
249    /// Creates an ObjectKey for a child.
250    pub fn child(object_id: u64, name: &str, dir_type: DirType) -> Self {
251        match dir_type {
252            DirType::Casefold => {
253                let cf = fxfs_unicode::CasefoldStr::new(name);
254                let casefolded = cf.casefold_normalized_chars().flat_map(fxfs_unicode::utf8_bytes);
255                let hash_code = fscrypt::direntry::tea_hash_filename(casefolded);
256                Self {
257                    object_id,
258                    data: ObjectKeyData::CasefoldChild { hash_code, name: name.into() },
259                }
260            }
261            DirType::LegacyCasefold => Self {
262                object_id,
263                data: ObjectKeyData::LegacyCasefoldChild(CasefoldString::new(name.into())),
264            },
265            DirType::Normal => Self { object_id, data: ObjectKeyData::Child { name: name.into() } },
266            DirType::Encrypted(_) | DirType::EncryptedCasefold(_) => {
267                // These shouldn't be used directly; encrypted_child should be used instead.
268                panic!("Encrypted modes require an encrypted name");
269            }
270        }
271    }
272
273    /// Creates an ObjectKey for an encrypted child.
274    ///
275    /// The hash_code is important here -- especially for fscrypt as it affects the
276    /// name of locked files.
277    ///
278    /// For case-insensitive lookups in large encrypted directories, we lose the ability to binary
279    /// search for an entry of interest because encryption breaks our sort order. In these cases
280    /// we prefix records with a 32-bit hash based on the stable *casefolded* name. Hash collisions
281    /// aside, this lets us jump straight to the entry of interest, if it exists.
282    pub fn encrypted_child(object_id: u64, name: Vec<u8>, hash_code: Option<u32>) -> Self {
283        if let Some(hash_code) = hash_code {
284            Self {
285                object_id,
286                data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
287                    hash_code,
288                    name,
289                }),
290            }
291        } else {
292            Self { object_id, data: ObjectKeyData::EncryptedChild(EncryptedChild(name)) }
293        }
294    }
295
296    /// Creates a graveyard entry for an object.
297    pub fn graveyard_entry(graveyard_object_id: u64, object_id: u64) -> Self {
298        Self { object_id: graveyard_object_id, data: ObjectKeyData::GraveyardEntry { object_id } }
299    }
300
301    /// Creates a graveyard entry for an attribute.
302    pub fn graveyard_attribute_entry(
303        graveyard_object_id: u64,
304        object_id: u64,
305        attribute_id: AttributeId,
306    ) -> Self {
307        Self {
308            object_id: graveyard_object_id,
309            data: ObjectKeyData::GraveyardAttributeEntry { object_id, attribute_id },
310        }
311    }
312
313    /// Creates an ObjectKey for a ProjectLimit entry.
314    pub fn project_limit(object_id: u64, project_id: ProjectId) -> Self {
315        Self {
316            object_id,
317            data: ObjectKeyData::Project { project_id, property: ProjectProperty::Limit },
318        }
319    }
320
321    /// Creates an ObjectKey for a ProjectUsage entry.
322    pub fn project_usage(object_id: u64, project_id: ProjectId) -> Self {
323        Self {
324            object_id,
325            data: ObjectKeyData::Project { project_id, property: ProjectProperty::Usage },
326        }
327    }
328
329    pub fn extended_attribute(object_id: u64, name: Vec<u8>) -> Self {
330        Self { object_id, data: ObjectKeyData::ExtendedAttribute { name } }
331    }
332
333    /// Returns the merge key for this key; that is, a key which is <= this key and any
334    /// other possibly overlapping key, under Ord. This would be used for the hint in |merge_into|.
335    pub fn key_for_merge_into(&self) -> Self {
336        if let Self {
337            object_id,
338            data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
339        } = self
340        {
341            Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.key_for_merge_into()))
342        } else {
343            self.clone()
344        }
345    }
346}
347
348impl OrdUpperBound for ObjectKey {
349    fn cmp_upper_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
350        self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
351            (
352                ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
353                ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
354            ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_upper_bound(right_extent)),
355            _ => self.data.cmp(&other.data),
356        })
357    }
358}
359
360impl OrdLowerBound for ObjectKey {
361    fn cmp_lower_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
362        self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
363            (
364                ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
365                ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
366            ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_lower_bound(right_extent)),
367            _ => self.data.cmp(&other.data),
368        })
369    }
370}
371
372impl LayerKey for ObjectKey {
373    fn merge_type(&self) -> MergeType {
374        // This listing is intentionally exhaustive to force folks to think about how certain
375        // subsets of the keyspace are merged.
376        match self.data {
377            ObjectKeyData::Object
378            | ObjectKeyData::Keys
379            | ObjectKeyData::Attribute(..)
380            | ObjectKeyData::Child { .. }
381            | ObjectKeyData::EncryptedChild(_)
382            | ObjectKeyData::EncryptedCasefoldChild(_)
383            | ObjectKeyData::CasefoldChild { .. }
384            | ObjectKeyData::LegacyCasefoldChild(_)
385            | ObjectKeyData::GraveyardEntry { .. }
386            | ObjectKeyData::GraveyardAttributeEntry { .. }
387            | ObjectKeyData::Project { property: ProjectProperty::Limit, .. }
388            | ObjectKeyData::ExtendedAttribute { .. } => MergeType::OptimizedMerge,
389            ObjectKeyData::Project { property: ProjectProperty::Usage, .. } => MergeType::FullMerge,
390        }
391    }
392
393    fn next_key(&self) -> Option<Self> {
394        match &self.data {
395            ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
396                // This key comes before (or is equal to) any extent starting at or after the
397                // end of `self`. Searching for its `next_key` finds extents that end after
398                // the end of `self`.
399                Some(ObjectKey {
400                    object_id: self.object_id,
401                    data: ObjectKeyData::Attribute(
402                        *attr_id,
403                        AttributeKey::Extent(Extent::search_key_from_offset(extent.end)),
404                    ),
405                })
406            }
407            _ => None,
408        }
409    }
410
411    fn search_key(&self) -> Option<Self> {
412        if let Self {
413            object_id,
414            data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
415        } = self
416        {
417            Some(Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.search_key())))
418        } else {
419            None
420        }
421    }
422
423    fn is_search_key(&self) -> bool {
424        match self {
425            Self { data: ObjectKeyData::Attribute(_, AttributeKey::Extent(e)), .. } => {
426                e.is_search_key()
427            }
428            _ => true,
429        }
430    }
431
432    fn overlaps(&self, other: &Self) -> bool {
433        if self.object_id != other.object_id {
434            return false;
435        }
436        match (&self.data, &other.data) {
437            (
438                ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_key)),
439                ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_key)),
440            ) if *left_attr_id == *right_attr_id => left_key.overlaps(right_key),
441            (a, b) => a == b,
442        }
443    }
444}
445
446pub enum ObjectKeyFuzzyHashIterator {
447    Extent(/* object_id */ u64, AttributeId, ExtentPartitionIterator),
448    NotExtent(/* hash */ Option<u64>),
449}
450
451impl Iterator for ObjectKeyFuzzyHashIterator {
452    type Item = u64;
453
454    fn next(&mut self) -> Option<Self::Item> {
455        match self {
456            Self::Extent(oid, attr_id, extent_keys) => extent_keys.next().map(|range| {
457                let key = ObjectKey::extent(*oid, *attr_id, range);
458                crate::stable_hash::stable_hash(key)
459            }),
460            Self::NotExtent(hash) => hash.take(),
461        }
462    }
463
464    fn size_hint(&self) -> (usize, Option<usize>) {
465        match self {
466            Self::Extent(_, _, extent_keys) => extent_keys.size_hint(),
467            Self::NotExtent(hash) => {
468                let len = if hash.is_some() { 1 } else { 0 };
469                (len, Some(len))
470            }
471        }
472    }
473}
474
475impl ExactSizeIterator for ObjectKeyFuzzyHashIterator {}
476
477impl FuzzyHash for ObjectKey {
478    fn fuzzy_hash(&self) -> impl ExactSizeIterator<Item = u64> {
479        match &self.data {
480            ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
481                ObjectKeyFuzzyHashIterator::Extent(
482                    self.object_id,
483                    *attr_id,
484                    extent.fuzzy_hash_partition(),
485                )
486            }
487            _ => {
488                let hash = crate::stable_hash::stable_hash(self);
489                ObjectKeyFuzzyHashIterator::NotExtent(Some(hash))
490            }
491        }
492    }
493
494    fn is_range_key(&self) -> bool {
495        match &self.data {
496            ObjectKeyData::Attribute(_, AttributeKey::Extent(_)) => true,
497            _ => false,
498        }
499    }
500}
501
502/// UNIX epoch based timestamp in the UTC timezone.
503pub type Timestamp = TimestampV49;
504
505#[derive(
506    Copy,
507    Clone,
508    Debug,
509    Default,
510    Eq,
511    PartialEq,
512    Ord,
513    PartialOrd,
514    Serialize,
515    Deserialize,
516    TypeFingerprint,
517)]
518#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
519pub struct TimestampV49 {
520    nanos: u64,
521}
522
523impl Timestamp {
524    const NSEC_PER_SEC: u64 = 1_000_000_000;
525
526    pub fn now() -> Self {
527        SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO).into()
528    }
529
530    pub const fn zero() -> Self {
531        Self { nanos: 0 }
532    }
533
534    pub const fn from_nanos(nanos: u64) -> Self {
535        Self { nanos }
536    }
537
538    pub fn from_secs_and_nanos(secs: u64, nanos: u32) -> Self {
539        let Some(secs_in_nanos) = secs.checked_mul(Self::NSEC_PER_SEC) else {
540            error!("Fxfs doesn't support dates past 2554-07-21");
541            return Self { nanos: u64::MAX };
542        };
543        let Some(nanos) = secs_in_nanos.checked_add(nanos as u64) else {
544            error!("Fxfs doesn't support dates past 2554-07-21");
545            return Self { nanos: u64::MAX };
546        };
547        Self { nanos }
548    }
549
550    /// Returns the total number of nanoseconds represented by this `Timestamp` since the Unix
551    /// epoch.
552    pub fn as_nanos(&self) -> u64 {
553        self.nanos
554    }
555
556    /// Returns the fractional nanoseconds represented by this `Timestamp`.
557    pub fn subsec_nanos(&self) -> u32 {
558        (self.nanos % Self::NSEC_PER_SEC) as u32
559    }
560
561    /// Returns the total number of whole seconds represented by this `Timestamp` since the Unix
562    /// epoch.
563    pub fn as_secs(&self) -> u64 {
564        self.nanos / Self::NSEC_PER_SEC
565    }
566}
567
568impl From<std::time::Duration> for Timestamp {
569    fn from(duration: std::time::Duration) -> Self {
570        Self::from_secs_and_nanos(duration.as_secs(), duration.subsec_nanos())
571    }
572}
573
574impl From<Timestamp> for std::time::Duration {
575    fn from(timestamp: Timestamp) -> std::time::Duration {
576        Duration::from_nanos(timestamp.nanos)
577    }
578}
579
580pub type ObjectKind = ObjectKindV62;
581pub type DirType = DirTypeV59;
582
583/// The default fscrypt policy flags implied for legacy fscrypt-encrypted nodes in Fxfs: 16-byte
584/// filename padding (`PAD_16`).
585///
586/// Prior to persisting policy flags in `DirType`, Fxfs only recorded `WrappingKeyId` on disk, so
587/// these are the fallback flags reported in `fuchsia.io/FscryptPolicy` for legacy encrypted
588/// directories and files.
589///
590/// TODO(https://fxbug.dev/527952709): Remove this fallback once all encrypted nodes persist their
591/// fscrypt policy flags on disk and legacy nodes without persisted flags are migrated.
592pub const LEGACY_FSCRYPT_FLAGS: fidl_fuchsia_io::FscryptPolicyFlags =
593    fidl_fuchsia_io::FscryptPolicyFlags::PAD_16;
594
595/// Bitfield of fscrypt encryption policy flags persisted on disk in `DirType`.
596#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
597#[repr(transparent)]
598pub struct FscryptPolicyFlags(u8);
599
600impl FscryptPolicyFlags {
601    pub const PAD_8: Self = Self(0x01);
602    pub const PAD_16: Self = Self(0x02);
603    pub const DIRECT_KEY: Self = Self(0x04);
604    pub const IV_INO_LBLK_64: Self = Self(0x08);
605    pub const IV_INO_LBLK_32: Self = Self(0x10);
606    pub const ALL: Self = Self(
607        Self::PAD_8.0
608            | Self::PAD_16.0
609            | Self::DIRECT_KEY.0
610            | Self::IV_INO_LBLK_64.0
611            | Self::IV_INO_LBLK_32.0,
612    );
613
614    pub const fn empty() -> Self {
615        Self(0)
616    }
617
618    pub const fn from_bits(bits: u8) -> Option<Self> {
619        if (bits & !Self::ALL.0) == 0 { Some(Self(bits)) } else { None }
620    }
621
622    pub const fn from_bits_retain(bits: u8) -> Self {
623        Self(bits)
624    }
625
626    pub const fn bits(&self) -> u8 {
627        self.0
628    }
629
630    pub const fn contains(&self, other: Self) -> bool {
631        (self.0 & other.0) == other.0
632    }
633
634    pub const fn intersects(&self, other: Self) -> bool {
635        (self.0 & other.0) != 0
636    }
637}
638
639#[cfg(fuzz)]
640impl<'a> arbitrary::Arbitrary<'a> for FscryptPolicyFlags {
641    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
642        Ok(Self(u.arbitrary::<u8>()? & Self::ALL.bits()))
643    }
644}
645
646const_assert_eq!(
647    FscryptPolicyFlags::PAD_8.bits(),
648    fidl_fuchsia_io::FscryptPolicyFlags::PAD_8.bits()
649);
650const_assert_eq!(
651    FscryptPolicyFlags::PAD_16.bits(),
652    fidl_fuchsia_io::FscryptPolicyFlags::PAD_16.bits()
653);
654const_assert_eq!(
655    FscryptPolicyFlags::DIRECT_KEY.bits(),
656    fidl_fuchsia_io::FscryptPolicyFlags::DIRECT_KEY.bits()
657);
658const_assert_eq!(
659    FscryptPolicyFlags::IV_INO_LBLK_64.bits(),
660    fidl_fuchsia_io::FscryptPolicyFlags::IV_INO_LBLK_64.bits()
661);
662const_assert_eq!(
663    FscryptPolicyFlags::IV_INO_LBLK_32.bits(),
664    fidl_fuchsia_io::FscryptPolicyFlags::IV_INO_LBLK_32.bits()
665);
666
667impl core::ops::BitOr for FscryptPolicyFlags {
668    type Output = Self;
669
670    fn bitor(self, rhs: Self) -> Self::Output {
671        Self(self.0 | rhs.0)
672    }
673}
674
675impl core::ops::BitOrAssign for FscryptPolicyFlags {
676    fn bitor_assign(&mut self, rhs: Self) {
677        self.0 |= rhs.0;
678    }
679}
680
681impl core::ops::BitAnd for FscryptPolicyFlags {
682    type Output = Self;
683
684    fn bitand(self, rhs: Self) -> Self::Output {
685        Self(self.0 & rhs.0)
686    }
687}
688
689impl core::ops::Not for FscryptPolicyFlags {
690    type Output = Self;
691
692    fn not(self) -> Self::Output {
693        Self(!self.0)
694    }
695}
696
697impl From<fidl_fuchsia_io::FscryptPolicyFlags> for FscryptPolicyFlags {
698    fn from(flags: fidl_fuchsia_io::FscryptPolicyFlags) -> Self {
699        Self(flags.bits())
700    }
701}
702
703impl From<FscryptPolicyFlags> for fidl_fuchsia_io::FscryptPolicyFlags {
704    fn from(flags: FscryptPolicyFlags) -> Self {
705        Self::from_bits_retain(flags.bits())
706    }
707}
708
709impl TryFrom<u8> for FscryptPolicyFlags {
710    type Error = anyhow::Error;
711
712    fn try_from(bits: u8) -> Result<Self, Self::Error> {
713        Self::from_bits(bits)
714            .ok_or_else(|| anyhow::anyhow!("Unrecognized fscrypt policy flags: {bits:#x}"))
715    }
716}
717
718impl From<FscryptPolicyFlags> for u8 {
719    fn from(flags: FscryptPolicyFlags) -> Self {
720        flags.bits()
721    }
722}
723
724impl TypeFingerprint for FscryptPolicyFlags {
725    fn fingerprint() -> String {
726        "u8".to_owned()
727    }
728}
729
730/// Fscrypt policy metadata persisted in `DirType` for encrypted directories.
731#[derive(Clone, Copy, Debug, Default, Serialize, Deserialize, PartialEq, Eq, TypeFingerprint)]
732#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
733pub struct FscryptDirInfo {
734    pub wrapping_key_id: WrappingKeyId,
735    pub flags: FscryptPolicyFlags,
736}
737
738impl FscryptDirInfo {
739    pub fn new(wrapping_key_id: WrappingKeyId, flags: impl Into<FscryptPolicyFlags>) -> Self {
740        Self { wrapping_key_id, flags: flags.into() }
741    }
742}
743
744/// Prior to Fxfs v59, `DirType` only persisted the 16-byte `WrappingKeyId`, and all fscrypt
745/// directories implicitly used 16-byte filename padding (`PAD_16`). When migrating legacy records
746/// or constructing `FscryptDirInfo` from a bare `WrappingKeyId`, default to
747/// `FscryptPolicyFlags::PAD_16`.
748impl From<WrappingKeyId> for FscryptDirInfo {
749    fn from(wrapping_key_id: WrappingKeyId) -> Self {
750        Self { wrapping_key_id, flags: FscryptPolicyFlags::PAD_16 }
751    }
752}
753
754impl From<fidl_fuchsia_io::FscryptPolicy> for FscryptDirInfo {
755    fn from(policy: fidl_fuchsia_io::FscryptPolicy) -> Self {
756        Self {
757            wrapping_key_id: policy.key_identifier,
758            flags: FscryptPolicyFlags::from(policy.flags),
759        }
760    }
761}
762
763impl From<FscryptDirInfo> for fidl_fuchsia_io::FscryptPolicy {
764    fn from(info: FscryptDirInfo) -> Self {
765        fidl_fuchsia_io::FscryptPolicy {
766            key_identifier: info.wrapping_key_id,
767            flags: info.flags.into(),
768        }
769    }
770}
771
772#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, TypeFingerprint)]
773#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
774pub enum DirTypeV59 {
775    Normal,
776    Encrypted(FscryptDirInfo),
777    LegacyCasefold,
778    Casefold,
779    EncryptedCasefold(FscryptDirInfo),
780}
781
782impl DirType {
783    pub fn is_casefold(&self) -> bool {
784        matches!(self, DirType::LegacyCasefold | DirType::Casefold | DirType::EncryptedCasefold(_))
785    }
786
787    pub fn is_encrypted(&self) -> bool {
788        matches!(self, DirType::Encrypted(_) | DirType::EncryptedCasefold(_))
789    }
790
791    pub fn with_encryption(self, info: FscryptDirInfo) -> Self {
792        match self {
793            DirType::Normal => DirType::Encrypted(info),
794            DirType::Casefold => DirType::EncryptedCasefold(info),
795            _ => self,
796        }
797    }
798
799    pub fn with_casefold(self, val: bool) -> Self {
800        match (val, self) {
801            (true, DirType::Encrypted(info) | DirType::EncryptedCasefold(info)) => {
802                DirType::EncryptedCasefold(info)
803            }
804            (true, _) => DirType::Casefold,
805            (false, DirType::Encrypted(info) | DirType::EncryptedCasefold(info)) => {
806                DirType::Encrypted(info)
807            }
808            (false, _) => DirType::Normal,
809        }
810    }
811
812    pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
813        match self {
814            DirType::Encrypted(info) | DirType::EncryptedCasefold(info) => {
815                Some(info.wrapping_key_id)
816            }
817            _ => None,
818        }
819    }
820
821    pub fn fscrypt_info(&self) -> Option<FscryptDirInfo> {
822        match self {
823            DirType::Encrypted(info) | DirType::EncryptedCasefold(info) => Some(*info),
824            _ => None,
825        }
826    }
827
828    pub fn fscrypt_policy(&self) -> Option<fidl_fuchsia_io::FscryptPolicy> {
829        self.fscrypt_info().map(Into::into)
830    }
831}
832
833impl Default for DirType {
834    fn default() -> Self {
835        DirType::Normal
836    }
837}
838
839#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
840#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
841pub enum ObjectKindV62 {
842    File {
843        /// The number of references to this file.
844        refs: u64,
845    },
846    Directory {
847        /// The number of sub-directories in this directory.
848        sub_dirs: u64,
849        /// The type of directory (encryption, casefolding, etc.)
850        dir_type: DirType,
851    },
852    Graveyard,
853    Symlink {
854        /// The number of references to this symbolic link.
855        refs: u64,
856        /// `link` is the target of the link and has no meaning within Fxfs; clients are free to
857        /// interpret it however they like.
858        #[serde(with = "crate::zerocopy_serialization")]
859        link: Box<[u8]>,
860    },
861    EncryptedSymlink {
862        /// The number of references to this symbolic link.
863        refs: u64,
864        /// `link` is the target of the link and has no meaning within Fxfs; clients are free to
865        /// interpret it however they like.
866        /// `link` is stored here in encrypted form, encrypted with the symlink's key using the
867        /// volume's data key.
868        #[serde(with = "crate::zerocopy_serialization")]
869        link: Box<[u8]>,
870    },
871    NonInlineSymlink {
872        /// The number of references to this symbolic link.
873        refs: u64,
874    },
875}
876
877#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
878#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
879pub enum ObjectKindV49 {
880    File {
881        /// The number of references to this file.
882        refs: u64,
883    },
884    Directory {
885        /// The number of sub-directories in this directory.
886        sub_dirs: u64,
887        /// If set, contains the wrapping key id used to encrypt the file contents and filenames in
888        /// this directory.
889        wrapping_key_id: Option<WrappingKeyId>,
890        /// If true, all files and sub-directories created in this directory will support case
891        /// insensitive (but case-preserving) file naming.
892        casefold: bool,
893    },
894    Graveyard,
895    Symlink {
896        /// The number of references to this symbolic link.
897        refs: u64,
898        /// `link` is the target of the link and has no meaning within Fxfs; clients are free to
899        /// interpret it however they like.
900        #[serde(with = "crate::zerocopy_serialization")]
901        link: Box<[u8]>,
902    },
903    EncryptedSymlink {
904        /// The number of references to this symbolic link.
905        refs: u64,
906        /// `link` is the target of the link and has no meaning within Fxfs; clients are free to
907        /// interpret it however they like.
908        /// `link` is stored here in encrypted form, encrypted with the symlink's key using the
909        /// same encryption scheme as the one used to encrypt filenames.
910        #[serde(with = "crate::zerocopy_serialization")]
911        link: Box<[u8]>,
912    },
913}
914
915/// This consists of POSIX attributes that are not used in Fxfs but it may be meaningful to some
916/// clients to have the ability to to set and retrieve these values.
917pub type PosixAttributes = PosixAttributesV32;
918
919#[derive(Clone, Debug, Copy, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
920#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
921pub struct PosixAttributesV32 {
922    /// The mode bits associated with this object
923    pub mode: u32,
924    /// User ID of owner
925    pub uid: u32,
926    /// Group ID of owner
927    pub gid: u32,
928    /// Device ID
929    pub rdev: u64,
930}
931
932/// Object-level attributes.  Note that these are not the same as "attributes" in the
933/// ObjectValue::Attribute sense, which refers to an arbitrary data payload associated with an
934/// object.  This naming collision is unfortunate.
935pub type ObjectAttributes = ObjectAttributesV49;
936
937#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
938#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
939pub struct ObjectAttributesV49 {
940    /// The timestamp at which the object was created (i.e. crtime).
941    pub creation_time: TimestampV49,
942    /// The timestamp at which the object's data was last modified (i.e. mtime).
943    pub modification_time: TimestampV49,
944    /// The project id to associate this object's resource usage with.
945    #[serde(with = "crate::object_store::project_id::optional_project_id")]
946    pub project_id: Option<ProjectId>,
947    /// Mode, uid, gid, and rdev
948    pub posix_attributes: Option<PosixAttributesV32>,
949    /// The number of bytes allocated to all extents across all attributes for this object.
950    pub allocated_size: u64,
951    /// The timestamp at which the object was last read (i.e. atime).
952    pub access_time: TimestampV49,
953    /// The timestamp at which the object's status was last modified (i.e. ctime).
954    pub change_time: TimestampV49,
955}
956
957pub type ExtendedAttributeValue = ExtendedAttributeValueV32;
958
959#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
960#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
961pub enum ExtendedAttributeValueV32 {
962    /// The extended attribute value is stored directly in this object. If the value is above a
963    /// certain size, it should be stored as an attribute with extents instead.
964    Inline(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
965    /// The extended attribute value is stored as an attribute with extents. The attribute id
966    /// should be chosen to be within the range of 64-512.
967    AttributeId(AttributeId),
968}
969
970/// Id and descriptor for a child entry.
971pub type ChildValue = ChildValueV32;
972
973#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
974#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
975pub struct ChildValueV32 {
976    /// The ID of the child object.
977    pub object_id: u64,
978    /// Describes the type of the child.
979    pub object_descriptor: ObjectDescriptorV32,
980}
981
982pub type RootDigest = RootDigestV33;
983
984#[derive(
985    Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
986)]
987#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
988pub enum RootDigestV33 {
989    Sha256([u8; 32]),
990    Sha512(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
991}
992
993pub type FsverityMetadata = FsverityMetadataV50;
994
995#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
996#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
997pub enum FsverityMetadataV50 {
998    /// The root hash and salt.
999    Internal(RootDigestV33, #[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
1000    /// The root hash and salt are in a descriptor inside the merkle attribute.
1001    F2fs(std::ops::Range<u64>),
1002}
1003
1004pub type EncryptionKey = EncryptionKeyV59;
1005pub type EncryptionKeyV59 = fxfs_crypto::EncryptionKey;
1006
1007pub type EncryptionKeys = EncryptionKeysV59;
1008
1009#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
1010#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
1011pub struct EncryptionKeysV59(pub(super) Vec<(u64, EncryptionKeyV59)>);
1012
1013impl EncryptionKeys {
1014    pub fn get(&self, id: u64) -> Option<&EncryptionKey> {
1015        self.0.iter().find_map(|(i, key)| (*i == id).then_some(key))
1016    }
1017
1018    pub fn insert(&mut self, id: u64, key: EncryptionKey) {
1019        self.0.push((id, key))
1020    }
1021
1022    pub fn remove(&mut self, id: u64) -> Option<EncryptionKey> {
1023        if let Some(ix) = self.0.iter().position(|(k, _)| *k == id) {
1024            Some(self.0.remove(ix).1)
1025        } else {
1026            None
1027        }
1028    }
1029}
1030
1031impl From<EncryptionKeys> for BTreeMap<u64, WrappedKey> {
1032    fn from(keys: EncryptionKeys) -> Self {
1033        keys.0.into_iter().map(|(id, key)| (id, key.into())).collect()
1034    }
1035}
1036
1037impl From<Vec<(u64, EncryptionKey)>> for EncryptionKeys {
1038    fn from(value: Vec<(u64, EncryptionKey)>) -> Self {
1039        Self(value)
1040    }
1041}
1042
1043impl std::ops::Deref for EncryptionKeys {
1044    type Target = Vec<(u64, EncryptionKey)>;
1045    fn deref(&self) -> &Self::Target {
1046        &self.0
1047    }
1048}
1049
1050/// ObjectValue is the value of an item in the object store.
1051/// Note that the tree stores deltas on objects, so these values describe deltas. Unless specified
1052/// otherwise, a value indicates an insert/replace mutation.
1053pub type ObjectValue = ObjectValueV62;
1054impl Value for ObjectValue {
1055    const DELETED_MARKER: Self = Self::None;
1056}
1057
1058#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
1059#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
1060pub enum ObjectValueV62 {
1061    /// Some keys have no value (this often indicates a tombstone of some sort).  Records with this
1062    /// value are always filtered when a major compaction is performed, so the meaning must be the
1063    /// same as if the item was not present.
1064    None,
1065    /// Some keys have no value but need to differentiate between a present value and no value
1066    /// (None) i.e. their value is really a boolean: None => false, Some => true.
1067    Some,
1068    /// The value for an ObjectKey::Object record.
1069    Object { kind: ObjectKindV62, attributes: ObjectAttributesV49 },
1070    /// Specifies encryption keys to use for an object.
1071    Keys(EncryptionKeysV59),
1072    /// An attribute associated with a file object. |size| is the size of the attribute in bytes.
1073    Attribute { size: u64, has_overwrite_extents: bool },
1074    /// An extent associated with an object.
1075    Extent(ExtentValueV38),
1076    /// A child of an object.
1077    Child(ChildValue),
1078    /// Graveyard entries can contain these entries which will cause a file that has extents beyond
1079    /// EOF to be trimmed at mount time.  This is used in cases where shrinking a file can exceed
1080    /// the bounds of a single transaction.
1081    Trim,
1082    /// Added to support tracking Project ID usage and limits.
1083    BytesAndNodes { bytes: i64, nodes: i64 },
1084    /// A value for an extended attribute. Either inline or a redirection to an attribute with
1085    /// extents.
1086    ExtendedAttribute(ExtendedAttributeValueV32),
1087    /// An attribute associated with a verified file object. |size| is the size of the attribute
1088    /// in bytes.
1089    VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV50 },
1090}
1091
1092/// Storage for a pair of related byte and node values.
1093#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1094pub struct BytesAndNodes {
1095    pub bytes: i64,
1096    pub nodes: i64,
1097}
1098
1099impl BytesAndNodes {
1100    pub fn is_zero(&self) -> bool {
1101        self.bytes == 0 && self.nodes == 0
1102    }
1103}
1104
1105impl std::ops::Add for BytesAndNodes {
1106    type Output = Self;
1107    fn add(self, rhs: Self) -> Self {
1108        Self { bytes: self.bytes + rhs.bytes, nodes: self.nodes + rhs.nodes }
1109    }
1110}
1111
1112impl std::ops::AddAssign for BytesAndNodes {
1113    fn add_assign(&mut self, rhs: Self) {
1114        self.bytes += rhs.bytes;
1115        self.nodes += rhs.nodes;
1116    }
1117}
1118
1119impl From<BytesAndNodes> for ObjectValue {
1120    fn from(value: BytesAndNodes) -> Self {
1121        ObjectValue::BytesAndNodes { bytes: value.bytes, nodes: value.nodes }
1122    }
1123}
1124
1125impl From<(i64, i64)> for BytesAndNodes {
1126    fn from((bytes, nodes): (i64, i64)) -> Self {
1127        Self { bytes, nodes }
1128    }
1129}
1130
1131impl From<BytesAndNodes> for (i64, i64) {
1132    fn from(value: BytesAndNodes) -> Self {
1133        (value.bytes, value.nodes)
1134    }
1135}
1136
1137impl ObjectValue {
1138    /// Creates an ObjectValue for a file object.
1139    pub fn file(
1140        refs: u64,
1141        allocated_size: u64,
1142        creation_time: Timestamp,
1143        modification_time: Timestamp,
1144        access_time: Timestamp,
1145        change_time: Timestamp,
1146        project_id: Option<ProjectId>,
1147        posix_attributes: Option<PosixAttributes>,
1148    ) -> ObjectValue {
1149        ObjectValue::Object {
1150            kind: ObjectKind::File { refs },
1151            attributes: ObjectAttributes {
1152                creation_time,
1153                modification_time,
1154                project_id,
1155                posix_attributes,
1156                allocated_size,
1157                access_time,
1158                change_time,
1159            },
1160        }
1161    }
1162    pub fn keys(encryption_keys: EncryptionKeys) -> ObjectValue {
1163        ObjectValue::Keys(encryption_keys)
1164    }
1165    /// Creates an ObjectValue for an object attribute.
1166    pub fn attribute(size: u64, has_overwrite_extents: bool) -> ObjectValue {
1167        ObjectValue::Attribute { size, has_overwrite_extents }
1168    }
1169    /// Creates an ObjectValue for an object attribute of a verified file.
1170    pub fn verified_attribute(size: u64, fsverity_metadata: FsverityMetadata) -> ObjectValue {
1171        ObjectValue::VerifiedAttribute { size, fsverity_metadata }
1172    }
1173    /// Creates an ObjectValue for an insertion/replacement of an object extent.
1174    pub fn extent(device_offset: u64, key_id: u64) -> ObjectValue {
1175        ObjectValue::Extent(ExtentValue::new_raw(device_offset, key_id))
1176    }
1177    /// Creates an ObjectValue for an insertion/replacement of an object extent.
1178    pub fn extent_with_checksum(
1179        device_offset: u64,
1180        checksum: Checksums,
1181        key_id: u64,
1182    ) -> ObjectValue {
1183        ObjectValue::Extent(ExtentValue::with_checksum(device_offset, checksum, key_id))
1184    }
1185    /// Creates an ObjectValue for a deletion of an object extent.
1186    pub fn deleted_extent() -> ObjectValue {
1187        ObjectValue::Extent(ExtentValue::deleted_extent())
1188    }
1189    /// Creates an ObjectValue for an object child.
1190    pub fn child(object_id: u64, object_descriptor: ObjectDescriptor) -> ObjectValue {
1191        ObjectValue::Child(ChildValue { object_id, object_descriptor })
1192    }
1193    /// Creates an ObjectValue for an object symlink.
1194    pub fn symlink(
1195        link: impl Into<Box<[u8]>>,
1196        creation_time: Timestamp,
1197        modification_time: Timestamp,
1198        project_id: Option<ProjectId>,
1199    ) -> ObjectValue {
1200        ObjectValue::Object {
1201            kind: ObjectKind::Symlink { refs: 1, link: link.into() },
1202            attributes: ObjectAttributes {
1203                creation_time,
1204                modification_time,
1205                project_id,
1206                ..Default::default()
1207            },
1208        }
1209    }
1210    /// Creates an ObjectValue for an encrypted symlink object.
1211    pub fn encrypted_symlink(
1212        link: impl Into<Box<[u8]>>,
1213        creation_time: Timestamp,
1214        modification_time: Timestamp,
1215        project_id: Option<ProjectId>,
1216    ) -> ObjectValue {
1217        ObjectValue::Object {
1218            kind: ObjectKind::EncryptedSymlink { refs: 1, link: link.into() },
1219            attributes: ObjectAttributes {
1220                creation_time,
1221                modification_time,
1222                project_id,
1223                ..Default::default()
1224            },
1225        }
1226    }
1227    /// Creates an ObjectValue for a non-inline symlink object whose target is stored in
1228    /// `AttributeId::DATA`.
1229    pub fn non_inline_symlink(
1230        creation_time: Timestamp,
1231        modification_time: Timestamp,
1232        project_id: Option<ProjectId>,
1233    ) -> ObjectValue {
1234        ObjectValue::Object {
1235            kind: ObjectKind::NonInlineSymlink { refs: 1 },
1236            attributes: ObjectAttributes {
1237                creation_time,
1238                modification_time,
1239                project_id,
1240                ..Default::default()
1241            },
1242        }
1243    }
1244    pub fn inline_extended_attribute(value: impl Into<Vec<u8>>) -> ObjectValue {
1245        ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value.into()))
1246    }
1247    pub fn extended_attribute(attribute_id: AttributeId) -> ObjectValue {
1248        ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(attribute_id))
1249    }
1250}
1251
1252pub type ObjectItem = ObjectItemV62;
1253
1254pub type ObjectItemV62 = Item<ObjectKeyV54, ObjectValueV62>;
1255
1256impl ObjectItem {
1257    pub fn is_tombstone(&self) -> bool {
1258        matches!(
1259            self,
1260            Item {
1261                key: ObjectKey { data: ObjectKeyData::Object, .. },
1262                value: ObjectValue::None,
1263                ..
1264            }
1265        )
1266    }
1267}
1268
1269// If the given item describes an extent, unwraps it and returns the extent key/value.
1270impl<'a> From<ItemRef<'a, ObjectKey, ObjectValue>>
1271    for Option<(/*object-id*/ u64, AttributeId, &'a Extent, &'a ExtentValue)>
1272{
1273    fn from(item: ItemRef<'a, ObjectKey, ObjectValue>) -> Self {
1274        match item {
1275            ItemRef {
1276                key:
1277                    ObjectKey {
1278                        object_id,
1279                        data:
1280                            ObjectKeyData::Attribute(
1281                                attribute_id, //
1282                                AttributeKey::Extent(extent_key),
1283                            ),
1284                    },
1285                value: ObjectValue::Extent(extent_value),
1286                ..
1287            } => Some((*object_id, *attribute_id, extent_key, extent_value)),
1288            _ => None,
1289        }
1290    }
1291}
1292
1293pub type FxfsKey = FxfsKeyV49;
1294pub type FxfsKeyV49 = fxfs_crypto::FxfsKey;
1295
1296#[derive(
1297    Clone,
1298    Copy,
1299    PartialEq,
1300    Eq,
1301    PartialOrd,
1302    Ord,
1303    Debug,
1304    Serialize,
1305    Deserialize,
1306    Hash,
1307    SerializeKey,
1308    TypeFingerprint,
1309)]
1310#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
1311#[repr(transparent)]
1312pub struct AttributeId(pub u64);
1313
1314impl AttributeId {
1315    /// The common case for extents which cover the data payload of an object.
1316    pub const DATA: Self = Self(0);
1317
1318    /// Contains a serialized and versioned `BlobMetadata` struct. Use [`BlobMetadata::read_from`]
1319    /// and [`BlobMetadata::write_to`] to access this attribute.
1320    pub const BLOB_METADATA: Self = Self(3);
1321
1322    /// Contains a serialized `BlobMetadataUnversioned` struct. This attribute may still exist on
1323    /// blobs but should no longer be written. Use `AttributeId::BLOB_METADATA` instead.
1324    pub const BLOB_MERKLE: Self = Self(1);
1325
1326    /// For fsverity files in Fxfs, we store the merkle tree of the verified file at a well-known
1327    /// attribute.
1328    pub const FSVERITY_MERKLE: Self = Self(2);
1329
1330    /// For storing an associated profile of paging activity.
1331    pub const PROFILE_RECORDING: Self = Self(4);
1332
1333    /// The range of fxfs attribute IDs which are reserved for extended attribute values. Whenever a
1334    /// new attribute is needed, the first unused ID will be chosen from this range. It's
1335    /// technically safe to change these values, but it has potential consequences - they are only
1336    /// used during ID selection, so any existing extended attributes keep their IDs, which means
1337    /// any past or present selected range here could potentially have used attributes unless they
1338    /// are explicitly migrated, which isn't currently done.
1339    pub const XATTR_RANGE_START: Self = Self(64);
1340    pub const XATTR_RANGE_END: Self = Self(512);
1341
1342    /// A semantic alias for the `0` attribute ID, indicating that it is being used as a starting
1343    /// point to iterate over all attributes rather than specifically looking up the primary data
1344    /// attribute [`AttributeId::DATA`].
1345    pub const SORTED_START: Self = Self(0);
1346
1347    /// An attribute ID to use in tests when no particular ID is necessary.
1348    #[cfg(test)]
1349    pub const TEST_ID: Self = Self(u64::MAX - 1000);
1350
1351    pub const fn raw(self) -> u64 {
1352        self.0
1353    }
1354
1355    /// Returns the current id + 1.
1356    pub const fn next(self) -> Self {
1357        Self(self.0 + 1)
1358    }
1359
1360    /// Returns true if the attribute ID is within the range of extended attributes.
1361    pub const fn is_xattr(self) -> bool {
1362        self.0 >= Self::XATTR_RANGE_START.0 && self.0 < Self::XATTR_RANGE_END.0
1363    }
1364}
1365
1366impl log::kv::ToValue for AttributeId {
1367    fn to_value(&self) -> log::kv::Value<'_> {
1368        log::kv::Value::from(self.0)
1369    }
1370}
1371
1372impl std::fmt::Display for AttributeId {
1373    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1374        std::fmt::Display::fmt(&self.0, f)
1375    }
1376}
1377
1378#[cfg(test)]
1379mod tests {
1380    use super::{AttributeId, ObjectKey, ObjectKeyV54, TimestampV49};
1381    use crate::lsm_tree::types::{FuzzyHash as _, LayerKey};
1382    use crate::object_store::extent::MIN_BLOCK_SIZE;
1383    use std::ops::Add;
1384    use std::time::{Duration, SystemTime, UNIX_EPOCH};
1385
1386    // Smoke test to ensure hash stability for Fxfs objects.
1387    // If this test fails, the hash algorithm changed, and that won't do -- Fxfs relies on stable
1388    // hash values, and existing images will appear to be corrupt if they change (see
1389    // https://fxbug.dev/419133532).
1390    #[test]
1391    fn test_hash_stability() {
1392        // Target a specific version of ObjectKey.  If you want to delete ObjectKeyV54, simply
1393        // update this test with a later key version, which will also require re-generating the
1394        // hashes.
1395        assert_eq!(
1396            &ObjectKeyV54::object(100).fuzzy_hash().collect::<Vec<_>>()[..],
1397            &[11885326717398844384]
1398        );
1399        assert_eq!(
1400            &ObjectKeyV54::extent(1, AttributeId::DATA, 0..2 * 1024 * 1024)
1401                .fuzzy_hash()
1402                .collect::<Vec<_>>()[..],
1403            &[11090579907097549012, 2814892992701560424]
1404        );
1405    }
1406
1407    #[test]
1408    fn test_fuzzy_hash_len() {
1409        let key = ObjectKey::object(100);
1410        let mut iter = key.fuzzy_hash();
1411        assert_eq!(iter.len(), 1);
1412        assert_eq!(iter.size_hint(), (1, Some(1)));
1413        assert!(iter.next().is_some());
1414        assert_eq!(iter.len(), 0);
1415        assert_eq!(iter.size_hint(), (0, Some(0)));
1416        assert_eq!(iter.next(), None);
1417
1418        let key = ObjectKey::extent(1, AttributeId::DATA, 0..2 * 1024 * 1024);
1419        let mut iter = key.fuzzy_hash();
1420        assert_eq!(iter.len(), 2);
1421        assert_eq!(iter.size_hint(), (2, Some(2)));
1422        assert!(iter.next().is_some());
1423        assert_eq!(iter.len(), 1);
1424        assert_eq!(iter.size_hint(), (1, Some(1)));
1425        assert!(iter.next().is_some());
1426        assert_eq!(iter.len(), 0);
1427        assert_eq!(iter.size_hint(), (0, Some(0)));
1428        assert_eq!(iter.next(), None);
1429    }
1430
1431    #[test]
1432    fn test_next_key() {
1433        assert_eq!(
1434            ObjectKey::extent(1, AttributeId::TEST_ID, 25 * MIN_BLOCK_SIZE..100 * MIN_BLOCK_SIZE)
1435                .next_key()
1436                .unwrap(),
1437            ObjectKey::extent(1, AttributeId::TEST_ID, 100 * MIN_BLOCK_SIZE..101 * MIN_BLOCK_SIZE)
1438        );
1439        assert_eq!(ObjectKey::object(100).next_key(), None);
1440    }
1441
1442    #[test]
1443    fn test_range_key() {
1444        const ATTR_ID: AttributeId = AttributeId::TEST_ID;
1445        // Make sure we disallow using extent keys with point queries. Other object keys should
1446        // still be allowed with point queries.
1447        assert!(ObjectKey::extent(1, ATTR_ID, 0..2 * 1024 * 1024).is_range_key());
1448        assert!(!ObjectKey::object(100).is_range_key());
1449
1450        assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(1)), true);
1451        assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(2)), false);
1452        assert_eq!(ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::object(1)), false);
1453        assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)), false);
1454        assert_eq!(
1455            ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(2, ATTR_ID, 0..100)),
1456            false
1457        );
1458        assert_eq!(
1459            ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(
1460                1,
1461                ATTR_ID.next(),
1462                0..100
1463            )),
1464            false
1465        );
1466        assert_eq!(
1467            ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)),
1468            true
1469        );
1470
1471        assert_eq!(
1472            ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 49..100)),
1473            true
1474        );
1475        assert_eq!(
1476            ObjectKey::extent(1, ATTR_ID, 49..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1477            true
1478        );
1479
1480        assert_eq!(
1481            ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 50..100)),
1482            false
1483        );
1484        assert_eq!(
1485            ObjectKey::extent(1, ATTR_ID, 50..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1486            false
1487        );
1488    }
1489
1490    #[test]
1491    fn test_timestamp() {
1492        fn compare_time(std_time: Duration) {
1493            let ts_time: TimestampV49 = std_time.into();
1494            assert_eq!(<TimestampV49 as Into<Duration>>::into(ts_time), std_time);
1495            assert_eq!(ts_time.subsec_nanos(), std_time.subsec_nanos());
1496            assert_eq!(ts_time.as_secs(), std_time.as_secs());
1497            assert_eq!(ts_time.as_nanos() as u128, std_time.as_nanos());
1498        }
1499        compare_time(Duration::from_nanos(0));
1500        compare_time(Duration::from_nanos(u64::MAX));
1501        compare_time(SystemTime::now().duration_since(UNIX_EPOCH).unwrap());
1502
1503        let ts: TimestampV49 = Duration::from_secs(u64::MAX - 1).into();
1504        assert_eq!(ts.nanos, u64::MAX);
1505
1506        let ts: TimestampV49 = (Duration::from_nanos(u64::MAX).add(Duration::from_nanos(1))).into();
1507        assert_eq!(ts.nanos, u64::MAX);
1508    }
1509
1510    #[test]
1511    fn test_legacy_fxfs_key_decoding_fails() {
1512        use fxfs_crypto::{EncryptionKey, FXFS_WRAPPED_KEY_SIZE, FxfsKey, WrappedKeyBytes};
1513
1514        let key = EncryptionKey::LegacyFxfs(FxfsKey {
1515            wrapping_key_id: [1; 16],
1516            key: WrappedKeyBytes([2; FXFS_WRAPPED_KEY_SIZE]),
1517        });
1518        let mut buf = Vec::new();
1519        bincode::serialize_into(&mut buf, &key).expect("serialize succeeds");
1520        assert!(bincode::deserialize::<EncryptionKey>(&buf).is_err());
1521    }
1522}