1mod legacy;
6
7use crate::checksum::Checksums;
9use crate::log::error;
10use crate::lsm_tree::types::{
11 FuzzyHash, Item, ItemRef, LayerKey, MergeType, OrdLowerBound, OrdUpperBound, SortByU64, Value,
12};
13use crate::object_store::ProjectId;
14use crate::object_store::extent::{Extent, ExtentPartitionIterator};
15use crate::object_store::extent_record::{ExtentValue, ExtentValueV38};
16use crate::serialized_types::Versioned;
17use fprint::TypeFingerprint;
18use fxfs_crypto::{WrappedKey, WrappingKeyId};
19use fxfs_macros::SerializeKey;
20use fxfs_unicode::CasefoldString;
21use serde::{Deserialize, Serialize};
22use std::collections::BTreeMap;
23use std::default::Default;
24use std::hash::Hash;
25use std::time::{Duration, SystemTime, UNIX_EPOCH};
26
27pub type ObjectDescriptor = ObjectDescriptorV32;
29
30#[derive(Copy, Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
31#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
32pub enum ObjectDescriptorV32 {
33 File,
35 Directory,
37 Volume,
39 Symlink,
41}
42
43pub type ProjectProperty = ProjectPropertyV32;
45
46#[derive(
47 Clone,
48 Debug,
49 Eq,
50 Hash,
51 Ord,
52 PartialEq,
53 PartialOrd,
54 Serialize,
55 Deserialize,
56 TypeFingerprint,
57 SerializeKey,
58)]
59#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
60pub enum ProjectPropertyV32 {
61 Limit,
63 Usage,
65}
66
67pub type ObjectKeyData = ObjectKeyDataV54;
68
69#[derive(
70 Clone,
71 Debug,
72 Eq,
73 Hash,
74 PartialEq,
75 PartialOrd,
76 Ord,
77 Serialize,
78 Deserialize,
79 TypeFingerprint,
80 SerializeKey,
81)]
82#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
83pub enum ObjectKeyDataV54 {
84 Object,
87 Keys,
89 Attribute(AttributeId, AttributeKeyV32),
91 Child { name: String },
93 GraveyardEntry { object_id: u64 },
95 Project { project_id: ProjectId, property: ProjectPropertyV32 },
99 ExtendedAttribute {
102 #[serde(with = "crate::zerocopy_serialization")]
103 name: Vec<u8>,
104 },
105 GraveyardAttributeEntry { object_id: u64, attribute_id: AttributeId },
107 EncryptedCasefoldChild(EncryptedCasefoldChild),
112 LegacyCasefoldChild(CasefoldString),
114 EncryptedChild(EncryptedChild),
116 CasefoldChild { hash_code: u32, name: String },
119}
120
121#[derive(
122 Clone,
123 Debug,
124 Eq,
125 Hash,
126 PartialEq,
127 PartialOrd,
128 Ord,
129 Serialize,
130 Deserialize,
131 TypeFingerprint,
132 SerializeKey,
133)]
134#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
135pub struct EncryptedCasefoldChild {
136 pub hash_code: u32,
137 #[serde(with = "crate::zerocopy_serialization")]
138 pub name: Vec<u8>,
139}
140
141#[derive(
142 Clone,
143 Debug,
144 Eq,
145 Hash,
146 PartialEq,
147 PartialOrd,
148 Ord,
149 Serialize,
150 Deserialize,
151 TypeFingerprint,
152 SerializeKey,
153)]
154#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
155pub struct EncryptedChild(#[serde(with = "crate::zerocopy_serialization")] pub Vec<u8>);
156
157pub type AttributeKey = AttributeKeyV32;
158
159#[derive(
160 Clone,
161 Debug,
162 Eq,
163 Hash,
164 Ord,
165 PartialEq,
166 PartialOrd,
167 Serialize,
168 Deserialize,
169 TypeFingerprint,
170 SerializeKey,
171)]
172#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
173pub enum AttributeKeyV32 {
174 Attribute,
176 Extent(Extent),
177}
178
179pub type ObjectKey = ObjectKeyV54;
181
182#[derive(
183 Clone,
184 Debug,
185 Eq,
186 Ord,
187 Hash,
188 PartialEq,
189 PartialOrd,
190 Serialize,
191 Deserialize,
192 SerializeKey,
193 TypeFingerprint,
194 Versioned,
195)]
196#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
197pub struct ObjectKeyV54 {
198 pub object_id: u64,
200 pub data: ObjectKeyDataV54,
202}
203
204impl SortByU64 for ObjectKey {
205 fn get_leading_u64(&self) -> u64 {
206 self.object_id
207 }
208}
209
210impl ObjectKey {
211 pub fn object(object_id: u64) -> Self {
213 Self { object_id: object_id, data: ObjectKeyData::Object }
214 }
215
216 pub fn keys(object_id: u64) -> Self {
218 Self { object_id, data: ObjectKeyData::Keys }
219 }
220
221 pub fn attribute(object_id: u64, attribute_id: AttributeId, key: AttributeKey) -> Self {
223 Self { object_id, data: ObjectKeyData::Attribute(attribute_id, key) }
224 }
225
226 pub fn extent(object_id: u64, attribute_id: AttributeId, range: std::ops::Range<u64>) -> Self {
228 Self {
229 object_id,
230 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(Extent(range))),
231 }
232 }
233
234 pub fn from_extent(object_id: u64, attribute_id: AttributeId, extent: Extent) -> Self {
236 Self {
237 object_id,
238 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(extent)),
239 }
240 }
241
242 pub fn child(object_id: u64, name: &str, dir_type: DirType) -> Self {
244 match dir_type {
245 DirType::Casefold => {
246 let cf = fxfs_unicode::CasefoldStr::new(name);
247 let casefolded = cf.casefold_normalized_chars().flat_map(fxfs_unicode::utf8_bytes);
248 let hash_code = fscrypt::direntry::tea_hash_filename(casefolded);
249 Self {
250 object_id,
251 data: ObjectKeyData::CasefoldChild { hash_code, name: name.into() },
252 }
253 }
254 DirType::LegacyCasefold => Self {
255 object_id,
256 data: ObjectKeyData::LegacyCasefoldChild(CasefoldString::new(name.into())),
257 },
258 DirType::Normal => Self { object_id, data: ObjectKeyData::Child { name: name.into() } },
259 DirType::Encrypted(_) | DirType::EncryptedCasefold(_) => {
260 panic!("Encrypted modes require an encrypted name");
262 }
263 }
264 }
265
266 pub fn encrypted_child(object_id: u64, name: Vec<u8>, hash_code: Option<u32>) -> Self {
276 if let Some(hash_code) = hash_code {
277 Self {
278 object_id,
279 data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
280 hash_code,
281 name,
282 }),
283 }
284 } else {
285 Self { object_id, data: ObjectKeyData::EncryptedChild(EncryptedChild(name)) }
286 }
287 }
288
289 pub fn graveyard_entry(graveyard_object_id: u64, object_id: u64) -> Self {
291 Self { object_id: graveyard_object_id, data: ObjectKeyData::GraveyardEntry { object_id } }
292 }
293
294 pub fn graveyard_attribute_entry(
296 graveyard_object_id: u64,
297 object_id: u64,
298 attribute_id: AttributeId,
299 ) -> Self {
300 Self {
301 object_id: graveyard_object_id,
302 data: ObjectKeyData::GraveyardAttributeEntry { object_id, attribute_id },
303 }
304 }
305
306 pub fn project_limit(object_id: u64, project_id: ProjectId) -> Self {
308 Self {
309 object_id,
310 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Limit },
311 }
312 }
313
314 pub fn project_usage(object_id: u64, project_id: ProjectId) -> Self {
316 Self {
317 object_id,
318 data: ObjectKeyData::Project { project_id, property: ProjectProperty::Usage },
319 }
320 }
321
322 pub fn extended_attribute(object_id: u64, name: Vec<u8>) -> Self {
323 Self { object_id, data: ObjectKeyData::ExtendedAttribute { name } }
324 }
325
326 pub fn key_for_merge_into(&self) -> Self {
329 if let Self {
330 object_id,
331 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
332 } = self
333 {
334 Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.key_for_merge_into()))
335 } else {
336 self.clone()
337 }
338 }
339}
340
341impl OrdUpperBound for ObjectKey {
342 fn cmp_upper_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
343 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
344 (
345 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
346 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
347 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_upper_bound(right_extent)),
348 _ => self.data.cmp(&other.data),
349 })
350 }
351}
352
353impl OrdLowerBound for ObjectKey {
354 fn cmp_lower_bound(&self, other: &ObjectKey) -> std::cmp::Ordering {
355 self.object_id.cmp(&other.object_id).then_with(|| match (&self.data, &other.data) {
356 (
357 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_extent)),
358 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_extent)),
359 ) => left_attr_id.cmp(right_attr_id).then(left_extent.cmp_lower_bound(right_extent)),
360 _ => self.data.cmp(&other.data),
361 })
362 }
363}
364
365impl LayerKey for ObjectKey {
366 fn merge_type(&self) -> MergeType {
367 match self.data {
370 ObjectKeyData::Object
371 | ObjectKeyData::Keys
372 | ObjectKeyData::Attribute(..)
373 | ObjectKeyData::Child { .. }
374 | ObjectKeyData::EncryptedChild(_)
375 | ObjectKeyData::EncryptedCasefoldChild(_)
376 | ObjectKeyData::CasefoldChild { .. }
377 | ObjectKeyData::LegacyCasefoldChild(_)
378 | ObjectKeyData::GraveyardEntry { .. }
379 | ObjectKeyData::GraveyardAttributeEntry { .. }
380 | ObjectKeyData::Project { property: ProjectProperty::Limit, .. }
381 | ObjectKeyData::ExtendedAttribute { .. } => MergeType::OptimizedMerge,
382 ObjectKeyData::Project { property: ProjectProperty::Usage, .. } => MergeType::FullMerge,
383 }
384 }
385
386 fn next_key(&self) -> Option<Self> {
387 match &self.data {
388 ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
389 Some(ObjectKey {
393 object_id: self.object_id,
394 data: ObjectKeyData::Attribute(
395 *attr_id,
396 AttributeKey::Extent(Extent::search_key_from_offset(extent.end)),
397 ),
398 })
399 }
400 _ => None,
401 }
402 }
403
404 fn search_key(&self) -> Option<Self> {
405 if let Self {
406 object_id,
407 data: ObjectKeyData::Attribute(attribute_id, AttributeKey::Extent(e)),
408 } = self
409 {
410 Some(Self::attribute(*object_id, *attribute_id, AttributeKey::Extent(e.search_key())))
411 } else {
412 None
413 }
414 }
415
416 fn is_search_key(&self) -> bool {
417 match self {
418 Self { data: ObjectKeyData::Attribute(_, AttributeKey::Extent(e)), .. } => {
419 e.is_search_key()
420 }
421 _ => true,
422 }
423 }
424
425 fn overlaps(&self, other: &Self) -> bool {
426 if self.object_id != other.object_id {
427 return false;
428 }
429 match (&self.data, &other.data) {
430 (
431 ObjectKeyData::Attribute(left_attr_id, AttributeKey::Extent(left_key)),
432 ObjectKeyData::Attribute(right_attr_id, AttributeKey::Extent(right_key)),
433 ) if *left_attr_id == *right_attr_id => left_key.overlaps(right_key),
434 (a, b) => a == b,
435 }
436 }
437}
438
439pub enum ObjectKeyFuzzyHashIterator {
440 Extent(u64, AttributeId, ExtentPartitionIterator),
441 NotExtent(Option<u64>),
442}
443
444impl Iterator for ObjectKeyFuzzyHashIterator {
445 type Item = u64;
446
447 fn next(&mut self) -> Option<Self::Item> {
448 match self {
449 Self::Extent(oid, attr_id, extent_keys) => extent_keys.next().map(|range| {
450 let key = ObjectKey::extent(*oid, *attr_id, range);
451 crate::stable_hash::stable_hash(key)
452 }),
453 Self::NotExtent(hash) => hash.take(),
454 }
455 }
456
457 fn size_hint(&self) -> (usize, Option<usize>) {
458 match self {
459 Self::Extent(_, _, extent_keys) => extent_keys.size_hint(),
460 Self::NotExtent(hash) => {
461 let len = if hash.is_some() { 1 } else { 0 };
462 (len, Some(len))
463 }
464 }
465 }
466}
467
468impl ExactSizeIterator for ObjectKeyFuzzyHashIterator {}
469
470impl FuzzyHash for ObjectKey {
471 fn fuzzy_hash(&self) -> impl ExactSizeIterator<Item = u64> {
472 match &self.data {
473 ObjectKeyData::Attribute(attr_id, AttributeKey::Extent(extent)) => {
474 ObjectKeyFuzzyHashIterator::Extent(
475 self.object_id,
476 *attr_id,
477 extent.fuzzy_hash_partition(),
478 )
479 }
480 _ => {
481 let hash = crate::stable_hash::stable_hash(self);
482 ObjectKeyFuzzyHashIterator::NotExtent(Some(hash))
483 }
484 }
485 }
486
487 fn is_range_key(&self) -> bool {
488 match &self.data {
489 ObjectKeyData::Attribute(_, AttributeKey::Extent(_)) => true,
490 _ => false,
491 }
492 }
493}
494
495pub type Timestamp = TimestampV49;
497
498#[derive(
499 Copy,
500 Clone,
501 Debug,
502 Default,
503 Eq,
504 PartialEq,
505 Ord,
506 PartialOrd,
507 Serialize,
508 Deserialize,
509 TypeFingerprint,
510)]
511#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
512pub struct TimestampV49 {
513 nanos: u64,
514}
515
516impl Timestamp {
517 const NSEC_PER_SEC: u64 = 1_000_000_000;
518
519 pub fn now() -> Self {
520 SystemTime::now().duration_since(UNIX_EPOCH).unwrap_or(Duration::ZERO).into()
521 }
522
523 pub const fn zero() -> Self {
524 Self { nanos: 0 }
525 }
526
527 pub const fn from_nanos(nanos: u64) -> Self {
528 Self { nanos }
529 }
530
531 pub fn from_secs_and_nanos(secs: u64, nanos: u32) -> Self {
532 let Some(secs_in_nanos) = secs.checked_mul(Self::NSEC_PER_SEC) else {
533 error!("Fxfs doesn't support dates past 2554-07-21");
534 return Self { nanos: u64::MAX };
535 };
536 let Some(nanos) = secs_in_nanos.checked_add(nanos as u64) else {
537 error!("Fxfs doesn't support dates past 2554-07-21");
538 return Self { nanos: u64::MAX };
539 };
540 Self { nanos }
541 }
542
543 pub fn as_nanos(&self) -> u64 {
546 self.nanos
547 }
548
549 pub fn subsec_nanos(&self) -> u32 {
551 (self.nanos % Self::NSEC_PER_SEC) as u32
552 }
553
554 pub fn as_secs(&self) -> u64 {
557 self.nanos / Self::NSEC_PER_SEC
558 }
559}
560
561impl From<std::time::Duration> for Timestamp {
562 fn from(duration: std::time::Duration) -> Self {
563 Self::from_secs_and_nanos(duration.as_secs(), duration.subsec_nanos())
564 }
565}
566
567impl From<Timestamp> for std::time::Duration {
568 fn from(timestamp: Timestamp) -> std::time::Duration {
569 Duration::from_nanos(timestamp.nanos)
570 }
571}
572
573pub type ObjectKind = ObjectKindV54;
574
575#[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq, TypeFingerprint)]
576#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
577pub enum DirType {
578 Normal,
579 Encrypted(WrappingKeyId),
580 LegacyCasefold,
582 Casefold,
583 EncryptedCasefold(WrappingKeyId),
584}
585
586impl DirType {
587 pub fn is_casefold(&self) -> bool {
588 matches!(self, DirType::LegacyCasefold | DirType::Casefold | DirType::EncryptedCasefold(_))
589 }
590
591 pub fn is_encrypted(&self) -> bool {
592 matches!(self, DirType::Encrypted(_) | DirType::EncryptedCasefold(_))
593 }
594
595 pub fn with_encryption(self, id: WrappingKeyId) -> Self {
596 match self {
597 DirType::Normal => DirType::Encrypted(id),
598 DirType::Casefold => DirType::EncryptedCasefold(id),
599 _ => self,
600 }
601 }
602
603 pub fn with_casefold(self, val: bool) -> Self {
604 match (val, self) {
605 (true, DirType::Encrypted(id) | DirType::EncryptedCasefold(id)) => {
606 DirType::EncryptedCasefold(id)
607 }
608 (true, _) => DirType::Casefold,
609 (false, DirType::Encrypted(id) | DirType::EncryptedCasefold(id)) => {
610 DirType::Encrypted(id)
611 }
612 (false, _) => DirType::Normal,
613 }
614 }
615
616 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
617 match self {
618 DirType::Encrypted(id) | DirType::EncryptedCasefold(id) => Some(*id),
619 _ => None,
620 }
621 }
622}
623
624impl Default for DirType {
625 fn default() -> Self {
626 DirType::Normal
627 }
628}
629
630#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
631#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
632pub enum ObjectKindV54 {
633 File {
634 refs: u64,
636 },
637 Directory {
638 sub_dirs: u64,
640 dir_type: DirType,
642 },
643 Graveyard,
644 Symlink {
645 refs: u64,
647 #[serde(with = "crate::zerocopy_serialization")]
650 link: Box<[u8]>,
651 },
652 EncryptedSymlink {
653 refs: u64,
655 #[serde(with = "crate::zerocopy_serialization")]
660 link: Box<[u8]>,
661 },
662}
663
664#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
665#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
666pub enum ObjectKindV49 {
667 File {
668 refs: u64,
670 },
671 Directory {
672 sub_dirs: u64,
674 wrapping_key_id: Option<WrappingKeyId>,
677 casefold: bool,
680 },
681 Graveyard,
682 Symlink {
683 refs: u64,
685 #[serde(with = "crate::zerocopy_serialization")]
688 link: Box<[u8]>,
689 },
690 EncryptedSymlink {
691 refs: u64,
693 #[serde(with = "crate::zerocopy_serialization")]
698 link: Box<[u8]>,
699 },
700}
701
702pub type PosixAttributes = PosixAttributesV32;
705
706#[derive(Clone, Debug, Copy, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
707#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
708pub struct PosixAttributesV32 {
709 pub mode: u32,
711 pub uid: u32,
713 pub gid: u32,
715 pub rdev: u64,
717}
718
719pub type ObjectAttributes = ObjectAttributesV49;
723
724#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq, TypeFingerprint)]
725#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
726pub struct ObjectAttributesV49 {
727 pub creation_time: TimestampV49,
729 pub modification_time: TimestampV49,
731 #[serde(with = "crate::object_store::project_id::optional_project_id")]
733 pub project_id: Option<ProjectId>,
734 pub posix_attributes: Option<PosixAttributesV32>,
736 pub allocated_size: u64,
738 pub access_time: TimestampV49,
740 pub change_time: TimestampV49,
742}
743
744pub type ExtendedAttributeValue = ExtendedAttributeValueV32;
745
746#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint)]
747#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
748pub enum ExtendedAttributeValueV32 {
749 Inline(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
752 AttributeId(AttributeId),
755}
756
757pub type ChildValue = ChildValueV32;
759
760#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
761#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
762pub struct ChildValueV32 {
763 pub object_id: u64,
765 pub object_descriptor: ObjectDescriptorV32,
767}
768
769pub type RootDigest = RootDigestV33;
770
771#[derive(
772 Clone, Debug, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize, Deserialize, TypeFingerprint,
773)]
774#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
775pub enum RootDigestV33 {
776 Sha256([u8; 32]),
777 Sha512(#[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
778}
779
780pub type FsverityMetadata = FsverityMetadataV50;
781
782#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, TypeFingerprint, Versioned)]
783#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
784pub enum FsverityMetadataV50 {
785 Internal(RootDigestV33, #[serde(with = "crate::zerocopy_serialization")] Vec<u8>),
787 F2fs(std::ops::Range<u64>),
789}
790
791pub type EncryptionKey = EncryptionKeyV56;
792pub type EncryptionKeyV56 = fxfs_crypto::EncryptionKey;
793
794pub type EncryptionKeys = EncryptionKeysV56;
795
796#[derive(Clone, Default, Debug, PartialEq, Serialize, Deserialize, TypeFingerprint)]
797#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
798pub struct EncryptionKeysV56(Vec<(u64, EncryptionKeyV56)>);
799
800impl EncryptionKeys {
801 pub fn get(&self, id: u64) -> Option<&EncryptionKey> {
802 self.0.iter().find_map(|(i, key)| (*i == id).then_some(key))
803 }
804
805 pub fn insert(&mut self, id: u64, key: EncryptionKey) {
806 self.0.push((id, key))
807 }
808
809 pub fn remove(&mut self, id: u64) -> Option<EncryptionKey> {
810 if let Some(ix) = self.0.iter().position(|(k, _)| *k == id) {
811 Some(self.0.remove(ix).1)
812 } else {
813 None
814 }
815 }
816}
817
818impl From<EncryptionKeys> for BTreeMap<u64, WrappedKey> {
819 fn from(keys: EncryptionKeys) -> Self {
820 keys.0.into_iter().map(|(id, key)| (id, key.into())).collect()
821 }
822}
823
824impl From<Vec<(u64, EncryptionKey)>> for EncryptionKeys {
825 fn from(value: Vec<(u64, EncryptionKey)>) -> Self {
826 Self(value)
827 }
828}
829
830impl std::ops::Deref for EncryptionKeys {
831 type Target = Vec<(u64, EncryptionKey)>;
832 fn deref(&self) -> &Self::Target {
833 &self.0
834 }
835}
836
837pub type ObjectValue = ObjectValueV56;
841impl Value for ObjectValue {
842 const DELETED_MARKER: Self = Self::None;
843}
844
845#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, TypeFingerprint, Versioned)]
846#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
847pub enum ObjectValueV56 {
848 None,
852 Some,
855 Object { kind: ObjectKindV54, attributes: ObjectAttributesV49 },
857 Keys(EncryptionKeysV56),
859 Attribute { size: u64, has_overwrite_extents: bool },
861 Extent(ExtentValueV38),
863 Child(ChildValue),
865 Trim,
869 BytesAndNodes { bytes: i64, nodes: i64 },
871 ExtendedAttribute(ExtendedAttributeValueV32),
874 VerifiedAttribute { size: u64, fsverity_metadata: FsverityMetadataV50 },
877}
878
879#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
881pub struct BytesAndNodes {
882 pub bytes: i64,
883 pub nodes: i64,
884}
885
886impl BytesAndNodes {
887 pub fn is_zero(&self) -> bool {
888 self.bytes == 0 && self.nodes == 0
889 }
890}
891
892impl std::ops::Add for BytesAndNodes {
893 type Output = Self;
894 fn add(self, rhs: Self) -> Self {
895 Self { bytes: self.bytes + rhs.bytes, nodes: self.nodes + rhs.nodes }
896 }
897}
898
899impl std::ops::AddAssign for BytesAndNodes {
900 fn add_assign(&mut self, rhs: Self) {
901 self.bytes += rhs.bytes;
902 self.nodes += rhs.nodes;
903 }
904}
905
906impl From<BytesAndNodes> for ObjectValue {
907 fn from(value: BytesAndNodes) -> Self {
908 ObjectValue::BytesAndNodes { bytes: value.bytes, nodes: value.nodes }
909 }
910}
911
912impl From<(i64, i64)> for BytesAndNodes {
913 fn from((bytes, nodes): (i64, i64)) -> Self {
914 Self { bytes, nodes }
915 }
916}
917
918impl From<BytesAndNodes> for (i64, i64) {
919 fn from(value: BytesAndNodes) -> Self {
920 (value.bytes, value.nodes)
921 }
922}
923
924impl ObjectValue {
925 pub fn file(
927 refs: u64,
928 allocated_size: u64,
929 creation_time: Timestamp,
930 modification_time: Timestamp,
931 access_time: Timestamp,
932 change_time: Timestamp,
933 project_id: Option<ProjectId>,
934 posix_attributes: Option<PosixAttributes>,
935 ) -> ObjectValue {
936 ObjectValue::Object {
937 kind: ObjectKind::File { refs },
938 attributes: ObjectAttributes {
939 creation_time,
940 modification_time,
941 project_id,
942 posix_attributes,
943 allocated_size,
944 access_time,
945 change_time,
946 },
947 }
948 }
949 pub fn keys(encryption_keys: EncryptionKeys) -> ObjectValue {
950 ObjectValue::Keys(encryption_keys)
951 }
952 pub fn attribute(size: u64, has_overwrite_extents: bool) -> ObjectValue {
954 ObjectValue::Attribute { size, has_overwrite_extents }
955 }
956 pub fn verified_attribute(size: u64, fsverity_metadata: FsverityMetadata) -> ObjectValue {
958 ObjectValue::VerifiedAttribute { size, fsverity_metadata }
959 }
960 pub fn extent(device_offset: u64, key_id: u64) -> ObjectValue {
962 ObjectValue::Extent(ExtentValue::new_raw(device_offset, key_id))
963 }
964 pub fn extent_with_checksum(
966 device_offset: u64,
967 checksum: Checksums,
968 key_id: u64,
969 ) -> ObjectValue {
970 ObjectValue::Extent(ExtentValue::with_checksum(device_offset, checksum, key_id))
971 }
972 pub fn deleted_extent() -> ObjectValue {
974 ObjectValue::Extent(ExtentValue::deleted_extent())
975 }
976 pub fn child(object_id: u64, object_descriptor: ObjectDescriptor) -> ObjectValue {
978 ObjectValue::Child(ChildValue { object_id, object_descriptor })
979 }
980 pub fn symlink(
982 link: impl Into<Box<[u8]>>,
983 creation_time: Timestamp,
984 modification_time: Timestamp,
985 project_id: Option<ProjectId>,
986 ) -> ObjectValue {
987 ObjectValue::Object {
988 kind: ObjectKind::Symlink { refs: 1, link: link.into() },
989 attributes: ObjectAttributes {
990 creation_time,
991 modification_time,
992 project_id,
993 ..Default::default()
994 },
995 }
996 }
997 pub fn encrypted_symlink(
999 link: impl Into<Box<[u8]>>,
1000 creation_time: Timestamp,
1001 modification_time: Timestamp,
1002 project_id: Option<ProjectId>,
1003 ) -> ObjectValue {
1004 ObjectValue::Object {
1005 kind: ObjectKind::EncryptedSymlink { refs: 1, link: link.into() },
1006 attributes: ObjectAttributes {
1007 creation_time,
1008 modification_time,
1009 project_id,
1010 ..Default::default()
1011 },
1012 }
1013 }
1014 pub fn inline_extended_attribute(value: impl Into<Vec<u8>>) -> ObjectValue {
1015 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::Inline(value.into()))
1016 }
1017 pub fn extended_attribute(attribute_id: AttributeId) -> ObjectValue {
1018 ObjectValue::ExtendedAttribute(ExtendedAttributeValue::AttributeId(attribute_id))
1019 }
1020}
1021
1022pub type ObjectItem = ObjectItemV56;
1023
1024pub type ObjectItemV56 = Item<ObjectKeyV54, ObjectValueV56>;
1025
1026impl ObjectItem {
1027 pub fn is_tombstone(&self) -> bool {
1028 matches!(
1029 self,
1030 Item {
1031 key: ObjectKey { data: ObjectKeyData::Object, .. },
1032 value: ObjectValue::None,
1033 ..
1034 }
1035 )
1036 }
1037}
1038
1039impl<'a> From<ItemRef<'a, ObjectKey, ObjectValue>>
1041 for Option<(u64, AttributeId, &'a Extent, &'a ExtentValue)>
1042{
1043 fn from(item: ItemRef<'a, ObjectKey, ObjectValue>) -> Self {
1044 match item {
1045 ItemRef {
1046 key:
1047 ObjectKey {
1048 object_id,
1049 data:
1050 ObjectKeyData::Attribute(
1051 attribute_id, AttributeKey::Extent(extent_key),
1053 ),
1054 },
1055 value: ObjectValue::Extent(extent_value),
1056 ..
1057 } => Some((*object_id, *attribute_id, extent_key, extent_value)),
1058 _ => None,
1059 }
1060 }
1061}
1062
1063pub type FxfsKey = FxfsKeyV49;
1064pub type FxfsKeyV49 = fxfs_crypto::FxfsKey;
1065
1066#[derive(
1067 Clone,
1068 Copy,
1069 PartialEq,
1070 Eq,
1071 PartialOrd,
1072 Ord,
1073 Debug,
1074 Serialize,
1075 Deserialize,
1076 Hash,
1077 SerializeKey,
1078 TypeFingerprint,
1079)]
1080#[cfg_attr(fuzz, derive(arbitrary::Arbitrary))]
1081#[repr(transparent)]
1082pub struct AttributeId(pub u64);
1083
1084impl AttributeId {
1085 pub const DATA: Self = Self(0);
1087
1088 pub const BLOB_METADATA: Self = Self(3);
1091
1092 pub const BLOB_MERKLE: Self = Self(1);
1095
1096 pub const FSVERITY_MERKLE: Self = Self(2);
1099
1100 pub const PROFILE_RECORDING: Self = Self(4);
1102
1103 pub const XATTR_RANGE_START: Self = Self(64);
1110 pub const XATTR_RANGE_END: Self = Self(512);
1111
1112 pub const SORTED_START: Self = Self(0);
1116
1117 #[cfg(test)]
1119 pub const TEST_ID: Self = Self(u64::MAX - 1000);
1120
1121 pub const fn raw(self) -> u64 {
1122 self.0
1123 }
1124
1125 pub const fn next(self) -> Self {
1127 Self(self.0 + 1)
1128 }
1129
1130 pub const fn is_xattr(self) -> bool {
1132 self.0 >= Self::XATTR_RANGE_START.0 && self.0 < Self::XATTR_RANGE_END.0
1133 }
1134}
1135
1136impl log::kv::ToValue for AttributeId {
1137 fn to_value(&self) -> log::kv::Value<'_> {
1138 log::kv::Value::from(self.0)
1139 }
1140}
1141
1142impl std::fmt::Display for AttributeId {
1143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1144 std::fmt::Display::fmt(&self.0, f)
1145 }
1146}
1147
1148#[cfg(test)]
1149mod tests {
1150 use super::{AttributeId, ObjectKey, ObjectKeyV54, TimestampV49};
1151 use crate::lsm_tree::types::{FuzzyHash as _, LayerKey};
1152 use crate::object_store::extent::MIN_BLOCK_SIZE;
1153 use std::ops::Add;
1154 use std::time::{Duration, SystemTime, UNIX_EPOCH};
1155
1156 #[test]
1161 fn test_hash_stability() {
1162 assert_eq!(
1166 &ObjectKeyV54::object(100).fuzzy_hash().collect::<Vec<_>>()[..],
1167 &[11885326717398844384]
1168 );
1169 assert_eq!(
1170 &ObjectKeyV54::extent(1, AttributeId::DATA, 0..2 * 1024 * 1024)
1171 .fuzzy_hash()
1172 .collect::<Vec<_>>()[..],
1173 &[11090579907097549012, 2814892992701560424]
1174 );
1175 }
1176
1177 #[test]
1178 fn test_fuzzy_hash_len() {
1179 let key = ObjectKey::object(100);
1180 let mut iter = key.fuzzy_hash();
1181 assert_eq!(iter.len(), 1);
1182 assert_eq!(iter.size_hint(), (1, Some(1)));
1183 assert!(iter.next().is_some());
1184 assert_eq!(iter.len(), 0);
1185 assert_eq!(iter.size_hint(), (0, Some(0)));
1186 assert_eq!(iter.next(), None);
1187
1188 let key = ObjectKey::extent(1, AttributeId::DATA, 0..2 * 1024 * 1024);
1189 let mut iter = key.fuzzy_hash();
1190 assert_eq!(iter.len(), 2);
1191 assert_eq!(iter.size_hint(), (2, Some(2)));
1192 assert!(iter.next().is_some());
1193 assert_eq!(iter.len(), 1);
1194 assert_eq!(iter.size_hint(), (1, Some(1)));
1195 assert!(iter.next().is_some());
1196 assert_eq!(iter.len(), 0);
1197 assert_eq!(iter.size_hint(), (0, Some(0)));
1198 assert_eq!(iter.next(), None);
1199 }
1200
1201 #[test]
1202 fn test_next_key() {
1203 assert_eq!(
1204 ObjectKey::extent(1, AttributeId::TEST_ID, 25 * MIN_BLOCK_SIZE..100 * MIN_BLOCK_SIZE)
1205 .next_key()
1206 .unwrap(),
1207 ObjectKey::extent(1, AttributeId::TEST_ID, 100 * MIN_BLOCK_SIZE..101 * MIN_BLOCK_SIZE)
1208 );
1209 assert_eq!(ObjectKey::object(100).next_key(), None);
1210 }
1211
1212 #[test]
1213 fn test_range_key() {
1214 const ATTR_ID: AttributeId = AttributeId::TEST_ID;
1215 assert!(ObjectKey::extent(1, ATTR_ID, 0..2 * 1024 * 1024).is_range_key());
1218 assert!(!ObjectKey::object(100).is_range_key());
1219
1220 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(1)), true);
1221 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::object(2)), false);
1222 assert_eq!(ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::object(1)), false);
1223 assert_eq!(ObjectKey::object(1).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)), false);
1224 assert_eq!(
1225 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(2, ATTR_ID, 0..100)),
1226 false
1227 );
1228 assert_eq!(
1229 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(
1230 1,
1231 ATTR_ID.next(),
1232 0..100
1233 )),
1234 false
1235 );
1236 assert_eq!(
1237 ObjectKey::extent(1, ATTR_ID, 0..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..100)),
1238 true
1239 );
1240
1241 assert_eq!(
1242 ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 49..100)),
1243 true
1244 );
1245 assert_eq!(
1246 ObjectKey::extent(1, ATTR_ID, 49..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1247 true
1248 );
1249
1250 assert_eq!(
1251 ObjectKey::extent(1, ATTR_ID, 0..50).overlaps(&ObjectKey::extent(1, ATTR_ID, 50..100)),
1252 false
1253 );
1254 assert_eq!(
1255 ObjectKey::extent(1, ATTR_ID, 50..100).overlaps(&ObjectKey::extent(1, ATTR_ID, 0..50)),
1256 false
1257 );
1258 }
1259
1260 #[test]
1261 fn test_timestamp() {
1262 fn compare_time(std_time: Duration) {
1263 let ts_time: TimestampV49 = std_time.into();
1264 assert_eq!(<TimestampV49 as Into<Duration>>::into(ts_time), std_time);
1265 assert_eq!(ts_time.subsec_nanos(), std_time.subsec_nanos());
1266 assert_eq!(ts_time.as_secs(), std_time.as_secs());
1267 assert_eq!(ts_time.as_nanos() as u128, std_time.as_nanos());
1268 }
1269 compare_time(Duration::from_nanos(0));
1270 compare_time(Duration::from_nanos(u64::MAX));
1271 compare_time(SystemTime::now().duration_since(UNIX_EPOCH).unwrap());
1272
1273 let ts: TimestampV49 = Duration::from_secs(u64::MAX - 1).into();
1274 assert_eq!(ts.nanos, u64::MAX);
1275
1276 let ts: TimestampV49 = (Duration::from_nanos(u64::MAX).add(Duration::from_nanos(1))).into();
1277 assert_eq!(ts.nanos, u64::MAX);
1278 }
1279
1280 #[test]
1281 fn test_legacy_fxfs_key_decoding_fails() {
1282 use fxfs_crypto::{EncryptionKey, FXFS_WRAPPED_KEY_SIZE, FxfsKey, WrappedKeyBytes};
1283
1284 let key = EncryptionKey::LegacyFxfs(FxfsKey {
1285 wrapping_key_id: [1; 16],
1286 key: WrappedKeyBytes([2; FXFS_WRAPPED_KEY_SIZE]),
1287 });
1288 let mut buf = Vec::new();
1289 bincode::serialize_into(&mut buf, &key).expect("serialize succeeds");
1290 assert!(bincode::deserialize::<EncryptionKey>(&buf).is_err());
1291 }
1292}