1use crate::errors::FxfsError;
5use crate::filesystem::TruncateGuard;
6use crate::lsm_tree::Query;
7use crate::lsm_tree::merge::{Merger, MergerIterator};
8use crate::lsm_tree::types::{ItemRef, LayerIterator};
9use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ObjectProperties};
10use crate::object_store::object_record::{
11 BytesAndNodes, ChildValue, DirType, EncryptedCasefoldChild, EncryptedChild, EncryptionKey,
12 FscryptDirInfo, ObjectAttributes, ObjectDescriptor, ObjectKey, ObjectKeyData, ObjectKind,
13 ObjectValue, Timestamp,
14};
15use crate::object_store::transaction::{
16 LockKey, LockKeys, Mutation, Options, ReservationOptions, Transaction, lock_keys,
17};
18use crate::object_store::{
19 AttributeId, DataObjectHandle, HandleOptions, HandleOwner, ObjectStore,
20 SetExtendedAttributeMode, StoreObjectHandle, TombstoneMode, TrimMode, TrimResult,
21};
22use anyhow::{Error, anyhow, bail, ensure};
23use fidl_fuchsia_io as fio;
24use fscrypt::proxy_filename::ProxyFilename;
25use fuchsia_sync::Mutex;
26use fxfs_crypto::{
27 Cipher, CipherHolder, CipherSet, KeyPurpose, MAX_SYMLINK_LEN, ObjectType, WrappingKeyId,
28 key_to_cipher,
29};
30use std::fmt;
31use std::ops::ControlFlow;
32use std::sync::Arc;
33use std::sync::atomic::{AtomicBool, Ordering};
34use zerocopy::IntoBytes;
35
36use super::{FSCRYPT_KEY_ID, VOLUME_DATA_KEY_ID};
37
38pub const MAX_INLINE_SYMLINK_SIZE: usize = 256;
41
42type BoxPredicate<'a> = Box<dyn Fn(&ObjectKey) -> ControlFlow<bool> + Send + 'a>;
43
44pub struct ReplaceContext<'a> {
47 pub transaction: Transaction<'a>,
48 pub truncate_guard: Option<TruncateGuard<'static>>,
49 pub src_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
50 pub dst_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
51 pub src_name: Option<String>,
52 pub dst_name: Option<String>,
53}
54
55pub struct LookupEntry {
56 pub object_id: u64,
57 pub descriptor: ObjectDescriptor,
58 pub key: ObjectKey,
59 pub locked: bool,
60}
61
62pub struct Directory<S: HandleOwner> {
64 handle: StoreObjectHandle<S>,
65 is_deleted: AtomicBool,
67 dir_type: Mutex<DirType>,
69}
70
71#[derive(Clone, Default)]
72pub struct MutableAttributesInternal {
73 sub_dirs: i64,
74 change_time: Option<Timestamp>,
75 modification_time: Option<u64>,
76 creation_time: Option<u64>,
77}
78
79impl MutableAttributesInternal {
80 pub fn new(
81 sub_dirs: i64,
82 change_time: Option<Timestamp>,
83 modification_time: Option<u64>,
84 creation_time: Option<u64>,
85 ) -> Self {
86 Self { sub_dirs, change_time, modification_time, creation_time }
87 }
88}
89
90pub(crate) fn encrypt_filename(
92 key: &dyn Cipher,
93 object_id: u64,
94 name: &str,
95) -> Result<Vec<u8>, Error> {
96 let mut name_bytes = name.as_bytes().to_vec();
97 key.encrypt_filename(object_id, &mut name_bytes)?;
98 Ok(name_bytes)
99}
100
101pub(crate) fn decrypt_filename(
103 key: &dyn Cipher,
104 object_id: u64,
105 data: &[u8],
106) -> Result<String, Error> {
107 let mut raw = data.to_vec();
108 key.decrypt_filename(object_id, &mut raw)?;
109 Ok(String::from_utf8(raw)?)
110}
111
112#[fxfs_trace::trace]
113impl<S: HandleOwner> Directory<S> {
114 fn new(owner: Arc<S>, object_id: u64, dir_type: DirType) -> Self {
115 Directory {
116 handle: StoreObjectHandle::new(
117 owner,
118 object_id,
119 false,
120 HandleOptions::default(),
121 false,
122 ),
123 is_deleted: AtomicBool::new(false),
124 dir_type: Mutex::new(dir_type),
125 }
126 }
127
128 pub async fn get_case_preserved_name(&self, key: ObjectKey) -> Result<Option<String>, Error> {
133 match key.data {
134 ObjectKeyData::Child { name } => Ok(Some(name)),
135 ObjectKeyData::CasefoldChild { name, .. } => Ok(Some(name)),
136 ObjectKeyData::LegacyCasefoldChild(name) => Ok(Some(name.to_string())),
137 ObjectKeyData::EncryptedChild(crate::object_store::object_record::EncryptedChild(
138 name,
139 )) => {
140 if let CipherHolder::Cipher(cipher) = self.get_fscrypt_key().await? {
141 Ok(Some(decrypt_filename(cipher.as_ref(), self.object_id(), &name)?))
142 } else {
143 Ok(None)
144 }
145 }
146 ObjectKeyData::EncryptedCasefoldChild(
147 crate::object_store::object_record::EncryptedCasefoldChild { name, .. },
148 ) => {
149 if let CipherHolder::Cipher(cipher) = self.get_fscrypt_key().await? {
150 Ok(Some(decrypt_filename(cipher.as_ref(), self.object_id(), &name)?))
151 } else {
152 Ok(None)
153 }
154 }
155 _ => Ok(None),
156 }
157 }
158
159 pub fn object_id(&self) -> u64 {
160 self.handle.object_id()
161 }
162
163 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
164 self.dir_type.lock().wrapping_key_id()
165 }
166
167 pub fn fscrypt_info(&self) -> Option<FscryptDirInfo> {
168 self.dir_type.lock().fscrypt_info()
169 }
170
171 pub async fn get_fscrypt_key(&self) -> Result<CipherHolder, Error> {
175 let object_id = self.object_id();
176 let store = self.store();
177 store
178 .key_manager()
179 .get_fscrypt_key(object_id, store.crypt().unwrap().as_ref(), async || {
180 store.get_keys(object_id).await
181 })
182 .await
183 }
184
185 pub fn owner(&self) -> &Arc<S> {
186 self.handle.owner()
187 }
188
189 pub fn store(&self) -> &ObjectStore {
190 self.handle.store()
191 }
192
193 pub fn handle(&self) -> &StoreObjectHandle<S> {
194 &self.handle
195 }
196
197 pub fn is_deleted(&self) -> bool {
198 self.is_deleted.load(Ordering::Relaxed)
199 }
200
201 pub fn set_deleted(&self) {
202 self.is_deleted.store(true, Ordering::Relaxed);
203 }
204
205 pub fn dir_type(&self) -> DirType {
207 *self.dir_type.lock()
208 }
209
210 pub async fn set_casefold(&self, val: bool) -> Result<(), Error> {
212 let dir_type = self.dir_type().with_casefold(val);
213 let mut transaction = self
215 .store()
216 .new_transaction(
217 lock_keys![LockKey::object(self.store().store_object_id(), self.object_id())],
218 Options::default(),
219 )
220 .await?;
221 ensure!(!self.has_children().await?, FxfsError::NotEmpty);
222 let mut mutation =
223 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
224 if let ObjectValue::Object {
225 kind: ObjectKind::Directory { dir_type: dest_dir_type, .. },
226 ..
227 } = &mut mutation.item.value
228 {
229 *dest_dir_type = dir_type;
230 } else {
231 return Err(
232 anyhow!(FxfsError::Inconsistent).context("casefold only applies to directories")
233 );
234 }
235 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
236 transaction.commit_with_callback(|_| *self.dir_type.lock() = dir_type).await?;
237 Ok(())
238 }
239
240 pub async fn create(
241 transaction: &mut Transaction<'_>,
242 owner: &Arc<S>,
243 wrapping_key_id: Option<WrappingKeyId>,
244 ) -> Result<Directory<S>, Error> {
245 let dir_type = match wrapping_key_id {
246 Some(id) => DirType::Encrypted(id.into()),
247 None => DirType::Normal,
248 };
249 Self::create_with_options(transaction, owner, dir_type).await
250 }
251
252 pub async fn create_with_options(
253 transaction: &mut Transaction<'_>,
254 owner: &Arc<S>,
255 dir_type: DirType,
256 ) -> Result<Directory<S>, Error> {
257 let store = owner.as_ref().as_ref();
258 let object_id = store.get_next_object_id(transaction).await?;
259 let now = Timestamp::now();
260
261 let object_id = object_id.release().get();
263 transaction.add(
264 store.store_object_id(),
265 Mutation::insert_object(
266 ObjectKey::object(object_id),
267 ObjectValue::Object {
268 kind: ObjectKind::Directory { sub_dirs: 0, dir_type },
269 attributes: ObjectAttributes {
270 creation_time: now.clone(),
271 modification_time: now.clone(),
272 project_id: None,
273 posix_attributes: None,
274 allocated_size: 0,
275 access_time: now.clone(),
276 change_time: now,
277 },
278 },
279 ),
280 );
281 if let Some(info) = dir_type.fscrypt_info() {
282 if let Some(crypt) = store.crypt() {
283 let (key, unwrapped_key) = crypt
284 .create_key_with_id(
285 object_id,
286 info.wrapping_key_id,
287 ObjectType::Directory,
288 info.flags.into(),
289 )
290 .await?;
291 let cipher = key_to_cipher(&key, &unwrapped_key)?;
292 transaction.add(
293 store.store_object_id(),
294 Mutation::insert_object(
295 ObjectKey::keys(object_id),
296 ObjectValue::keys(vec![(FSCRYPT_KEY_ID, key)].into()),
297 ),
298 );
299 store.key_manager.insert(
304 object_id,
305 Arc::new(vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher))].into()),
306 false,
307 );
308 } else {
309 return Err(anyhow!("No crypt"));
310 }
311 }
312 Ok(Directory::new(owner.clone(), object_id, dir_type))
313 }
314
315 pub async fn set_wrapping_key(
323 &self,
324 transaction: &mut Transaction<'_>,
325 info: impl Into<FscryptDirInfo>,
326 ) -> Result<Arc<dyn Cipher>, Error> {
327 let info = info.into();
328 let object_id = self.object_id();
329 let store = self.store();
330 if let Some(crypt) = store.crypt() {
331 let (key, unwrapped_key) = crypt
332 .create_key_with_id(
333 object_id,
334 info.wrapping_key_id,
335 ObjectType::Directory,
336 info.flags.into(),
337 )
338 .await?;
339 let mut mutation = store.txn_get_object_mutation(transaction, object_id).await?;
340 if let ObjectValue::Object { kind: ObjectKind::Directory { dir_type, .. }, .. } =
341 &mut mutation.item.value
342 {
343 if dir_type.is_encrypted() {
344 return Err(anyhow!("wrapping key id is already set"));
345 }
346 if self.has_children().await? {
347 return Err(FxfsError::NotEmpty.into());
348 }
349 *dir_type = dir_type.with_encryption(info);
350 } else {
351 match mutation.item.value {
352 ObjectValue::None => bail!(FxfsError::NotFound),
353 _ => bail!(FxfsError::NotDir),
354 }
355 }
356 transaction.add(store.store_object_id(), Mutation::ObjectStore(mutation));
357
358 let keys_key = ObjectKey::keys(object_id);
359 let value = if let Some(mutation) =
360 transaction.get_object_mutation(store.store_object_id(), keys_key.clone())
361 {
362 Some(mutation.item.value.clone())
363 } else {
364 store.tree.find_value(&keys_key).await?
365 };
366
367 let cipher = key_to_cipher(&key, &unwrapped_key)?;
368 match value {
369 None | Some(ObjectValue::None) => {
370 transaction.add(
371 store.store_object_id(),
372 Mutation::insert_object(
373 ObjectKey::keys(object_id),
374 ObjectValue::keys(vec![(FSCRYPT_KEY_ID, key)].into()),
375 ),
376 );
377 }
378 Some(ObjectValue::Keys(mut keys)) => {
379 keys.insert(FSCRYPT_KEY_ID, key.into());
380 transaction.add(
381 store.store_object_id(),
382 Mutation::replace_or_insert_object(
383 ObjectKey::keys(object_id),
384 ObjectValue::keys(keys),
385 ),
386 );
387 }
388 Some(value) => bail!("Unexpected value in lookup: {value:?}"),
389 }
390 Ok(cipher)
391 } else {
392 Err(anyhow!("No crypt"))
393 }
394 }
395
396 #[trace]
397 pub async fn open(owner: &Arc<S>, object_id: u64) -> Result<Directory<S>, Error> {
398 let store = owner.as_ref().as_ref();
399 let dir_type = store
400 .tree
401 .find_map(&ObjectKey::object(object_id), |item| match item.value {
402 ObjectValue::Object { kind: ObjectKind::Directory { dir_type, .. }, .. } => {
403 Ok(*dir_type)
404 }
405 _ => bail!(FxfsError::NotDir),
406 })
407 .await?
408 .ok_or(FxfsError::NotFound)??;
409 Ok(Directory::new(owner.clone(), object_id, dir_type))
410 }
411
412 pub fn open_unchecked(owner: Arc<S>, object_id: u64, dir_type: DirType) -> Self {
415 Self::new(owner, object_id, dir_type)
416 }
417
418 pub async fn acquire_context_for_replace(
431 &self,
432 src: Option<(&Directory<S>, &str)>,
433 dst: &str,
434 borrow_metadata_space: bool,
435 ) -> Result<ReplaceContext<'_>, Error> {
436 let store = self.store();
447 let fs = store.filesystem();
448 let mut child_object_id = INVALID_OBJECT_ID;
449 let mut src_object_id = src.map(|_| INVALID_OBJECT_ID);
450 let mut lock_keys = LockKeys::with_capacity(4);
451 lock_keys.push(LockKey::object(store.store_object_id(), self.object_id()));
452 loop {
453 lock_keys.truncate(1);
454 if let Some(src) = src {
455 lock_keys.push(LockKey::object(store.store_object_id(), src.0.object_id()));
456 if let Some(src_object_id) = src_object_id {
457 if src_object_id != INVALID_OBJECT_ID {
458 lock_keys.push(LockKey::object(store.store_object_id(), src_object_id));
459 }
460 }
461 }
462 if child_object_id != INVALID_OBJECT_ID {
463 lock_keys.push(LockKey::object(store.store_object_id(), child_object_id));
464 };
465 let truncate_guard = if child_object_id != INVALID_OBJECT_ID {
466 Some(fs.truncate_guard_owned(store.store_object_id(), child_object_id).await)
467 } else {
468 None
469 };
470 let transaction = store
471 .new_transaction(
472 lock_keys.clone(),
473 Options {
474 reservation: if borrow_metadata_space {
475 ReservationOptions::Borrowed
476 } else {
477 ReservationOptions::New
478 },
479 ..Default::default()
480 },
481 )
482 .await?;
483
484 let mut have_required_locks = true;
485 let mut src_id_and_descriptor = None;
486 let mut src_name_out = None;
487 let mut dst_name_out = None;
488 if let Some((src_dir, src_name)) = src {
489 match src_dir.lookup_ext(src_name).await? {
490 Some(entry) => match entry.descriptor {
491 ObjectDescriptor::File
492 | ObjectDescriptor::Directory
493 | ObjectDescriptor::Symlink => {
494 if src_object_id != Some(entry.object_id) {
495 have_required_locks = false;
496 src_object_id = Some(entry.object_id);
497 }
498 src_id_and_descriptor = Some((entry.object_id, entry.descriptor));
499 src_name_out = Some(
500 src_dir
501 .get_case_preserved_name(entry.key)
502 .await?
503 .unwrap_or_else(|| src_name.to_string()),
504 );
505 }
506 _ => bail!(FxfsError::Inconsistent),
507 },
508 None => {
509 bail!(FxfsError::NotFound)
511 }
512 }
513 };
514 let dst_entry = self.lookup_ext(dst).await?;
515 let dst_id_and_descriptor = match dst_entry {
516 Some(entry) => match entry.descriptor {
517 ObjectDescriptor::File
518 | ObjectDescriptor::Directory
519 | ObjectDescriptor::Symlink => {
520 if child_object_id != entry.object_id {
521 have_required_locks = false;
522 child_object_id = entry.object_id
523 }
524 dst_name_out = Some(
525 self.get_case_preserved_name(entry.key)
526 .await?
527 .unwrap_or_else(|| dst.to_string()),
528 );
529 Some((entry.object_id, entry.descriptor.clone()))
530 }
531 _ => bail!(FxfsError::Inconsistent),
532 },
533 None => {
534 if child_object_id != INVALID_OBJECT_ID {
535 have_required_locks = false;
536 child_object_id = INVALID_OBJECT_ID;
537 }
538 None
539 }
540 };
541 if have_required_locks {
542 return Ok(ReplaceContext {
543 transaction,
544 truncate_guard,
545 src_id_and_descriptor,
546 dst_id_and_descriptor,
547 src_name: src_name_out,
548 dst_name: dst_name_out,
549 });
550 }
551 }
552 }
553
554 async fn has_children(&self) -> Result<bool, Error> {
555 if self.is_deleted() {
556 return Ok(false);
557 }
558 let layer_set = self.store().tree().layer_set();
559 let mut merger = layer_set.merger();
560 Ok(self.iter(&mut merger).await?.get().is_some())
561 }
562
563 #[trace]
567 pub async fn lookup(&self, name: &str) -> Result<Option<(u64, ObjectDescriptor, bool)>, Error> {
568 Ok(self
569 .lookup_ext(name)
570 .await?
571 .map(|entry| (entry.object_id, entry.descriptor, entry.locked)))
572 }
573
574 #[trace]
576 pub async fn lookup_ext(&self, name: &str) -> Result<Option<LookupEntry>, Error> {
577 let _measure =
578 crate::metrics::DurationMeasureScope::new(&crate::metrics::directory_metrics().lookup);
579 if self.is_deleted() {
580 return Ok(None);
581 }
582 let cipher;
583 let proxy_name;
584 let (key, predicate, locked): (_, Option<BoxPredicate<'_>>, _) = if self
588 .dir_type()
589 .is_encrypted()
590 {
591 cipher = self.get_fscrypt_key().await?;
592 match &cipher {
593 CipherHolder::Cipher(cipher) => {
594 if self.dir_type().is_casefold() {
595 let target_hash_code = cipher.hash_code_casefold(name);
598 let key = ObjectKey::encrypted_child(
599 self.object_id(),
600 vec![],
601 Some(target_hash_code),
602 );
603 (
604 key,
605 Some(Box::new(encrypted_casefold_predicate(
606 cipher.as_ref(),
607 self.object_id(),
608 target_hash_code,
609 name,
610 ))),
611 false,
612 )
613 } else {
614 let encrypted_name =
615 encrypt_filename(cipher.as_ref(), self.object_id(), name)?;
616 let hash_code = cipher.hash_code(encrypted_name.as_bytes(), name);
617 (
618 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
619 None,
620 false,
621 )
622 }
623 }
624 CipherHolder::Unavailable => {
625 proxy_name = match ProxyFilename::try_from(name) {
626 Ok(name) => name,
627 Err(_) => return Ok(None),
628 };
629 let (key, predicate) =
630 self.get_key_and_predicate_for_unavailable_cipher(&proxy_name);
631 (key, predicate, true)
632 }
633 }
634 } else {
635 match self.dir_type() {
636 DirType::Casefold => {
637 let target_key = ObjectKey::child(self.object_id(), name, DirType::Casefold);
638 let target_hash_code = match &target_key.data {
639 ObjectKeyData::CasefoldChild { hash_code, .. } => *hash_code,
640 _ => unreachable!(),
641 };
642 (
643 ObjectKey {
644 object_id: self.object_id(),
645 data: ObjectKeyData::CasefoldChild {
646 hash_code: target_hash_code,
647 name: "".to_string(),
648 },
649 },
650 Some(Box::new(casefold_predicate(
651 self.object_id(),
652 target_hash_code,
653 name,
654 ))),
655 false,
656 )
657 }
658 DirType::LegacyCasefold | DirType::Normal => {
659 (ObjectKey::child(self.object_id(), name, self.dir_type()), None, false)
660 }
661 DirType::Encrypted(_) | DirType::EncryptedCasefold(_) => {
662 unreachable!("is_encrypted() was already checked")
663 }
664 }
665 };
666
667 if locked || predicate.is_some() {
671 let layer_set = self.store().tree().layer_set();
672 let mut merger = layer_set.merger();
673 let mut iter = merger.query(Query::FullRange(&key)).await?;
674 if let Some(predicate) = predicate {
675 if !self.advance_until(&mut iter, predicate).await? {
676 return Ok(None);
677 }
678 } else if iter
679 .get()
680 .is_none_or(|item| item.key != &key || matches!(item.value, ObjectValue::None))
681 {
682 return Ok(None);
683 }
684 let item = iter.get().unwrap();
685 match item.value {
686 ObjectValue::Child(ChildValue { object_id, object_descriptor }) => {
687 Ok(Some(LookupEntry {
688 object_id: *object_id,
689 descriptor: object_descriptor.clone(),
690 key: item.key.clone(),
691 locked,
692 }))
693 }
694 _ => Err(anyhow!(FxfsError::Inconsistent)
695 .context(format!("Unexpected item in lookup: {item:?}"))),
696 }
697 } else {
698 self.store()
699 .tree()
700 .find_map(&key, |item| match item.value {
701 ObjectValue::Child(ChildValue { object_id, object_descriptor }) => {
702 Ok(LookupEntry {
703 object_id: *object_id,
704 descriptor: *object_descriptor,
705 key: item.key.clone(),
706 locked: false,
707 })
708 }
709 _ => Err(anyhow!(FxfsError::Inconsistent)
710 .context(format!("Unexpected item in lookup: {item:?}",))),
711 })
712 .await?
713 .transpose()
714 }
715 }
716
717 pub async fn create_child_dir(
718 &self,
719 transaction: &mut Transaction<'_>,
720 name: &str,
721 ) -> Result<Directory<S>, Error> {
722 ensure!(!self.is_deleted(), FxfsError::Deleted);
723
724 let handle =
725 Directory::create_with_options(transaction, self.owner(), self.dir_type()).await?;
726 if self.dir_type().is_encrypted() {
727 let fscrypt_key =
728 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
729 let encrypted_name =
730 encrypt_filename(&*fscrypt_key, self.object_id(), name).expect("encrypt_filename");
731 let hash_code = if self.dir_type().is_casefold() {
732 Some(fscrypt_key.hash_code_casefold(name))
733 } else {
734 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
735 };
736 transaction.add(
737 self.store().store_object_id(),
738 Mutation::replace_or_insert_object(
739 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
740 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
741 ),
742 );
743 } else {
744 transaction.add(
745 self.store().store_object_id(),
746 Mutation::replace_or_insert_object(
747 ObjectKey::child(self.object_id(), &name, self.dir_type()),
748 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
749 ),
750 );
751 }
752 let now = Timestamp::now();
753 self.update_dir_attributes_internal(
754 transaction,
755 self.object_id(),
756 MutableAttributesInternal {
757 sub_dirs: 1,
758 modification_time: Some(now.as_nanos()),
759 change_time: Some(now),
760 ..Default::default()
761 },
762 )
763 .await?;
764 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
765 Ok(handle)
766 }
767
768 pub async fn add_child_file<'a>(
769 &self,
770 transaction: &mut Transaction<'a>,
771 name: &str,
772 handle: &DataObjectHandle<S>,
773 ) -> Result<(), Error> {
774 ensure!(!self.is_deleted(), FxfsError::Deleted);
775 if self.dir_type().is_encrypted() {
776 let fscrypt_key =
777 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
778 let encrypted_name =
779 encrypt_filename(&*fscrypt_key, self.object_id(), name).expect("encrypt_filename");
780 let hash_code = if self.dir_type().is_casefold() {
781 Some(fscrypt_key.hash_code_casefold(name))
782 } else {
783 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
784 };
785 transaction.add(
786 self.store().store_object_id(),
787 Mutation::replace_or_insert_object(
788 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
789 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
790 ),
791 );
792 } else {
793 transaction.add(
794 self.store().store_object_id(),
795 Mutation::replace_or_insert_object(
796 ObjectKey::child(self.object_id(), &name, self.dir_type()),
797 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
798 ),
799 );
800 }
801 let now = Timestamp::now();
802 self.update_dir_attributes_internal(
803 transaction,
804 self.object_id(),
805 MutableAttributesInternal {
806 modification_time: Some(now.as_nanos()),
807 change_time: Some(now),
808 ..Default::default()
809 },
810 )
811 .await
812 }
813
814 fn copy_project_id_to_object_in_txn<'a>(
819 &self,
820 transaction: &mut Transaction<'a>,
821 object_id: u64,
822 ) -> Result<(), Error> {
823 let store_id = self.store().store_object_id();
824 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
826 transaction
827 .get_object_mutation(store_id, ObjectKey::object(self.object_id()))
828 .unwrap()
829 .item
830 .value
831 else {
832 return Err(anyhow!(FxfsError::Inconsistent));
833 };
834 if let Some(project_id) = project_id {
835 let mut mutation = transaction
838 .get_object_mutation(store_id, ObjectKey::object(object_id))
839 .unwrap()
840 .clone();
841 if let ObjectValue::Object {
842 attributes: ObjectAttributes { project_id: child_project_id, .. },
843 ..
844 } = &mut mutation.item.value
845 {
846 *child_project_id = Some(project_id);
847 } else {
848 return Err(anyhow!(FxfsError::Inconsistent));
849 }
850 transaction.add(store_id, Mutation::ObjectStore(mutation));
851 transaction.merge_bytes_and_nodes(
852 store_id,
853 ObjectKey::project_usage(self.store().root_directory_object_id(), project_id),
854 BytesAndNodes { bytes: 0, nodes: 1 },
855 );
856 }
857 Ok(())
858 }
859
860 pub async fn create_child_file<'a>(
861 &self,
862 transaction: &mut Transaction<'a>,
863 name: &str,
864 ) -> Result<DataObjectHandle<S>, Error> {
865 self.create_child_file_with_options(transaction, name, HandleOptions::default()).await
866 }
867
868 pub async fn create_child_file_with_options<'a>(
869 &self,
870 transaction: &mut Transaction<'a>,
871 name: &str,
872 options: HandleOptions,
873 ) -> Result<DataObjectHandle<S>, Error> {
874 ensure!(!self.is_deleted(), FxfsError::Deleted);
875 let fscrypt_info = self.fscrypt_info();
876 let handle =
877 ObjectStore::create_object(self.owner(), transaction, options, fscrypt_info).await?;
878 self.add_child_file(transaction, name, &handle).await?;
879 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
880 Ok(handle)
881 }
882
883 pub async fn create_child_unnamed_temporary_file<'a>(
884 &self,
885 transaction: &mut Transaction<'a>,
886 ) -> Result<DataObjectHandle<S>, Error> {
887 ensure!(!self.is_deleted(), FxfsError::Deleted);
888 let fscrypt_info = self.fscrypt_info();
889 let handle = ObjectStore::create_object(
890 self.owner(),
891 transaction,
892 HandleOptions::default(),
893 fscrypt_info,
894 )
895 .await?;
896
897 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } = self
899 .store()
900 .txn_get_object_mutation(&transaction, self.object_id())
901 .await
902 .unwrap()
903 .item
904 .value
905 else {
906 bail!(
907 anyhow!(FxfsError::Inconsistent)
908 .context("Directory.create_child_file_with_options: expected mutation object")
909 );
910 };
911
912 let mut child_mutation = transaction
914 .get_object_mutation(
915 self.store().store_object_id(),
916 ObjectKey::object(handle.object_id()),
917 )
918 .unwrap()
919 .clone();
920 if let ObjectValue::Object {
921 attributes: ObjectAttributes { project_id: child_project_id, .. },
922 ..
923 } = &mut child_mutation.item.value
924 {
925 *child_project_id = project_id;
926 } else {
927 bail!(
928 anyhow!(FxfsError::Inconsistent)
929 .context("Directory.create_child_file_with_options: expected file object")
930 );
931 }
932 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(child_mutation));
933
934 self.store().add_to_graveyard(transaction, handle.object_id());
936
937 Ok(handle)
938 }
939
940 pub async fn create_symlink(
941 &self,
942 transaction: &mut Transaction<'_>,
943 link: &[u8],
944 name: &str,
945 ) -> Result<u64, Error> {
946 ensure!(!self.is_deleted(), FxfsError::Deleted);
947 ensure!(link.len() <= MAX_SYMLINK_LEN, FxfsError::BadPath);
948 let store = self.store();
949 let store_id = store.store_object_id();
950 let reserved_symlink_id = store.get_next_object_id(transaction).await?;
951 let symlink_id = reserved_symlink_id.get();
952 let mut link = link.to_vec();
953 let inline = link.len() <= MAX_INLINE_SYMLINK_SIZE;
954
955 let cipher_set: Option<Arc<CipherSet>> = match self.dir_type() {
956 DirType::Encrypted(info) | DirType::EncryptedCasefold(info) => {
957 if let Some(crypt) = store.crypt() {
958 let (key, unwrapped_key) = crypt
959 .create_key_with_id(
960 symlink_id,
961 info.wrapping_key_id,
962 ObjectType::Symlink,
963 info.flags.into(),
964 )
965 .await?;
966
967 let cipher = key_to_cipher(&key, &unwrapped_key)?;
968 let keys = vec![(FSCRYPT_KEY_ID, key)];
969 let ciphers = vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher.clone()))];
970
971 let dir_key =
972 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
973 let encrypted_name = encrypt_filename(&*dir_key, self.object_id(), name)?;
974 let hash_code = if self.dir_type().is_casefold() {
975 Some(dir_key.hash_code_casefold(name))
976 } else {
977 dir_key.hash_code(encrypted_name.as_bytes(), name)
978 };
979 cipher.encrypt_symlink(symlink_id, &mut link)?;
980
981 let object_value = if inline {
982 ObjectValue::encrypted_symlink(
983 std::mem::take(&mut link),
984 Timestamp::now(),
985 Timestamp::now(),
986 None,
987 )
988 } else {
989 ObjectValue::non_inline_symlink(Timestamp::now(), Timestamp::now(), None)
990 };
991 transaction.add(
992 store_id,
993 Mutation::insert_object(
994 ObjectKey::object(reserved_symlink_id.release().get()),
995 object_value,
996 ),
997 );
998 transaction.add(
999 store_id,
1000 Mutation::insert_object(
1001 ObjectKey::keys(symlink_id),
1002 ObjectValue::keys(keys.into()),
1003 ),
1004 );
1005 if !inline {
1006 let handle = StoreObjectHandle::new(
1012 self.owner().clone(),
1013 symlink_id,
1014 false,
1015 HandleOptions::default(),
1016 false,
1017 );
1018 handle
1019 .write_new_attr_pre_encrypted(
1020 transaction,
1021 AttributeId::DATA,
1022 FSCRYPT_KEY_ID,
1023 &link,
1024 )
1025 .await?;
1026 }
1027 transaction.add(
1028 store_id,
1029 Mutation::replace_or_insert_object(
1030 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
1031 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
1032 ),
1033 );
1034 Some(Arc::new(ciphers.into()))
1035 } else {
1036 return Err(anyhow!("No crypt"));
1037 }
1038 }
1039 _ => {
1040 let object_value = if inline {
1041 ObjectValue::symlink(
1042 std::mem::take(&mut link),
1043 Timestamp::now(),
1044 Timestamp::now(),
1045 None,
1046 )
1047 } else {
1048 ObjectValue::non_inline_symlink(Timestamp::now(), Timestamp::now(), None)
1049 };
1050 transaction.add(
1051 store_id,
1052 Mutation::insert_object(
1053 ObjectKey::object(reserved_symlink_id.release().get()),
1054 object_value,
1055 ),
1056 );
1057 let cipher_set = if !inline {
1058 let cipher_set = if let Some(crypt) = store.crypt() {
1059 let (fxfs_key, unwrapped_fxfs_key) =
1060 crypt.create_key(symlink_id, KeyPurpose::Data).await?;
1061 let fxfs_key = EncryptionKey::Fxfs(fxfs_key);
1062 let fxfs_cipher = key_to_cipher(&fxfs_key, &unwrapped_fxfs_key)?;
1063 transaction.add(
1064 store_id,
1065 Mutation::insert_object(
1066 ObjectKey::keys(symlink_id),
1067 ObjectValue::keys(vec![(VOLUME_DATA_KEY_ID, fxfs_key)].into()),
1068 ),
1069 );
1070 let cipher_set: Arc<CipherSet> = Arc::new(
1071 vec![(VOLUME_DATA_KEY_ID, CipherHolder::Cipher(fxfs_cipher))].into(),
1072 );
1073 store.key_manager.insert(symlink_id, cipher_set.clone(), false);
1074 Some(cipher_set)
1075 } else {
1076 None
1077 };
1078 let handle = StoreObjectHandle::new(
1079 self.owner().clone(),
1080 symlink_id,
1081 false,
1082 HandleOptions::default(),
1083 false,
1084 );
1085 handle.write_new_attr(transaction, AttributeId::DATA, &link).await?;
1086 cipher_set
1087 } else {
1088 None
1089 };
1090 transaction.add(
1091 store_id,
1092 Mutation::replace_or_insert_object(
1093 ObjectKey::child(self.object_id(), &name, self.dir_type()),
1094 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
1095 ),
1096 );
1097 cipher_set
1098 }
1099 };
1100
1101 if let Some(cipher_set) = cipher_set {
1102 store.key_manager.insert(symlink_id, cipher_set, false);
1107 }
1108
1109 let now = Timestamp::now();
1110 self.update_dir_attributes_internal(
1111 transaction,
1112 self.object_id(),
1113 MutableAttributesInternal {
1114 modification_time: Some(now.as_nanos()),
1115 change_time: Some(now),
1116 ..Default::default()
1117 },
1118 )
1119 .await?;
1120 Ok(symlink_id)
1121 }
1122
1123 pub async fn add_child_volume(
1124 &self,
1125 transaction: &mut Transaction<'_>,
1126 volume_name: &str,
1127 store_object_id: u64,
1128 ) -> Result<(), Error> {
1129 ensure!(!self.is_deleted(), FxfsError::Deleted);
1130 transaction.add(
1131 self.store().store_object_id(),
1132 Mutation::replace_or_insert_object(
1133 ObjectKey::child(self.object_id(), volume_name, self.dir_type()),
1134 ObjectValue::child(store_object_id, ObjectDescriptor::Volume),
1135 ),
1136 );
1137 let now = Timestamp::now();
1138 self.update_dir_attributes_internal(
1139 transaction,
1140 self.object_id(),
1141 MutableAttributesInternal {
1142 modification_time: Some(now.as_nanos()),
1143 change_time: Some(now),
1144 ..Default::default()
1145 },
1146 )
1147 .await
1148 }
1149
1150 pub fn delete_child_volume<'a>(
1151 &self,
1152 transaction: &mut Transaction<'a>,
1153 volume_name: &str,
1154 store_object_id: u64,
1155 ) -> Result<(), Error> {
1156 ensure!(!self.is_deleted(), FxfsError::Deleted);
1157 transaction.add(
1158 self.store().store_object_id(),
1159 Mutation::replace_or_insert_object(
1160 ObjectKey::child(self.object_id(), volume_name, self.dir_type()),
1161 ObjectValue::None,
1162 ),
1163 );
1164 transaction.add(store_object_id, Mutation::DeleteVolume);
1169 Ok(())
1170 }
1171
1172 pub async fn insert_child<'a>(
1176 &self,
1177 transaction: &mut Transaction<'a>,
1178 name: &str,
1179 object_id: u64,
1180 descriptor: ObjectDescriptor,
1181 ) -> Result<(), Error> {
1182 ensure!(!self.is_deleted(), FxfsError::Deleted);
1183 let sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1184 if self.dir_type().is_encrypted() {
1185 let fscrypt_key =
1186 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
1187 let encrypted_name = encrypt_filename(&*fscrypt_key, self.object_id(), name)?;
1188 let hash_code = if self.dir_type().is_casefold() {
1189 Some(fscrypt_key.hash_code_casefold(name))
1190 } else {
1191 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
1192 };
1193 transaction.add(
1194 self.store().store_object_id(),
1195 Mutation::replace_or_insert_object(
1196 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
1197 ObjectValue::child(object_id, descriptor),
1198 ),
1199 );
1200 } else {
1201 transaction.add(
1202 self.store().store_object_id(),
1203 Mutation::replace_or_insert_object(
1204 ObjectKey::child(self.object_id(), &name, self.dir_type()),
1205 ObjectValue::child(object_id, descriptor),
1206 ),
1207 );
1208 }
1209 let now = Timestamp::now();
1210 self.update_dir_attributes_internal(
1211 transaction,
1212 self.object_id(),
1213 MutableAttributesInternal {
1214 sub_dirs: sub_dirs_delta,
1215 modification_time: Some(now.as_nanos()),
1216 change_time: Some(now),
1217 ..Default::default()
1218 },
1219 )
1220 .await
1221 }
1222
1223 pub async fn update_attributes<'a>(
1226 &self,
1227 mut transaction: Transaction<'a>,
1228 node_attributes: Option<&fio::MutableNodeAttributes>,
1229 sub_dirs_delta: i64,
1230 change_time: Option<Timestamp>,
1231 ) -> Result<(), Error> {
1232 ensure!(!self.is_deleted(), FxfsError::Deleted);
1233
1234 if sub_dirs_delta != 0 {
1235 let mut mutation =
1236 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
1237 if let ObjectValue::Object { kind: ObjectKind::Directory { sub_dirs, .. }, .. } =
1238 &mut mutation.item.value
1239 {
1240 *sub_dirs = sub_dirs.saturating_add_signed(sub_dirs_delta);
1241 } else {
1242 bail!(
1243 anyhow!(FxfsError::Inconsistent)
1244 .context("Directory.update_attributes: expected directory object")
1245 );
1246 };
1247
1248 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1249 }
1250
1251 let wrapping_key =
1252 if let Some(fio::MutableNodeAttributes { encryption_policy: Some(policy), .. }) =
1253 node_attributes
1254 {
1255 let info = FscryptDirInfo::from(*policy);
1256 Some((info, self.set_wrapping_key(&mut transaction, info).await?))
1257 } else {
1258 None
1259 };
1260
1261 if node_attributes.is_some() || change_time.is_some() {
1263 self.handle.update_attributes(&mut transaction, node_attributes, change_time).await?;
1264 }
1265 transaction
1266 .commit_with_callback(|_| {
1267 if let Some((info, cipher)) = wrapping_key {
1268 {
1269 let mut dir_type = self.dir_type.lock();
1270 *dir_type = dir_type.with_encryption(info);
1271 }
1272 self.store().key_manager.merge(self.object_id(), |existing| match existing {
1273 Some(existing) => {
1274 let mut cipher_set = (**existing).clone();
1275 cipher_set.add_key(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher));
1276 Arc::new(cipher_set)
1277 }
1278 None => {
1279 Arc::new(vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher))].into())
1280 }
1281 });
1282 }
1283 })
1284 .await?;
1285 Ok(())
1286 }
1287
1288 pub async fn update_dir_attributes_internal<'a>(
1292 &self,
1293 transaction: &mut Transaction<'a>,
1294 object_id: u64,
1295 mutable_node_attributes: MutableAttributesInternal,
1296 ) -> Result<(), Error> {
1297 ensure!(!self.is_deleted(), FxfsError::Deleted);
1298
1299 let mut mutation = self.store().txn_get_object_mutation(transaction, object_id).await?;
1300 if let ObjectValue::Object {
1301 kind: ObjectKind::Directory { sub_dirs, .. },
1302 attributes,
1303 ..
1304 } = &mut mutation.item.value
1305 {
1306 if let Some(time) = mutable_node_attributes.modification_time {
1307 attributes.modification_time = Timestamp::from_nanos(time);
1308 }
1309 if let Some(time) = mutable_node_attributes.change_time {
1310 attributes.change_time = time;
1311 }
1312 if mutable_node_attributes.sub_dirs != 0 {
1313 *sub_dirs = sub_dirs.saturating_add_signed(mutable_node_attributes.sub_dirs);
1314 }
1315 if let Some(time) = mutable_node_attributes.creation_time {
1316 attributes.creation_time = Timestamp::from_nanos(time);
1317 }
1318 } else {
1319 bail!(
1320 anyhow!(FxfsError::Inconsistent)
1321 .context("Directory.update_attributes: expected directory object")
1322 );
1323 };
1324 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1325 Ok(())
1326 }
1327
1328 pub async fn get_properties(&self) -> Result<ObjectProperties, Error> {
1329 if self.is_deleted() {
1330 return Ok(ObjectProperties {
1331 refs: 0,
1332 allocated_size: 0,
1333 data_attribute_size: 0,
1334 creation_time: Timestamp::zero(),
1335 modification_time: Timestamp::zero(),
1336 access_time: Timestamp::zero(),
1337 change_time: Timestamp::zero(),
1338 sub_dirs: 0,
1339 posix_attributes: None,
1340 dir_type: DirType::Normal,
1341 });
1342 }
1343
1344 let value = self
1345 .store()
1346 .tree()
1347 .find_value(&ObjectKey::object(self.object_id()))
1348 .await?
1349 .ok_or(FxfsError::NotFound)?;
1350 match value {
1351 ObjectValue::Object {
1352 kind: ObjectKind::Directory { sub_dirs, dir_type },
1353 attributes:
1354 ObjectAttributes {
1355 creation_time,
1356 modification_time,
1357 posix_attributes,
1358 access_time,
1359 change_time,
1360 ..
1361 },
1362 } => Ok(ObjectProperties {
1363 refs: 1,
1364 allocated_size: 0,
1365 data_attribute_size: 0,
1366 creation_time,
1367 modification_time,
1368 access_time,
1369 change_time,
1370 sub_dirs,
1371 posix_attributes,
1372 dir_type,
1373 }),
1374 _ => {
1375 bail!(
1376 anyhow!(FxfsError::Inconsistent)
1377 .context("get_properties: Expected object value")
1378 )
1379 }
1380 }
1381 }
1382
1383 pub async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, Error> {
1384 ensure!(!self.is_deleted(), FxfsError::Deleted);
1385 self.handle.list_extended_attributes().await
1386 }
1387
1388 pub async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, Error> {
1389 ensure!(!self.is_deleted(), FxfsError::Deleted);
1390 self.handle.get_extended_attribute(name).await
1391 }
1392
1393 pub async fn set_extended_attribute(
1394 &self,
1395 name: Vec<u8>,
1396 value: Vec<u8>,
1397 mode: SetExtendedAttributeMode,
1398 ) -> Result<(), Error> {
1399 ensure!(!self.is_deleted(), FxfsError::Deleted);
1400 self.handle.set_extended_attribute(name, value, mode).await
1401 }
1402
1403 pub async fn remove_extended_attribute(&self, name: Vec<u8>) -> Result<(), Error> {
1404 ensure!(!self.is_deleted(), FxfsError::Deleted);
1405 self.handle.remove_extended_attribute(name).await
1406 }
1407
1408 pub async fn iter<'a, 'b>(
1416 &self,
1417 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1418 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1419 self.iter_from_key(
1424 merger,
1425 &if self.dir_type().is_encrypted() {
1426 ObjectKey::encrypted_child(self.object_id(), Vec::new(), Some(0))
1430 } else {
1431 ObjectKey::child(self.object_id(), "", self.dir_type())
1432 },
1433 )
1434 .await
1435 }
1436
1437 pub async fn iter_from_key<'a, 'b>(
1439 &self,
1440 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1441 key: &ObjectKey,
1442 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1443 ensure!(!self.is_deleted(), FxfsError::Deleted);
1444
1445 DirectoryIterator::new(
1446 self.object_id(),
1447 merger.query(Query::FullRange(key)).await?,
1448 if self.dir_type().is_encrypted() {
1449 self.get_fscrypt_key().await?.into_cipher()
1450 } else {
1451 None
1452 },
1453 )
1454 .await
1455 }
1456
1457 pub async fn iter_from<'a, 'b>(
1468 &self,
1469 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1470 from: &str,
1471 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1472 debug_assert!(!self.dir_type().is_encrypted());
1473
1474 self.iter_from_key(merger, &ObjectKey::child(self.object_id(), from, self.dir_type())).await
1475 }
1476
1477 pub async fn iter_from_bytes<'a, 'b>(
1481 &self,
1482 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1483 from: &[u8],
1484 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1485 debug_assert!(self.dir_type().is_encrypted());
1486
1487 self.iter_from_key(merger, &bincode::deserialize(&from).unwrap()).await
1488 }
1489
1490 async fn advance_until(
1493 &self,
1494 iter: &mut MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1495 predicate: impl Fn(&ObjectKey) -> ControlFlow<bool>,
1496 ) -> Result<bool, Error> {
1497 while let Some(item) = iter.get()
1498 && matches!(
1499 item,
1500 ItemRef { key: ObjectKey { object_id, .. }, .. }
1501 if *object_id == self.object_id()
1502 )
1503 {
1504 match item {
1505 ItemRef { value: ObjectValue::None, .. } => {}
1507 ItemRef { key, .. } => match predicate(key) {
1508 ControlFlow::Continue(()) => {}
1509 ControlFlow::Break(result) => return Ok(result),
1510 },
1511 }
1512 iter.advance().await?
1513 }
1514 Ok(false)
1515 }
1516
1517 fn get_key_and_predicate_for_unavailable_cipher<'a>(
1520 &self,
1521 proxy_name: &'a ProxyFilename,
1522 ) -> (ObjectKey, Option<BoxPredicate<'a>>) {
1523 if self.dir_type().is_casefold() {
1524 (
1525 ObjectKey::encrypted_child(
1526 self.object_id(),
1527 proxy_name.raw_filename().to_vec(),
1528 Some(proxy_name.hash_code as u32),
1529 ),
1530 proxy_name
1531 .is_truncated()
1532 .then(|| Box::new(long_proxy_prefix_casefold_predicate(&proxy_name)) as Box<_>),
1533 )
1534 } else {
1535 (
1536 ObjectKey::encrypted_child(
1537 self.object_id(),
1538 proxy_name.raw_filename().to_vec(),
1539 None,
1540 ),
1541 proxy_name
1542 .is_truncated()
1543 .then(|| Box::new(long_proxy_prefix_predicate(&proxy_name)) as Box<_>),
1544 )
1545 }
1546 }
1547}
1548
1549fn encrypted_casefold_predicate<'a>(
1551 cipher: &'a dyn Cipher,
1552 object_id: u64,
1553 target_hash_code: u32,
1554 name: &'a str,
1555) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + 'a {
1556 move |key| match key {
1557 ObjectKey {
1558 data:
1559 ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
1560 hash_code,
1561 name: encrypted_name,
1562 }),
1563 ..
1564 } if *hash_code == target_hash_code => {
1565 let decrypted_name = decrypt_filename(cipher, object_id, encrypted_name);
1566 match decrypted_name {
1567 Ok(decrypted_name) => {
1568 if fxfs_unicode::casefold_cmp(name, &decrypted_name)
1569 == std::cmp::Ordering::Equal
1570 {
1571 ControlFlow::Break(true)
1572 } else {
1573 ControlFlow::Continue(())
1574 }
1575 }
1576 Err(_) => ControlFlow::Continue(()),
1577 }
1578 }
1579 _ => ControlFlow::Break(false),
1580 }
1581}
1582
1583fn casefold_predicate(
1584 object_id: u64,
1585 target_hash_code: u32,
1586 name: &str,
1587) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1588 move |key| match key {
1589 ObjectKey {
1590 object_id: oid,
1591 data: ObjectKeyData::CasefoldChild { hash_code, name: actual_name },
1592 } if *oid == object_id && *hash_code == target_hash_code => {
1593 if fxfs_unicode::casefold_cmp(name, actual_name) == std::cmp::Ordering::Equal {
1594 ControlFlow::Break(true)
1595 } else {
1596 ControlFlow::Continue(())
1597 }
1598 }
1599 _ => ControlFlow::Break(false),
1600 }
1601}
1602
1603fn long_proxy_prefix_casefold_predicate(
1605 proxy_name: &ProxyFilename,
1606) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1607 move |key| match key {
1608 ObjectKey {
1609 data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild { hash_code, name }),
1610 ..
1611 } if *hash_code as u64 == proxy_name.hash_code
1612 && name.starts_with(&proxy_name.filename) =>
1613 {
1614 if ProxyFilename::compute_sha256(&name) == proxy_name.sha256 {
1615 ControlFlow::Break(true)
1616 } else {
1617 ControlFlow::Continue(())
1618 }
1619 }
1620 _ => ControlFlow::Break(false),
1621 }
1622}
1623
1624fn long_proxy_prefix_predicate(
1626 proxy_name: &ProxyFilename,
1627) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1628 move |key| match key {
1629 ObjectKey { data: ObjectKeyData::EncryptedChild(EncryptedChild(name)), .. }
1630 if name.starts_with(&proxy_name.filename) =>
1631 {
1632 if ProxyFilename::compute_hash_code(name) == proxy_name.hash_code
1633 && ProxyFilename::compute_sha256(name) == proxy_name.sha256
1634 {
1635 ControlFlow::Break(true)
1636 } else {
1637 ControlFlow::Continue(())
1638 }
1639 }
1640 _ => ControlFlow::Break(false),
1641 }
1642}
1643
1644impl<S: HandleOwner> fmt::Debug for Directory<S> {
1645 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1646 f.debug_struct("Directory")
1647 .field("store_id", &self.store().store_object_id())
1648 .field("object_id", &self.object_id())
1649 .finish()
1650 }
1651}
1652
1653pub struct DirectoryIterator<'a, 'b> {
1654 object_id: u64,
1655 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1656 cipher: Option<Arc<dyn Cipher>>,
1657 filename: Option<String>,
1659}
1660
1661impl<'a, 'b> DirectoryIterator<'a, 'b> {
1662 pub async fn new(
1663 object_id: u64,
1664 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1665 cipher: Option<Arc<dyn Cipher>>,
1666 ) -> Result<Self, Error> {
1667 let mut this = DirectoryIterator { object_id, iter, cipher, filename: None };
1668 this.init_item().await?;
1669 Ok(this)
1670 }
1671
1672 pub fn get(&self) -> Option<(&str, u64, &ObjectDescriptor)> {
1673 match self.iter.get() {
1674 Some(ItemRef {
1675 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1676 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1677 ..
1678 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1679 Some(ItemRef {
1680 key:
1681 ObjectKey {
1682 object_id: oid,
1683 data: ObjectKeyData::CasefoldChild { hash_code: _, name },
1684 },
1685 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1686 ..
1687 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1688 Some(ItemRef {
1689 key: ObjectKey { object_id: oid, data: ObjectKeyData::LegacyCasefoldChild(name) },
1690 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1691 ..
1692 }) if *oid == self.object_id => Some((name.as_str(), *object_id, object_descriptor)),
1693 Some(ItemRef {
1694 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedChild(_) },
1695 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1696 ..
1697 }) if *oid == self.object_id => {
1698 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1699 }
1700 Some(ItemRef {
1701 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedCasefoldChild(_) },
1702 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1703 ..
1704 }) if *oid == self.object_id => {
1705 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1706 }
1707 _ => None,
1708 }
1709 }
1710
1711 pub async fn advance(&mut self) -> Result<(), Error> {
1712 self.iter.advance().await?;
1713 self.init_item().await
1714 }
1715
1716 pub fn traversal_position<R>(
1718 &self,
1719 name_visitor: impl FnOnce(&str) -> R,
1720 bytes_visitor: impl FnOnce(Box<[u8]>) -> R,
1721 ) -> Option<R> {
1722 match self.iter.get() {
1723 Some(ItemRef {
1724 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1725 ..
1726 }) if *oid == self.object_id => Some(name_visitor(name)),
1727 Some(ItemRef {
1728 key:
1729 ObjectKey {
1730 object_id: oid,
1731 data: ObjectKeyData::CasefoldChild { hash_code: _, name },
1732 },
1733 ..
1734 }) if *oid == self.object_id => Some(name_visitor(&name)),
1735 Some(ItemRef {
1736 key: ObjectKey { object_id: oid, data: ObjectKeyData::LegacyCasefoldChild(name) },
1737 ..
1738 }) if *oid == self.object_id => Some(name_visitor(name.as_str())),
1739
1740 Some(ItemRef {
1741 key:
1742 key @ ObjectKey {
1743 object_id: oid,
1744 data:
1745 ObjectKeyData::EncryptedChild(_) | ObjectKeyData::EncryptedCasefoldChild(_),
1746 },
1747 ..
1748 }) if *oid == self.object_id => {
1749 Some(bytes_visitor(bincode::serialize(key).unwrap().into()))
1750 }
1751 _ => None,
1752 }
1753 }
1754
1755 async fn init_item(&mut self) -> Result<(), Error> {
1757 loop {
1758 match self.iter.get() {
1759 Some(ItemRef {
1760 key: ObjectKey { object_id, .. },
1761 value: ObjectValue::None,
1762 ..
1763 }) if *object_id == self.object_id => {}
1764 Some(ItemRef {
1765 key:
1766 ObjectKey {
1767 object_id,
1768 data:
1769 ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
1770 hash_code,
1771 name,
1772 }),
1773 },
1774 value: ObjectValue::Child(_),
1775 ..
1776 }) if *object_id == self.object_id => {
1777 self.update_encrypted_filename(Some(*hash_code), name.clone())?;
1780 return Ok(());
1781 }
1782 Some(ItemRef {
1783 key:
1784 ObjectKey {
1785 object_id,
1786 data: ObjectKeyData::EncryptedChild(EncryptedChild(name)),
1787 },
1788 value: ObjectValue::Child(_),
1789 ..
1790 }) if *object_id == self.object_id => {
1791 self.update_encrypted_filename(None, name.clone())?;
1794 return Ok(());
1795 }
1796 _ => return Ok(()),
1797 }
1798 self.iter.advance().await?;
1799 }
1800 }
1801
1802 fn update_encrypted_filename(
1805 &mut self,
1806 hash_code: Option<u32>,
1807 mut name: Vec<u8>,
1808 ) -> Result<(), Error> {
1809 if let Some(cipher) = &self.cipher {
1810 cipher.decrypt_filename(self.object_id, &mut name)?;
1811 self.filename = Some(String::from_utf8(name).map_err(|_| {
1812 anyhow!(FxfsError::Internal).context("Bad UTF-8 encrypted filename")
1813 })?);
1814 } else if let Some(hash_code) = hash_code {
1815 self.filename = Some(ProxyFilename::new_with_hash_code(hash_code as u64, &name).into());
1816 } else {
1817 self.filename = Some(ProxyFilename::new(&name).into());
1818 }
1819 Ok(())
1820 }
1821}
1822
1823#[derive(Debug)]
1826pub enum ReplacedChild {
1827 None,
1828
1829 Object(u64),
1831 ObjectWithRemainingLinks(u64),
1832 Directory(u64),
1833
1834 Purged(u64),
1836}
1837
1838pub async fn replace_child<'a, S: HandleOwner>(
1846 transaction: &mut Transaction<'a>,
1847 src: Option<(&'a Directory<S>, &str)>,
1848 dst: (&'a Directory<S>, &str),
1849) -> Result<ReplacedChild, Error> {
1850 replace_child_with_purge(transaction, src, dst, false).await
1851}
1852
1853pub async fn replace_child_with_purge<'a, S: HandleOwner>(
1857 transaction: &mut Transaction<'a>,
1858 src: Option<(&'a Directory<S>, &str)>,
1859 dst: (&'a Directory<S>, &str),
1860 can_purge: bool,
1861) -> Result<ReplacedChild, Error> {
1862 let mut sub_dirs_delta: i64 = 0;
1863 let now = Timestamp::now();
1864
1865 let is_same_dir_casefold_rename = if let Some((src_dir, src_name)) = src {
1866 src_dir.object_id() == dst.0.object_id()
1867 && src_dir.dir_type().is_casefold()
1868 && fxfs_unicode::casefold_cmp(src_name, dst.1) == std::cmp::Ordering::Equal
1869 } else {
1870 false
1871 };
1872
1873 let src = if let Some((src_dir, src_name)) = src {
1874 let store_id = dst.0.store().store_object_id();
1875 assert_eq!(store_id, src_dir.store().store_object_id());
1876
1877 let src_entry = src_dir.lookup_ext(src_name).await?.ok_or(FxfsError::NotFound)?;
1878 let LookupEntry { object_id: id, descriptor, key: src_key, .. } = src_entry;
1879
1880 match (src_dir.dir_type(), dst.0.dir_type()) {
1881 (
1882 DirType::Encrypted(src_id) | DirType::EncryptedCasefold(src_id),
1883 DirType::Encrypted(dst_id) | DirType::EncryptedCasefold(dst_id),
1884 ) => {
1885 ensure!(src_id == dst_id, FxfsError::InconsistentEncryptionPolicy);
1886
1887 let _ = src_dir.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
1890 }
1891 (
1892 DirType::Normal | DirType::Casefold | DirType::LegacyCasefold,
1893 DirType::Normal | DirType::Casefold | DirType::LegacyCasefold,
1894 ) => {}
1895 _ => bail!(FxfsError::InconsistentEncryptionPolicy),
1896 }
1897
1898 transaction.add(store_id, Mutation::replace_or_insert_object(src_key, ObjectValue::None));
1899
1900 src_dir.store().update_attributes(transaction, id, None, Some(now)).await?;
1901 if src_dir.object_id() != dst.0.object_id() {
1902 sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1903 src_dir
1904 .update_dir_attributes_internal(
1905 transaction,
1906 src_dir.object_id(),
1907 MutableAttributesInternal {
1908 sub_dirs: -sub_dirs_delta,
1909 modification_time: Some(now.as_nanos()),
1910 change_time: Some(now),
1911 ..Default::default()
1912 },
1913 )
1914 .await?;
1915 }
1916 Some((id, descriptor))
1917 } else {
1918 None
1919 };
1920 replace_child_with_object_impl(
1921 transaction,
1922 src,
1923 dst,
1924 sub_dirs_delta,
1925 is_same_dir_casefold_rename,
1926 now,
1927 can_purge,
1928 )
1929 .await
1930}
1931
1932pub async fn replace_child_with_object<'a, S: HandleOwner>(
1942 transaction: &mut Transaction<'a>,
1943 src: Option<(u64, ObjectDescriptor)>,
1944 dst: (&'a Directory<S>, &str),
1945 sub_dirs_delta: i64,
1946 is_same_dir_casefold_rename: bool,
1947 timestamp: Timestamp,
1948) -> Result<ReplacedChild, Error> {
1949 replace_child_with_object_impl(
1950 transaction,
1951 src,
1952 dst,
1953 sub_dirs_delta,
1954 is_same_dir_casefold_rename,
1955 timestamp,
1956 false,
1957 )
1958 .await
1959}
1960
1961async fn replace_child_with_object_impl<'a, S: HandleOwner>(
1962 transaction: &mut Transaction<'a>,
1963 src: Option<(u64, ObjectDescriptor)>,
1964 dst: (&'a Directory<S>, &str),
1965 mut sub_dirs_delta: i64,
1966 is_same_dir_casefold_rename: bool,
1967 timestamp: Timestamp,
1968 can_purge: bool,
1969) -> Result<ReplacedChild, Error> {
1970 let deleted_info =
1971 if is_same_dir_casefold_rename { None } else { dst.0.lookup_ext(dst.1).await? };
1972
1973 let (deleted_id_and_descriptor, dst_key) = match deleted_info {
1974 Some(entry) => (Some((entry.object_id, entry.descriptor.clone())), Some(entry.key)),
1975 None => (None, None),
1976 };
1977 let store_id = dst.0.store().store_object_id();
1978
1979 let result = match deleted_id_and_descriptor {
1980 Some((old_id, ObjectDescriptor::File | ObjectDescriptor::Symlink)) => {
1981 let was_last_ref =
1982 dst.0.store().adjust_refs_impl(transaction, old_id, -1, !can_purge).await?;
1983 if was_last_ref {
1984 if can_purge {
1985 let trim_result = dst
1986 .0
1987 .store()
1988 .trim_some(
1989 transaction,
1990 old_id,
1991 AttributeId::SORTED_START,
1992 TrimMode::Tombstone(TombstoneMode::Object),
1993 )
1994 .await?;
1995 if matches!(trim_result, TrimResult::Done(None)) {
1996 ReplacedChild::Purged(old_id)
1997 } else {
1998 dst.0.store().add_to_graveyard(transaction, old_id);
2000 ReplacedChild::Object(old_id)
2001 }
2002 } else {
2003 dst.0
2004 .store()
2005 .update_attributes(transaction, old_id, None, Some(timestamp))
2006 .await?;
2007 ReplacedChild::Object(old_id)
2008 }
2009 } else {
2010 dst.0.store().update_attributes(transaction, old_id, None, Some(timestamp)).await?;
2011 ReplacedChild::ObjectWithRemainingLinks(old_id)
2012 }
2013 }
2014 Some((old_id, ObjectDescriptor::Directory)) => {
2015 let dir = Directory::open(&dst.0.owner(), old_id).await?;
2016 if dir.has_children().await? {
2017 bail!(FxfsError::NotEmpty);
2018 }
2019
2020 dst.0.store().add_to_graveyard(transaction, old_id);
2023 sub_dirs_delta -= 1;
2024 ReplacedChild::Directory(old_id)
2025 }
2026 Some((_, ObjectDescriptor::Volume)) => {
2027 bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected volume child"))
2028 }
2029 None => {
2030 if src.is_none() {
2031 bail!(FxfsError::NotFound);
2033 }
2034 ReplacedChild::None
2035 }
2036 };
2037 let new_value = match src {
2038 Some((id, descriptor)) => ObjectValue::child(id, descriptor),
2039 None => ObjectValue::None,
2040 };
2041 let new_key = if matches!(new_value, ObjectValue::None) {
2042 None
2043 } else {
2044 if dst.0.dir_type().is_encrypted() {
2045 match dst.0.get_fscrypt_key().await? {
2046 CipherHolder::Cipher(cipher) => {
2047 let encrypted_dst_name = encrypt_filename(&*cipher, dst.0.object_id(), dst.1)?;
2048 let dst_hash_code = if dst.0.dir_type().is_casefold() {
2049 Some(cipher.hash_code_casefold(dst.1))
2050 } else {
2051 cipher.hash_code(encrypted_dst_name.as_bytes(), dst.1)
2052 };
2053 Some(ObjectKey::encrypted_child(
2054 dst.0.object_id(),
2055 encrypted_dst_name,
2056 dst_hash_code,
2057 ))
2058 }
2059 CipherHolder::Unavailable => {
2060 bail!(FxfsError::NoKey);
2061 }
2062 }
2063 } else {
2064 Some(ObjectKey::child(dst.0.object_id(), dst.1, dst.0.dir_type()))
2065 }
2066 };
2067
2068 if let Some(dst_key) = dst_key
2069 && new_key.as_ref() != Some(&dst_key)
2070 {
2071 transaction.add(store_id, Mutation::replace_or_insert_object(dst_key, ObjectValue::None));
2072 }
2073
2074 if let Some(new_key) = new_key {
2075 transaction.add(store_id, Mutation::replace_or_insert_object(new_key, new_value));
2076 }
2077 dst.0
2078 .update_dir_attributes_internal(
2079 transaction,
2080 dst.0.object_id(),
2081 MutableAttributesInternal {
2082 sub_dirs: sub_dirs_delta,
2083 modification_time: Some(timestamp.as_nanos()),
2084 change_time: Some(timestamp),
2085 ..Default::default()
2086 },
2087 )
2088 .await?;
2089 Ok(result)
2090}
2091
2092#[cfg(test)]
2093mod tests {
2094 use super::{
2095 MAX_INLINE_SYMLINK_SIZE, MAX_SYMLINK_LEN, ProxyFilename, encrypt_filename,
2096 replace_child_with_object,
2097 };
2098 use crate::errors::FxfsError;
2099 use crate::filesystem::{FxFilesystem, SyncOptions};
2100 use crate::fsck::{fsck, fsck_volume};
2101 use crate::lsm_tree::Query;
2102 use crate::object_handle::{ObjectHandle, WriteObjectHandle};
2103 use crate::object_store::directory::{
2104 Directory, MutableAttributesInternal, ReplacedChild, replace_child,
2105 replace_child_with_purge,
2106 };
2107 use crate::object_store::object_record::{AttributeKey, ObjectKey, ObjectValue, Timestamp};
2108 use crate::object_store::transaction::{Options, lock_keys};
2109 use crate::object_store::volume::root_volume;
2110 use crate::object_store::{
2111 AttributeId, HandleOptions, LockKey, NewChildStoreOptions, ObjectDescriptor, ObjectKind,
2112 ObjectStore, SetExtendedAttributeMode, StoreObjectHandle, StoreOptions,
2113 };
2114 use anyhow::Error;
2115 use assert_matches::assert_matches;
2116 use fidl_fuchsia_io as fio;
2117 use fxfs_crypt_common::CryptBase;
2118 use fxfs_crypto::{Cipher, Crypt, WrappingKeyId};
2119 use fxfs_insecure_crypto::new_insecure_crypt;
2120 use std::collections::HashSet;
2121 use std::future::poll_fn;
2122 use std::sync::Arc;
2123 use std::task::Poll;
2124 use storage_device::DeviceHolder;
2125 use storage_device::fake_device::FakeDevice;
2126 use test_case::test_case;
2127
2128 #[fuchsia::test]
2129 fn test_casefold_equality_implies_hash_equality() {
2130 use fxfs_unicode::CasefoldString;
2131
2132 let test_cases = vec![
2133 ("Hello", "hello"),
2134 ("straße", "STRASSE"),
2135 ("e\u{0301}", "\u{00c9}"), ("hello\u{00ad}", "hello"), ("foo\u{200b}bar", "FOOBAR"), ];
2139
2140 for (a, b) in test_cases {
2141 let cf_a = CasefoldString::new(a.to_string());
2142 let cf_b = CasefoldString::new(b.to_string());
2143 assert_eq!(cf_a, cf_b, "Strings {:?} and {:?} should be equal under casefolding", a, b);
2144
2145 let bytes_a: Vec<u8> =
2146 cf_a.casefold_normalized_chars().collect::<String>().into_bytes();
2147 let bytes_b: Vec<u8> =
2148 cf_b.casefold_normalized_chars().collect::<String>().into_bytes();
2149 assert_eq!(
2150 bytes_a, bytes_b,
2151 "Normalized bytes for {:?} and {:?} should be identical",
2152 a, b
2153 );
2154
2155 let hash_a = fscrypt::direntry::tea_hash_filename(bytes_a);
2156 let hash_b = fscrypt::direntry::tea_hash_filename(bytes_b);
2157 assert_eq!(hash_a, hash_b, "Hashes for {:?} and {:?} should be identical", a, b);
2158 }
2159 }
2160
2161 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
2162 const WRAPPING_KEY_ID: WrappingKeyId = u128::to_le_bytes(2);
2163
2164 #[fuchsia::test]
2168 async fn test_reopen_with_different_crypt_shows_proxy_name() -> Result<(), Error> {
2169 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2170 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2171 let symlink_object_id;
2172 {
2173 let crypt = Arc::new(new_insecure_crypt());
2174 crypt
2175 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
2176 .expect("add_wrapping_key failed");
2177 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2178 let store = root_volume
2179 .new_volume(
2180 "test",
2181 NewChildStoreOptions {
2182 options: StoreOptions {
2183 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2184 ..StoreOptions::default()
2185 },
2186 ..Default::default()
2187 },
2188 )
2189 .await
2190 .expect("new_volume failed");
2191 let mut transaction = fs
2192 .root_store()
2193 .new_transaction(
2194 lock_keys![LockKey::object(
2195 store.store_object_id(),
2196 store.root_directory_object_id()
2197 )],
2198 Options::default(),
2199 )
2200 .await
2201 .expect("new_transaction failed");
2202 let root_dir = Directory::open(&store, store.root_directory_object_id())
2203 .await
2204 .expect("open failed");
2205 let _ = root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await?;
2206 transaction.commit().await.unwrap();
2207
2208 let mut transaction = fs
2209 .root_store()
2210 .new_transaction(
2211 lock_keys![LockKey::object(
2212 store.store_object_id(),
2213 store.root_directory_object_id()
2214 )],
2215 Options::default(),
2216 )
2217 .await
2218 .expect("new_transaction failed");
2219 let root_dir = Directory::open(&store, store.root_directory_object_id())
2220 .await
2221 .expect("open failed");
2222 symlink_object_id = root_dir
2223 .create_symlink(&mut transaction, b"some_link_text", "a")
2224 .await
2225 .expect("create_symlink failed");
2226 transaction.commit().await.expect("commit failed");
2227 };
2228 fs.close().await.expect("close failed");
2229 let device = fs.take_device().await;
2230 device.reopen(false);
2231
2232 let fs = FxFilesystem::open(device).await.expect("open failed");
2233 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2234 let store = root_volume
2236 .volume(
2237 "test",
2238 StoreOptions {
2239 crypt: Some(Arc::new(new_insecure_crypt())),
2240 ..StoreOptions::default()
2241 },
2242 )
2243 .await
2244 .expect("volume failed");
2245
2246 let value = store
2247 .tree()
2248 .find_value(&ObjectKey::object(symlink_object_id))
2249 .await
2250 .expect("find failed")
2251 .expect("found record");
2252 let raw_link = match value {
2253 ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. } => link,
2254 _ => panic!("Unexpected value {value:?}"),
2255 };
2256 let symlink_target = store.read_symlink(symlink_object_id).await?;
2257 let expected_symlink_target: String =
2259 ProxyFilename::new_with_hash_code(0, &raw_link).into();
2260 assert_eq!(symlink_target, expected_symlink_target.as_bytes());
2261
2262 fs.close().await.expect("Close failed");
2263 Ok(())
2264 }
2265
2266 async fn yield_to_executor() {
2267 let mut done = false;
2268 poll_fn(|cx| {
2269 if done {
2270 Poll::Ready(())
2271 } else {
2272 done = true;
2273 cx.waker().wake_by_ref();
2274 Poll::Pending
2275 }
2276 })
2277 .await;
2278 }
2279
2280 #[fuchsia::test]
2281 async fn test_create_directory() {
2282 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2283 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2284 let object_id = {
2285 let mut transaction = fs
2286 .root_store()
2287 .new_transaction(lock_keys![], Options::default())
2288 .await
2289 .expect("new_transaction failed");
2290 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
2291 .await
2292 .expect("create failed");
2293
2294 let child_dir = dir
2295 .create_child_dir(&mut transaction, "foo")
2296 .await
2297 .expect("create_child_dir failed");
2298 let _child_dir_file = child_dir
2299 .create_child_file(&mut transaction, "bar")
2300 .await
2301 .expect("create_child_file failed");
2302 let _child_file = dir
2303 .create_child_file(&mut transaction, "baz")
2304 .await
2305 .expect("create_child_file failed");
2306 dir.add_child_volume(&mut transaction, "corge", 100)
2307 .await
2308 .expect("add_child_volume failed");
2309 transaction.commit().await.expect("commit failed");
2310 fs.sync(SyncOptions::default()).await.expect("sync failed");
2311 dir.object_id()
2312 };
2313 fs.close().await.expect("Close failed");
2314 let device = fs.take_device().await;
2315 device.reopen(false);
2316 let fs = FxFilesystem::open(device).await.expect("open failed");
2317 {
2318 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2319 let (object_id, object_descriptor, _) =
2320 dir.lookup("foo").await.expect("lookup failed").expect("not found");
2321 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
2322 let child_dir =
2323 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2324 let (object_id, object_descriptor, _) =
2325 child_dir.lookup("bar").await.expect("lookup failed").expect("not found");
2326 assert_eq!(object_descriptor, ObjectDescriptor::File);
2327 let _child_dir_file = ObjectStore::open_object(
2328 &fs.root_store(),
2329 object_id,
2330 HandleOptions::default(),
2331 None,
2332 )
2333 .await
2334 .expect("open object failed");
2335 let (object_id, object_descriptor, _) =
2336 dir.lookup("baz").await.expect("lookup failed").expect("not found");
2337 assert_eq!(object_descriptor, ObjectDescriptor::File);
2338 let _child_file = ObjectStore::open_object(
2339 &fs.root_store(),
2340 object_id,
2341 HandleOptions::default(),
2342 None,
2343 )
2344 .await
2345 .expect("open object failed");
2346 let (object_id, object_descriptor, _) =
2347 dir.lookup("corge").await.expect("lookup failed").expect("not found");
2348 assert_eq!(object_id, 100);
2349 if let ObjectDescriptor::Volume = object_descriptor {
2350 } else {
2351 panic!("wrong ObjectDescriptor");
2352 }
2353
2354 assert_eq!(dir.lookup("qux").await.expect("lookup failed"), None);
2355 }
2356 fs.close().await.expect("Close failed");
2357 }
2358
2359 #[fuchsia::test]
2360 async fn test_set_wrapping_key_does_not_exist() {
2361 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2362 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2363 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2364 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2365 let store = root_volume
2366 .new_volume(
2367 "test",
2368 NewChildStoreOptions {
2369 options: StoreOptions {
2370 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2371 ..StoreOptions::default()
2372 },
2373 ..NewChildStoreOptions::default()
2374 },
2375 )
2376 .await
2377 .expect("new_volume failed");
2378
2379 let mut transaction = fs
2380 .root_store()
2381 .new_transaction(
2382 lock_keys![LockKey::object(
2383 store.store_object_id(),
2384 store.root_directory_object_id()
2385 )],
2386 Options::default(),
2387 )
2388 .await
2389 .expect("new transaction failed");
2390 let root_directory =
2391 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2392 let directory = root_directory
2393 .create_child_dir(&mut transaction, "foo")
2394 .await
2395 .expect("create_child_dir failed");
2396 transaction.commit().await.expect("commit failed");
2397 let mut transaction = fs
2398 .root_store()
2399 .new_transaction(
2400 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2401 Options::default(),
2402 )
2403 .await
2404 .expect("new transaction failed");
2405 directory
2406 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2407 .await
2408 .expect_err("wrapping key id 2 has not been added");
2409 transaction.commit().await.expect("commit failed");
2410 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2411 let mut transaction = fs
2412 .root_store()
2413 .new_transaction(
2414 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2415 Options::default(),
2416 )
2417 .await
2418 .expect("new transaction failed");
2419 directory
2420 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2421 .await
2422 .expect("wrapping key id 2 has been added");
2423 fs.close().await.expect("Close failed");
2424 }
2425
2426 #[fuchsia::test]
2427 async fn test_set_encryption_policy_on_unencrypted_nonempty_dir() {
2428 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2429 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2430 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2431 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2432 let store = root_volume
2433 .new_volume(
2434 "test",
2435 NewChildStoreOptions {
2436 options: StoreOptions {
2437 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2438 ..StoreOptions::default()
2439 },
2440 ..NewChildStoreOptions::default()
2441 },
2442 )
2443 .await
2444 .expect("new_volume failed");
2445
2446 let mut transaction = fs
2447 .root_store()
2448 .new_transaction(
2449 lock_keys![LockKey::object(
2450 store.store_object_id(),
2451 store.root_directory_object_id()
2452 )],
2453 Options::default(),
2454 )
2455 .await
2456 .expect("new transaction failed");
2457 let root_directory =
2458 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2459 let directory = root_directory
2460 .create_child_dir(&mut transaction, "foo")
2461 .await
2462 .expect("create_child_dir failed");
2463 let _file = directory
2464 .create_child_file(&mut transaction, "bar")
2465 .await
2466 .expect("create_child_file failed");
2467 transaction.commit().await.expect("commit failed");
2468 let mut transaction = fs
2469 .root_store()
2470 .new_transaction(
2471 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2472 Options::default(),
2473 )
2474 .await
2475 .expect("new transaction failed");
2476 directory
2477 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2478 .await
2479 .expect_err("directory is not empty");
2480 transaction.commit().await.expect("commit failed");
2481 fs.close().await.expect("Close failed");
2482 }
2483
2484 #[fuchsia::test]
2485 async fn test_create_file_or_subdir_in_locked_directory() {
2486 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2487 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2488 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2489 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2490 let store = root_volume
2491 .new_volume(
2492 "test",
2493 NewChildStoreOptions {
2494 options: StoreOptions {
2495 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2496 ..StoreOptions::default()
2497 },
2498 ..NewChildStoreOptions::default()
2499 },
2500 )
2501 .await
2502 .expect("new_volume failed");
2503
2504 let mut transaction = fs
2505 .root_store()
2506 .new_transaction(
2507 lock_keys![LockKey::object(
2508 store.store_object_id(),
2509 store.root_directory_object_id()
2510 )],
2511 Options::default(),
2512 )
2513 .await
2514 .expect("new transaction failed");
2515 let root_directory =
2516 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2517 let directory = root_directory
2518 .create_child_dir(&mut transaction, "foo")
2519 .await
2520 .expect("create_child_dir failed");
2521 transaction.commit().await.expect("commit failed");
2522 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2523 let transaction = fs
2524 .root_store()
2525 .new_transaction(
2526 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2527 Options::default(),
2528 )
2529 .await
2530 .expect("new transaction failed");
2531 directory
2532 .update_attributes(
2533 transaction,
2534 Some(&fio::MutableNodeAttributes {
2535 encryption_policy: Some(fio::FscryptPolicy {
2536 key_identifier: WRAPPING_KEY_ID,
2537 flags: crate::object_store::LEGACY_FSCRYPT_FLAGS,
2538 }),
2539 ..Default::default()
2540 }),
2541 0,
2542 None,
2543 )
2544 .await
2545 .expect("update attributes failed");
2546 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget wrapping key failed");
2547 let mut transaction = fs
2548 .root_store()
2549 .new_transaction(
2550 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2551 Options::default(),
2552 )
2553 .await
2554 .expect("new transaction failed");
2555 directory
2556 .create_child_dir(&mut transaction, "bar")
2557 .await
2558 .expect_err("cannot create a dir inside of a locked encrypted directory");
2559 directory
2560 .create_child_file(&mut transaction, "baz")
2561 .await
2562 .map(|_| ())
2563 .expect_err("cannot create a file inside of a locked encrypted directory");
2564 fs.close().await.expect("Close failed");
2565 }
2566
2567 #[fuchsia::test]
2568 async fn test_replace_child_with_object_in_locked_directory() {
2569 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2570 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2571 let crypt = Arc::new(new_insecure_crypt());
2572
2573 let (parent_oid, src_oid, dst_oid) = {
2574 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2575 let store = root_volume
2576 .new_volume(
2577 "test",
2578 NewChildStoreOptions {
2579 options: StoreOptions {
2580 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2581 ..StoreOptions::default()
2582 },
2583 ..Default::default()
2584 },
2585 )
2586 .await
2587 .expect("new_volume failed");
2588
2589 let mut transaction = fs
2590 .root_store()
2591 .new_transaction(
2592 lock_keys![LockKey::object(
2593 store.store_object_id(),
2594 store.root_directory_object_id()
2595 )],
2596 Options::default(),
2597 )
2598 .await
2599 .expect("new transaction failed");
2600 let root_directory = Directory::open(&store, store.root_directory_object_id())
2601 .await
2602 .expect("open failed");
2603 let directory = root_directory
2604 .create_child_dir(&mut transaction, "foo")
2605 .await
2606 .expect("create_child_dir failed");
2607 transaction.commit().await.expect("commit failed");
2608 crypt
2609 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
2610 .expect("add_wrapping_key failed");
2611 let transaction = fs
2612 .root_store()
2613 .new_transaction(
2614 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2615 Options::default(),
2616 )
2617 .await
2618 .expect("new transaction failed");
2619 directory
2620 .update_attributes(
2621 transaction,
2622 Some(&fio::MutableNodeAttributes {
2623 encryption_policy: Some(fio::FscryptPolicy {
2624 key_identifier: WRAPPING_KEY_ID,
2625 flags: crate::object_store::LEGACY_FSCRYPT_FLAGS,
2626 }),
2627 ..Default::default()
2628 }),
2629 0,
2630 None,
2631 )
2632 .await
2633 .expect("update attributes failed");
2634 let mut transaction = fs
2635 .root_store()
2636 .new_transaction(
2637 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2638 Options::default(),
2639 )
2640 .await
2641 .expect("new transaction failed");
2642 let src_child = directory
2643 .create_child_dir(&mut transaction, "fee")
2644 .await
2645 .expect("create_child_dir failed");
2646 let dst_child = directory
2647 .create_child_dir(&mut transaction, "faa")
2648 .await
2649 .expect("create_child_dir failed");
2650 transaction.commit().await.expect("commit failed");
2651 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget_wrapping_key failed");
2652 (directory.object_id(), src_child.object_id(), dst_child.object_id())
2653 };
2654 fs.close().await.expect("Close failed");
2655 let device = fs.take_device().await;
2656 device.reopen(false);
2657 let fs = FxFilesystem::open(device).await.expect("open failed");
2658 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2659 let store = root_volume
2660 .volume(
2661 "test",
2662 StoreOptions {
2663 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2664 ..StoreOptions::default()
2665 },
2666 )
2667 .await
2668 .expect("volume failed");
2669
2670 {
2671 let parent_directory = Directory::open(&store, parent_oid).await.expect("open failed");
2672 let layer_set = store.tree().layer_set();
2673 let mut merger = layer_set.merger();
2674 let mut encrypted_src_name = None;
2675 let mut encrypted_dst_name = None;
2676 let mut iter = parent_directory.iter(&mut merger).await.expect("iter_from failed");
2677 while let Some((name, object_id, object_descriptor)) = iter.get() {
2678 assert!(matches!(object_descriptor, ObjectDescriptor::Directory));
2679 if object_id == dst_oid {
2680 encrypted_dst_name = Some(name.to_string());
2681 } else if object_id == src_oid {
2682 encrypted_src_name = Some(name.to_string());
2683 }
2684 iter.advance().await.expect("iter advance failed");
2685 }
2686
2687 let src_child = parent_directory
2688 .lookup(&encrypted_src_name.expect("src child not found"))
2689 .await
2690 .expect("lookup failed")
2691 .expect("not found");
2692 let mut transaction = fs
2693 .root_store()
2694 .new_transaction(
2695 lock_keys![LockKey::object(
2696 store.store_object_id(),
2697 parent_directory.object_id(),
2698 )],
2699 Options::default(),
2700 )
2701 .await
2702 .expect("new transaction failed");
2703 replace_child_with_object(
2704 &mut transaction,
2705 Some((src_child.0, src_child.1)),
2706 (&parent_directory, &encrypted_dst_name.expect("dst child not found")),
2707 0,
2708 false,
2709 Timestamp::now(),
2710 )
2711 .await
2712 .expect_err("renames should fail within a locked directory");
2713 }
2714 fs.close().await.expect("Close failed");
2715 }
2716
2717 #[fuchsia::test]
2718 async fn test_set_encryption_policy_on_unencrypted_file() {
2719 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2720 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2721 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2722 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2723 let store = root_volume
2724 .new_volume(
2725 "test",
2726 NewChildStoreOptions {
2727 options: StoreOptions {
2728 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2729 ..StoreOptions::default()
2730 },
2731 ..NewChildStoreOptions::default()
2732 },
2733 )
2734 .await
2735 .expect("new_volume failed");
2736
2737 let mut transaction = fs
2738 .root_store()
2739 .new_transaction(
2740 lock_keys![LockKey::object(
2741 store.store_object_id(),
2742 store.root_directory_object_id()
2743 )],
2744 Options::default(),
2745 )
2746 .await
2747 .expect("new transaction failed");
2748 let root_directory =
2749 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2750 let file_handle = root_directory
2751 .create_child_file(&mut transaction, "foo")
2752 .await
2753 .expect("create_child_dir failed");
2754 transaction.commit().await.expect("commit failed");
2755 let mut transaction = fs
2756 .root_store()
2757 .new_transaction(
2758 lock_keys![LockKey::object(store.store_object_id(), file_handle.object_id())],
2759 Options::default(),
2760 )
2761 .await
2762 .expect("new transaction failed");
2763 file_handle
2764 .update_attributes(
2765 &mut transaction,
2766 Some(&fio::MutableNodeAttributes {
2767 encryption_policy: Some(fio::FscryptPolicy {
2768 key_identifier: WRAPPING_KEY_ID,
2769 flags: crate::object_store::LEGACY_FSCRYPT_FLAGS,
2770 }),
2771 ..Default::default()
2772 }),
2773 None,
2774 )
2775 .await
2776 .expect_err("Cannot update the wrapping key id of a file");
2777 fs.close().await.expect("Close failed");
2778 }
2779
2780 #[fuchsia::test]
2781 async fn test_delete_child() {
2782 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2783 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2784 let dir;
2785 let child;
2786 let mut transaction = fs
2787 .root_store()
2788 .new_transaction(lock_keys![], Options::default())
2789 .await
2790 .expect("new_transaction failed");
2791 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2792 .await
2793 .expect("create failed");
2794
2795 child =
2796 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2797 transaction.commit().await.expect("commit failed");
2798
2799 transaction = fs
2800 .root_store()
2801 .new_transaction(
2802 lock_keys![
2803 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2804 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2805 ],
2806 Options::default(),
2807 )
2808 .await
2809 .expect("new_transaction failed");
2810 assert_matches!(
2811 replace_child(&mut transaction, None, (&dir, "foo"))
2812 .await
2813 .expect("replace_child failed"),
2814 ReplacedChild::Object(..)
2815 );
2816 transaction.commit().await.expect("commit failed");
2817
2818 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2819 fs.close().await.expect("Close failed");
2820 }
2821
2822 #[fuchsia::test]
2823 async fn test_delete_child_with_children_fails() {
2824 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2825 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2826 let dir;
2827 let child;
2828 let bar;
2829 let mut transaction = fs
2830 .root_store()
2831 .new_transaction(lock_keys![], Options::default())
2832 .await
2833 .expect("new_transaction failed");
2834 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2835 .await
2836 .expect("create failed");
2837
2838 child =
2839 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2840 bar = child
2841 .create_child_file(&mut transaction, "bar")
2842 .await
2843 .expect("create_child_file failed");
2844 transaction.commit().await.expect("commit failed");
2845
2846 transaction = fs
2847 .root_store()
2848 .new_transaction(
2849 lock_keys![
2850 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2851 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2852 ],
2853 Options::default(),
2854 )
2855 .await
2856 .expect("new_transaction failed");
2857 assert_eq!(
2858 replace_child(&mut transaction, None, (&dir, "foo"))
2859 .await
2860 .expect_err("replace_child succeeded")
2861 .downcast::<FxfsError>()
2862 .expect("wrong error"),
2863 FxfsError::NotEmpty
2864 );
2865 transaction.commit().await.expect("commit failed");
2866
2867 transaction = fs
2868 .root_store()
2869 .new_transaction(
2870 lock_keys![
2871 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2872 LockKey::object(fs.root_store().store_object_id(), bar.object_id()),
2873 ],
2874 Options::default(),
2875 )
2876 .await
2877 .expect("new_transaction failed");
2878 assert_matches!(
2879 replace_child(&mut transaction, None, (&child, "bar"))
2880 .await
2881 .expect("replace_child failed"),
2882 ReplacedChild::Object(..)
2883 );
2884 transaction.commit().await.expect("commit failed");
2885
2886 transaction = fs
2887 .root_store()
2888 .new_transaction(
2889 lock_keys![
2890 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2891 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2892 ],
2893 Options::default(),
2894 )
2895 .await
2896 .expect("new_transaction failed");
2897 assert_matches!(
2898 replace_child(&mut transaction, None, (&dir, "foo"))
2899 .await
2900 .expect("replace_child failed"),
2901 ReplacedChild::Directory(..)
2902 );
2903 transaction.commit().await.expect("commit failed");
2904
2905 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2906 fs.close().await.expect("Close failed");
2907 }
2908
2909 #[fuchsia::test]
2910 async fn test_delete_and_reinsert_child() {
2911 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2912 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2913 let dir;
2914 let child;
2915 let mut transaction = fs
2916 .root_store()
2917 .new_transaction(lock_keys![], Options::default())
2918 .await
2919 .expect("new_transaction failed");
2920 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2921 .await
2922 .expect("create failed");
2923
2924 child =
2925 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2926 transaction.commit().await.expect("commit failed");
2927
2928 transaction = fs
2929 .root_store()
2930 .new_transaction(
2931 lock_keys![
2932 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2933 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2934 ],
2935 Options::default(),
2936 )
2937 .await
2938 .expect("new_transaction failed");
2939 assert_matches!(
2940 replace_child(&mut transaction, None, (&dir, "foo"))
2941 .await
2942 .expect("replace_child failed"),
2943 ReplacedChild::Object(..)
2944 );
2945 transaction.commit().await.expect("commit failed");
2946
2947 transaction = fs
2948 .root_store()
2949 .new_transaction(
2950 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2951 Options::default(),
2952 )
2953 .await
2954 .expect("new_transaction failed");
2955 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2956 transaction.commit().await.expect("commit failed");
2957
2958 dir.lookup("foo").await.expect("lookup failed");
2959 fs.close().await.expect("Close failed");
2960 }
2961
2962 #[fuchsia::test]
2963 async fn test_delete_child_persists() {
2964 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2965 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2966 let object_id = {
2967 let dir;
2968 let child;
2969 let mut transaction = fs
2970 .root_store()
2971 .new_transaction(lock_keys![], Options::default())
2972 .await
2973 .expect("new_transaction failed");
2974 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2975 .await
2976 .expect("create failed");
2977
2978 child = dir
2979 .create_child_file(&mut transaction, "foo")
2980 .await
2981 .expect("create_child_file failed");
2982 transaction.commit().await.expect("commit failed");
2983 dir.lookup("foo").await.expect("lookup failed");
2984
2985 transaction = fs
2986 .root_store()
2987 .new_transaction(
2988 lock_keys![
2989 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2990 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2991 ],
2992 Options::default(),
2993 )
2994 .await
2995 .expect("new_transaction failed");
2996 assert_matches!(
2997 replace_child(&mut transaction, None, (&dir, "foo"))
2998 .await
2999 .expect("replace_child failed"),
3000 ReplacedChild::Object(..)
3001 );
3002 transaction.commit().await.expect("commit failed");
3003
3004 fs.sync(SyncOptions::default()).await.expect("sync failed");
3005 dir.object_id()
3006 };
3007
3008 fs.close().await.expect("Close failed");
3009 let device = fs.take_device().await;
3010 device.reopen(false);
3011 let fs = FxFilesystem::open(device).await.expect("open failed");
3012 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
3013 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3014 fs.close().await.expect("Close failed");
3015 }
3016
3017 #[fuchsia::test]
3018 async fn test_replace_child() {
3019 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3020 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3021 let dir;
3022 let child_dir1;
3023 let child_dir2;
3024 let mut transaction = fs
3025 .root_store()
3026 .new_transaction(lock_keys![], Options::default())
3027 .await
3028 .expect("new_transaction failed");
3029 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3030 .await
3031 .expect("create failed");
3032
3033 child_dir1 =
3034 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
3035 child_dir2 =
3036 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
3037 let file = child_dir1
3038 .create_child_file(&mut transaction, "foo")
3039 .await
3040 .expect("create_child_file failed");
3041 transaction.commit().await.expect("commit failed");
3042
3043 transaction = fs
3044 .root_store()
3045 .new_transaction(
3046 lock_keys![
3047 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
3048 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
3049 LockKey::object(fs.root_store().store_object_id(), file.object_id()),
3050 ],
3051 Options::default(),
3052 )
3053 .await
3054 .expect("new_transaction failed");
3055 assert_matches!(
3056 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
3057 .await
3058 .expect("replace_child failed"),
3059 ReplacedChild::None
3060 );
3061 transaction.commit().await.expect("commit failed");
3062
3063 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
3064 child_dir2.lookup("bar").await.expect("lookup failed");
3065 fs.close().await.expect("Close failed");
3066 }
3067
3068 #[fuchsia::test]
3069 async fn test_replace_child_overwrites_dst() {
3070 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3071 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3072 let dir;
3073 let child_dir1;
3074 let child_dir2;
3075 let mut transaction = fs
3076 .root_store()
3077 .new_transaction(lock_keys![], Options::default())
3078 .await
3079 .expect("new_transaction failed");
3080 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3081 .await
3082 .expect("create failed");
3083
3084 child_dir1 =
3085 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
3086 child_dir2 =
3087 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
3088 let foo = child_dir1
3089 .create_child_file(&mut transaction, "foo")
3090 .await
3091 .expect("create_child_file failed");
3092 let bar = child_dir2
3093 .create_child_file(&mut transaction, "bar")
3094 .await
3095 .expect("create_child_file failed");
3096 let foo_oid = foo.object_id();
3097 let bar_oid = bar.object_id();
3098 transaction.commit().await.expect("commit failed");
3099
3100 {
3101 let mut buf = foo.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
3102 buf.fill(0xaa);
3103 foo.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3104 buf.fill(0xbb);
3105 bar.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3106 }
3107 std::mem::drop(bar);
3108 std::mem::drop(foo);
3109
3110 transaction = fs
3111 .root_store()
3112 .new_transaction(
3113 lock_keys![
3114 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
3115 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
3116 LockKey::object(fs.root_store().store_object_id(), foo_oid),
3117 LockKey::object(fs.root_store().store_object_id(), bar_oid),
3118 ],
3119 Options::default(),
3120 )
3121 .await
3122 .expect("new_transaction failed");
3123 assert_matches!(
3124 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
3125 .await
3126 .expect("replace_child failed"),
3127 ReplacedChild::Object(..)
3128 );
3129 transaction.commit().await.expect("commit failed");
3130
3131 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
3132
3133 let (oid, object_descriptor, _) =
3135 child_dir2.lookup("bar").await.expect("lookup failed").expect("not found");
3136 assert_eq!(object_descriptor, ObjectDescriptor::File);
3137 let bar =
3138 ObjectStore::open_object(&child_dir2.owner(), oid, HandleOptions::default(), None)
3139 .await
3140 .expect("Open failed");
3141 let mut buf = bar.allocate_buffer(bar.block_size().get() as usize).await;
3142 assert_eq!(
3143 bar.read_aligned(0, buf.as_mut()).await.expect("read failed"),
3144 TEST_DEVICE_BLOCK_SIZE as usize
3145 );
3146 assert_eq!(
3147 buf.as_ptr_slice().subslice(0..TEST_DEVICE_BLOCK_SIZE as usize).to_vec(),
3148 vec![0xaa; TEST_DEVICE_BLOCK_SIZE as usize]
3149 );
3150 fs.close().await.expect("Close failed");
3151 }
3152
3153 #[fuchsia::test]
3154 async fn test_replace_child_with_purge() {
3155 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3156 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3157 let dir;
3158 let mut transaction = fs
3159 .root_store()
3160 .new_transaction(lock_keys![], Options::default())
3161 .await
3162 .expect("new_transaction failed");
3163 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3164 .await
3165 .expect("create failed");
3166 let file =
3167 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
3168 let file_oid = file.object_id();
3169 transaction.commit().await.expect("commit failed");
3170
3171 {
3172 let mut buf = file.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
3173 buf.fill(0xaa);
3174 file.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
3175 }
3176 std::mem::drop(file);
3177
3178 let initial_alloc = fs.allocator().get_allocated_bytes();
3179 assert!(initial_alloc >= fs.block_size());
3180
3181 transaction = fs
3182 .root_store()
3183 .new_transaction(
3184 lock_keys![
3185 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3186 LockKey::object(fs.root_store().store_object_id(), file_oid),
3187 ],
3188 Options::default(),
3189 )
3190 .await
3191 .expect("new_transaction failed");
3192 assert_matches!(
3193 replace_child_with_purge(&mut transaction, None, (&dir, "foo"), true)
3194 .await
3195 .expect("replace_child_with_purge failed"),
3196 ReplacedChild::Purged(id) if id == file_oid
3197 );
3198 transaction.commit().await.expect("commit failed");
3199
3200 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3201 assert_eq!(fs.root_store().graveyard_count(), 0);
3202 assert_eq!(fs.allocator().get_allocated_bytes(), initial_alloc - fs.block_size());
3203 assert!(
3204 fs.root_store()
3205 .tree()
3206 .find(&ObjectKey::object(file_oid))
3207 .await
3208 .expect("find failed")
3209 .is_none()
3210 );
3211
3212 fs.close().await.expect("Close failed");
3213 }
3214
3215 #[fuchsia::test]
3216 async fn test_replace_child_fails_if_would_overwrite_nonempty_dir() {
3217 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3218 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3219 let dir;
3220 let child_dir1;
3221 let child_dir2;
3222 let mut transaction = fs
3223 .root_store()
3224 .new_transaction(lock_keys![], Options::default())
3225 .await
3226 .expect("new_transaction failed");
3227 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3228 .await
3229 .expect("create failed");
3230
3231 child_dir1 =
3232 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
3233 child_dir2 =
3234 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
3235 let foo = child_dir1
3236 .create_child_file(&mut transaction, "foo")
3237 .await
3238 .expect("create_child_file failed");
3239 let nested_child = child_dir2
3240 .create_child_dir(&mut transaction, "bar")
3241 .await
3242 .expect("create_child_file failed");
3243 nested_child
3244 .create_child_file(&mut transaction, "baz")
3245 .await
3246 .expect("create_child_file failed");
3247 transaction.commit().await.expect("commit failed");
3248
3249 transaction = fs
3250 .root_store()
3251 .new_transaction(
3252 lock_keys![
3253 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
3254 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
3255 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3256 LockKey::object(fs.root_store().store_object_id(), nested_child.object_id()),
3257 ],
3258 Options::default(),
3259 )
3260 .await
3261 .expect("new_transaction failed");
3262 assert_eq!(
3263 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
3264 .await
3265 .expect_err("replace_child succeeded")
3266 .downcast::<FxfsError>()
3267 .expect("wrong error"),
3268 FxfsError::NotEmpty
3269 );
3270 fs.close().await.expect("Close failed");
3271 }
3272
3273 #[fuchsia::test]
3274 async fn test_replace_child_within_dir() {
3275 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3276 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3277 let dir;
3278 let mut transaction = fs
3279 .root_store()
3280 .new_transaction(lock_keys![], Options::default())
3281 .await
3282 .expect("new_transaction failed");
3283 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3284 .await
3285 .expect("create failed");
3286 let foo =
3287 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
3288 transaction.commit().await.expect("commit failed");
3289
3290 transaction = fs
3291 .root_store()
3292 .new_transaction(
3293 lock_keys![
3294 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3295 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3296 ],
3297 Options::default(),
3298 )
3299 .await
3300 .expect("new_transaction failed");
3301 assert_matches!(
3302 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
3303 .await
3304 .expect("replace_child failed"),
3305 ReplacedChild::None
3306 );
3307 transaction.commit().await.expect("commit failed");
3308
3309 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3310 dir.lookup("bar").await.expect("lookup new name failed");
3311 fs.close().await.expect("Close failed");
3312 }
3313
3314 #[fuchsia::test]
3315 async fn test_replace_child_normal_into_encrypted_fails() {
3316 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3317 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3318 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
3319 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
3320 let store = root_volume(fs.clone())
3321 .await
3322 .expect("root_volume")
3323 .new_volume(
3324 "vol",
3325 NewChildStoreOptions {
3326 options: StoreOptions { crypt: Some(crypt.clone()), ..Default::default() },
3327 ..Default::default()
3328 },
3329 )
3330 .await
3331 .expect("new_volume");
3332
3333 let normal_dir;
3334 let encrypted_dir;
3335 let foo;
3336 let mut transaction = fs
3337 .root_store()
3338 .new_transaction(lock_keys![], Options::default())
3339 .await
3340 .expect("new_transaction failed");
3341 normal_dir =
3342 Directory::create(&mut transaction, &store, None).await.expect("create failed");
3343 encrypted_dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
3344 .await
3345 .expect("create failed");
3346 foo = normal_dir
3347 .create_child_file(&mut transaction, "foo")
3348 .await
3349 .expect("create_child_file failed");
3350 transaction.commit().await.expect("commit failed");
3351
3352 transaction = fs
3353 .root_store()
3354 .new_transaction(
3355 lock_keys![
3356 LockKey::object(store.store_object_id(), normal_dir.object_id()),
3357 LockKey::object(store.store_object_id(), encrypted_dir.object_id()),
3358 LockKey::object(store.store_object_id(), foo.object_id()),
3359 ],
3360 Options::default(),
3361 )
3362 .await
3363 .expect("new_transaction failed");
3364 assert_eq!(
3365 replace_child(&mut transaction, Some((&normal_dir, "foo")), (&encrypted_dir, "foo"))
3366 .await
3367 .expect_err("replace_child succeeded")
3368 .downcast::<FxfsError>()
3369 .expect("wrong error"),
3370 FxfsError::InconsistentEncryptionPolicy
3371 );
3372 fs.close().await.expect("Close failed");
3373 }
3374
3375 #[fuchsia::test]
3376 async fn test_iterate() {
3377 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3378 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3379 let dir;
3380 let mut transaction = fs
3381 .root_store()
3382 .new_transaction(lock_keys![], Options::default())
3383 .await
3384 .expect("new_transaction failed");
3385 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3386 .await
3387 .expect("create failed");
3388 let _cat =
3389 dir.create_child_file(&mut transaction, "cat").await.expect("create_child_file failed");
3390 let _ball = dir
3391 .create_child_file(&mut transaction, "ball")
3392 .await
3393 .expect("create_child_file failed");
3394 let apple = dir
3395 .create_child_file(&mut transaction, "apple")
3396 .await
3397 .expect("create_child_file failed");
3398 let _dog =
3399 dir.create_child_file(&mut transaction, "dog").await.expect("create_child_file failed");
3400 transaction.commit().await.expect("commit failed");
3401 transaction = fs
3402 .root_store()
3403 .new_transaction(
3404 lock_keys![
3405 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3406 LockKey::object(fs.root_store().store_object_id(), apple.object_id()),
3407 ],
3408 Options::default(),
3409 )
3410 .await
3411 .expect("new_transaction failed");
3412 replace_child(&mut transaction, None, (&dir, "apple")).await.expect("replace_child failed");
3413 transaction.commit().await.expect("commit failed");
3414 let layer_set = dir.store().tree().layer_set();
3415 let mut merger = layer_set.merger();
3416 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
3417 let mut entries = Vec::new();
3418 while let Some((name, _, _)) = iter.get() {
3419 entries.push(name.to_string());
3420 iter.advance().await.expect("advance failed");
3421 }
3422 assert_eq!(&entries, &["ball", "cat", "dog"]);
3423 fs.close().await.expect("Close failed");
3424 }
3425
3426 #[fuchsia::test]
3427 async fn test_sub_dir_count() {
3428 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3429 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3430 let dir;
3431 let child_dir;
3432 let mut transaction = fs
3433 .root_store()
3434 .new_transaction(lock_keys![], Options::default())
3435 .await
3436 .expect("new_transaction failed");
3437 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3438 .await
3439 .expect("create failed");
3440 child_dir =
3441 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3442 transaction.commit().await.expect("commit failed");
3443 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3444
3445 transaction = fs
3447 .root_store()
3448 .new_transaction(
3449 lock_keys![
3450 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3451 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3452 ],
3453 Options::default(),
3454 )
3455 .await
3456 .expect("new_transaction failed");
3457 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
3458 .await
3459 .expect("replace_child failed");
3460 transaction.commit().await.expect("commit failed");
3461
3462 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3463 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3464
3465 transaction = fs
3467 .root_store()
3468 .new_transaction(
3469 lock_keys![LockKey::object(
3470 fs.root_store().store_object_id(),
3471 child_dir.object_id()
3472 )],
3473 Options::default(),
3474 )
3475 .await
3476 .expect("new_transaction failed");
3477 let second_child = child_dir
3478 .create_child_dir(&mut transaction, "baz")
3479 .await
3480 .expect("create_child_dir failed");
3481 transaction.commit().await.expect("commit failed");
3482
3483 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3484
3485 transaction = fs
3486 .root_store()
3487 .new_transaction(
3488 lock_keys![
3489 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3490 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3491 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3492 ],
3493 Options::default(),
3494 )
3495 .await
3496 .expect("new_transaction failed");
3497 replace_child(&mut transaction, Some((&child_dir, "baz")), (&dir, "foo"))
3498 .await
3499 .expect("replace_child failed");
3500 transaction.commit().await.expect("commit failed");
3501
3502 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 2);
3503 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3504
3505 transaction = fs
3507 .root_store()
3508 .new_transaction(
3509 lock_keys![
3510 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3511 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3512 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3513 ],
3514 Options::default(),
3515 )
3516 .await
3517 .expect("new_transaction failed");
3518 replace_child(&mut transaction, Some((&dir, "bar")), (&dir, "foo"))
3519 .await
3520 .expect("replace_child failed");
3521 transaction.commit().await.expect("commit failed");
3522
3523 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3524
3525 transaction = fs
3527 .root_store()
3528 .new_transaction(
3529 lock_keys![
3530 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3531 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3532 ],
3533 Options::default(),
3534 )
3535 .await
3536 .expect("new_transaction failed");
3537 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3538 transaction.commit().await.expect("commit failed");
3539
3540 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3541 fs.close().await.expect("Close failed");
3542 }
3543
3544 #[fuchsia::test]
3545 async fn test_deleted_dir() {
3546 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3547 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3548 let dir;
3549 let mut transaction = fs
3550 .root_store()
3551 .new_transaction(lock_keys![], Options::default())
3552 .await
3553 .expect("new_transaction failed");
3554 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3555 .await
3556 .expect("create failed");
3557 let child =
3558 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3559 dir.create_child_dir(&mut transaction, "bar").await.expect("create_child_dir failed");
3560 transaction.commit().await.expect("commit failed");
3561
3562 dir.store().flush().await.expect("flush failed");
3564
3565 transaction = fs
3567 .root_store()
3568 .new_transaction(
3569 lock_keys![
3570 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3571 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
3572 ],
3573 Options::default(),
3574 )
3575 .await
3576 .expect("new_transaction failed");
3577 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3578 transaction.commit().await.expect("commit failed");
3579
3580 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3582
3583 assert!(dir.lookup("bar").await.expect("lookup failed").is_some());
3585
3586 dir.set_deleted();
3588
3589 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3590 assert_eq!(dir.lookup("bar").await.expect("lookup failed"), None);
3591 assert!(!dir.has_children().await.expect("has_children failed"));
3592
3593 transaction = fs
3594 .root_store()
3595 .new_transaction(lock_keys![], Options::default())
3596 .await
3597 .expect("new_transaction failed");
3598
3599 let assert_access_denied = |result| {
3600 if let Err(e) = result {
3601 assert!(FxfsError::Deleted.matches(&e));
3602 } else {
3603 panic!();
3604 }
3605 };
3606 assert_access_denied(dir.create_child_dir(&mut transaction, "baz").await.map(|_| {}));
3607 assert_access_denied(dir.create_child_file(&mut transaction, "baz").await.map(|_| {}));
3608 assert_access_denied(dir.add_child_volume(&mut transaction, "baz", 1).await);
3609 assert_access_denied(
3610 dir.insert_child(&mut transaction, "baz", 1, ObjectDescriptor::File).await,
3611 );
3612 assert_access_denied(
3613 dir.update_dir_attributes_internal(
3614 &mut transaction,
3615 dir.object_id(),
3616 MutableAttributesInternal {
3617 creation_time: Some(Timestamp::zero().as_nanos()),
3618 ..Default::default()
3619 },
3620 )
3621 .await,
3622 );
3623 let layer_set = dir.store().tree().layer_set();
3624 let mut merger = layer_set.merger();
3625 assert_access_denied(dir.iter(&mut merger).await.map(|_| {}));
3626 }
3627
3628 #[fuchsia::test]
3629 async fn test_create_symlink() {
3630 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3631 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3632 let (dir_id, symlink_id) = {
3633 let mut transaction = fs
3634 .root_store()
3635 .new_transaction(lock_keys![], Options::default())
3636 .await
3637 .expect("new_transaction failed");
3638 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
3639 .await
3640 .expect("create failed");
3641
3642 let symlink_id = dir
3643 .create_symlink(&mut transaction, b"link", "foo")
3644 .await
3645 .expect("create_symlink failed");
3646 transaction.commit().await.expect("commit failed");
3647
3648 fs.sync(SyncOptions::default()).await.expect("sync failed");
3649 (dir.object_id(), symlink_id)
3650 };
3651 fs.close().await.expect("Close failed");
3652 let device = fs.take_device().await;
3653 device.reopen(false);
3654 let fs = FxFilesystem::open(device).await.expect("open failed");
3655 {
3656 let dir = Directory::open(&fs.root_store(), dir_id).await.expect("open failed");
3657 assert_eq!(
3658 dir.lookup("foo").await.expect("lookup failed").expect("not found"),
3659 (symlink_id, ObjectDescriptor::Symlink, false)
3660 );
3661 }
3662 fs.close().await.expect("Close failed");
3663 }
3664
3665 #[fuchsia::test]
3666 async fn test_read_symlink() {
3667 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3668 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3669 let mut transaction = fs
3670 .root_store()
3671 .new_transaction(lock_keys![], Options::default())
3672 .await
3673 .expect("new_transaction failed");
3674 let store = fs.root_store();
3675 let dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3676
3677 let symlink_id = dir
3678 .create_symlink(&mut transaction, b"link", "foo")
3679 .await
3680 .expect("create_symlink failed");
3681 transaction.commit().await.expect("commit failed");
3682
3683 let link = store.read_symlink(symlink_id).await.expect("read_symlink failed");
3684 assert_eq!(&link, b"link");
3685 fs.close().await.expect("Close failed");
3686 }
3687
3688 #[fuchsia::test]
3689 async fn test_unlink_symlink() {
3690 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3691 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3692 let dir;
3693 let mut transaction = fs
3694 .root_store()
3695 .new_transaction(lock_keys![], Options::default())
3696 .await
3697 .expect("new_transaction failed");
3698 let store = fs.root_store();
3699 dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3700
3701 let symlink_id = dir
3702 .create_symlink(&mut transaction, b"link", "foo")
3703 .await
3704 .expect("create_symlink failed");
3705 transaction.commit().await.expect("commit failed");
3706 transaction = fs
3707 .root_store()
3708 .new_transaction(
3709 lock_keys![
3710 LockKey::object(store.store_object_id(), dir.object_id()),
3711 LockKey::object(store.store_object_id(), symlink_id),
3712 ],
3713 Options::default(),
3714 )
3715 .await
3716 .expect("new_transaction failed");
3717 assert_matches!(
3718 replace_child(&mut transaction, None, (&dir, "foo"))
3719 .await
3720 .expect("replace_child failed"),
3721 ReplacedChild::Object(_)
3722 );
3723 transaction.commit().await.expect("commit failed");
3724
3725 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3726 fs.close().await.expect("Close failed");
3727 }
3728
3729 #[fuchsia::test]
3730 async fn test_get_properties() {
3731 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3732 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3733 let dir;
3734 let mut transaction = fs
3735 .root_store()
3736 .new_transaction(lock_keys![], Options::default())
3737 .await
3738 .expect("new_transaction failed");
3739
3740 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3741 .await
3742 .expect("create failed");
3743 transaction.commit().await.expect("commit failed");
3744
3745 let mut properties = dir.get_properties().await.expect("get_properties failed");
3747 let dir_creation_time = properties.creation_time;
3748 assert_eq!(dir_creation_time, properties.modification_time);
3749 assert_eq!(properties.sub_dirs, 0);
3750 assert!(properties.posix_attributes.is_none());
3751
3752 transaction = fs
3754 .root_store()
3755 .new_transaction(
3756 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3757 Options::default(),
3758 )
3759 .await
3760 .expect("new_transaction failed");
3761 let child_dir =
3762 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3763 transaction.commit().await.expect("commit failed");
3764
3765 properties = dir.get_properties().await.expect("get_properties failed");
3767 assert_eq!(dir_creation_time, properties.creation_time);
3769 assert!(dir_creation_time < properties.modification_time);
3770 assert_eq!(properties.sub_dirs, 1);
3771 assert!(properties.posix_attributes.is_none());
3772
3773 properties = child_dir.get_properties().await.expect("get_properties failed");
3775 assert_eq!(properties.creation_time, properties.modification_time);
3776 assert_eq!(properties.sub_dirs, 0);
3777 assert!(properties.posix_attributes.is_none());
3778
3779 transaction = fs
3781 .root_store()
3782 .new_transaction(
3783 lock_keys![LockKey::object(
3784 fs.root_store().store_object_id(),
3785 child_dir.object_id()
3786 )],
3787 Options::default(),
3788 )
3789 .await
3790 .expect("new_transaction failed");
3791 let child_dir_file = child_dir
3792 .create_child_file(&mut transaction, "bar")
3793 .await
3794 .expect("create_child_file failed");
3795 child_dir_file
3796 .update_attributes(
3797 &mut transaction,
3798 Some(&fio::MutableNodeAttributes { gid: Some(1), ..Default::default() }),
3799 None,
3800 )
3801 .await
3802 .expect("Updating attributes");
3803 transaction.commit().await.expect("commit failed");
3804
3805 properties = child_dir.get_properties().await.expect("get_properties failed");
3807 assert!(properties.creation_time < properties.modification_time);
3808 assert!(properties.posix_attributes.is_none());
3809
3810 properties = child_dir_file.get_properties().await.expect("get_properties failed");
3812 assert_eq!(properties.creation_time, properties.modification_time);
3813 assert_eq!(properties.sub_dirs, 0);
3814 assert!(properties.posix_attributes.is_some());
3815 assert_eq!(properties.posix_attributes.unwrap().gid, 1);
3816 assert_eq!(properties.posix_attributes.unwrap().uid, 0);
3818 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3819 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3820 }
3821
3822 #[fuchsia::test]
3823 async fn test_update_create_attributes() {
3824 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3825 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3826 let dir;
3827 let mut transaction = fs
3828 .root_store()
3829 .new_transaction(lock_keys![], Options::default())
3830 .await
3831 .expect("new_transaction failed");
3832
3833 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3834 .await
3835 .expect("create failed");
3836 transaction.commit().await.expect("commit failed");
3837 let mut properties = dir.get_properties().await.expect("get_properties failed");
3838 assert_eq!(properties.sub_dirs, 0);
3839 assert!(properties.posix_attributes.is_none());
3840 let creation_time = properties.creation_time;
3841 let modification_time = properties.modification_time;
3842 assert_eq!(creation_time, modification_time);
3843
3844 transaction = fs
3850 .root_store()
3851 .new_transaction(
3852 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3853 Options::default(),
3854 )
3855 .await
3856 .expect("new_transaction failed");
3857 let now = Timestamp::now();
3858 dir.update_attributes(
3859 transaction,
3860 Some(&fio::MutableNodeAttributes {
3861 modification_time: Some(now.as_nanos()),
3862 uid: Some(1),
3863 gid: Some(2),
3864 ..Default::default()
3865 }),
3866 0,
3867 None,
3868 )
3869 .await
3870 .expect("update_attributes failed");
3871 properties = dir.get_properties().await.expect("get_properties failed");
3872 assert_eq!(properties.modification_time, now);
3874 assert!(properties.posix_attributes.is_some());
3875 assert_eq!(properties.posix_attributes.unwrap().uid, 1);
3876 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3877 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3879 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3880 assert_eq!(properties.sub_dirs, 0);
3882 assert_eq!(properties.creation_time, creation_time);
3883
3884 let transaction = fs
3887 .root_store()
3888 .new_transaction(
3889 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3890 Options::default(),
3891 )
3892 .await
3893 .expect("new_transaction failed");
3894 dir.update_attributes(
3895 transaction,
3896 Some(&fio::MutableNodeAttributes {
3897 creation_time: Some(now.as_nanos()),
3898 uid: Some(3),
3899 rdev: Some(10),
3900 ..Default::default()
3901 }),
3902 0,
3903 None,
3904 )
3905 .await
3906 .expect("update_attributes failed");
3907 properties = dir.get_properties().await.expect("get_properties failed");
3908 assert_eq!(properties.creation_time, now);
3909 assert!(properties.posix_attributes.is_some());
3910 assert_eq!(properties.posix_attributes.unwrap().uid, 3);
3911 assert_eq!(properties.posix_attributes.unwrap().rdev, 10);
3912 assert_eq!(properties.sub_dirs, 0);
3914 assert_eq!(properties.modification_time, now);
3915 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3916 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3917 }
3918
3919 #[fuchsia::test]
3920 async fn write_to_directory_attribute_creates_keys() {
3921 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3922 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3923 let crypt = Arc::new(new_insecure_crypt());
3924
3925 {
3926 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3927 let store = root_volume
3928 .new_volume(
3929 "vol",
3930 NewChildStoreOptions {
3931 options: StoreOptions {
3932 crypt: Some(crypt.clone()),
3933 ..StoreOptions::default()
3934 },
3935 ..Default::default()
3936 },
3937 )
3938 .await
3939 .expect("new_volume failed");
3940 let mut transaction = filesystem
3941 .root_store()
3942 .new_transaction(
3943 lock_keys![LockKey::object(
3944 store.store_object_id(),
3945 store.root_directory_object_id()
3946 )],
3947 Options::default(),
3948 )
3949 .await
3950 .expect("new transaction failed");
3951 let root_directory = Directory::open(&store, store.root_directory_object_id())
3952 .await
3953 .expect("open failed");
3954 let directory = root_directory
3955 .create_child_dir(&mut transaction, "foo")
3956 .await
3957 .expect("create_child_dir failed");
3958 transaction.commit().await.expect("commit failed");
3959
3960 let mut transaction = filesystem
3961 .root_store()
3962 .new_transaction(
3963 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
3964 Options::default(),
3965 )
3966 .await
3967 .expect("new transaction failed");
3968 let _ = directory
3969 .handle
3970 .write_attr(&mut transaction, AttributeId::TEST_ID, b"bar")
3971 .await
3972 .expect("write_attr failed");
3973 transaction.commit().await.expect("commit failed");
3974 }
3975
3976 filesystem.close().await.expect("Close failed");
3977 let device = filesystem.take_device().await;
3978 device.reopen(false);
3979 let filesystem = FxFilesystem::open(device).await.expect("open failed");
3980
3981 {
3982 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3983 let volume = root_volume
3984 .volume("vol", StoreOptions { crypt: Some(crypt), ..StoreOptions::default() })
3985 .await
3986 .expect("volume failed");
3987 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
3988 .await
3989 .expect("open failed");
3990 let directory = Directory::open(
3991 &volume,
3992 root_directory.lookup("foo").await.expect("lookup failed").expect("not found").0,
3993 )
3994 .await
3995 .expect("open failed");
3996 let mut buf = directory
3997 .handle
3998 .store()
3999 .device
4000 .allocate_buffer(directory.handle.block_size().get() as usize)
4001 .await;
4002 assert_eq!(
4003 directory
4004 .handle
4005 .read_aligned(AttributeId::TEST_ID, 0, buf.as_mut())
4006 .await
4007 .expect("read failed"),
4008 3
4009 );
4010 assert_eq!(buf.subslice(0..3).to_vec(), b"bar");
4011 }
4012
4013 filesystem.close().await.expect("Close failed");
4014 }
4015
4016 #[fuchsia::test]
4017 async fn directory_with_extended_attributes() {
4018 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
4019 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4020 let crypt = Arc::new(new_insecure_crypt());
4021
4022 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
4023 let store = root_volume
4024 .new_volume(
4025 "vol",
4026 NewChildStoreOptions {
4027 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4028 ..Default::default()
4029 },
4030 )
4031 .await
4032 .expect("new_volume failed");
4033 let directory =
4034 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4035
4036 let test_small_name = b"security.selinux".to_vec();
4037 let test_small_value = b"foo".to_vec();
4038 let test_large_name = b"large.attribute".to_vec();
4039 let test_large_value = vec![1u8; 500];
4040
4041 directory
4042 .set_extended_attribute(
4043 test_small_name.clone(),
4044 test_small_value.clone(),
4045 SetExtendedAttributeMode::Set,
4046 )
4047 .await
4048 .unwrap();
4049 assert_eq!(
4050 directory.get_extended_attribute(test_small_name.clone()).await.unwrap(),
4051 test_small_value
4052 );
4053
4054 directory
4055 .set_extended_attribute(
4056 test_large_name.clone(),
4057 test_large_value.clone(),
4058 SetExtendedAttributeMode::Set,
4059 )
4060 .await
4061 .unwrap();
4062 assert_eq!(
4063 directory.get_extended_attribute(test_large_name.clone()).await.unwrap(),
4064 test_large_value
4065 );
4066
4067 fsck(filesystem.clone()).await.unwrap();
4068 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4069 .await
4070 .unwrap();
4071
4072 directory.remove_extended_attribute(test_small_name.clone()).await.unwrap();
4073 directory.remove_extended_attribute(test_large_name.clone()).await.unwrap();
4074
4075 filesystem.close().await.expect("close failed");
4076 }
4077
4078 #[fuchsia::test]
4079 async fn remove_directory_with_extended_attributes() {
4080 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
4081 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4082 let crypt = Arc::new(new_insecure_crypt());
4083
4084 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
4085 let store = root_volume
4086 .new_volume(
4087 "vol",
4088 NewChildStoreOptions {
4089 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4090 ..Default::default()
4091 },
4092 )
4093 .await
4094 .expect("new_volume failed");
4095 let mut transaction = filesystem
4096 .root_store()
4097 .new_transaction(
4098 lock_keys![LockKey::object(
4099 store.store_object_id(),
4100 store.root_directory_object_id()
4101 )],
4102 Options::default(),
4103 )
4104 .await
4105 .expect("new transaction failed");
4106 let root_directory =
4107 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4108 let directory = root_directory
4109 .create_child_dir(&mut transaction, "foo")
4110 .await
4111 .expect("create_child_dir failed");
4112 transaction.commit().await.expect("commit failed");
4113
4114 fsck(filesystem.clone()).await.unwrap();
4115 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4116 .await
4117 .unwrap();
4118
4119 let test_small_name = b"security.selinux".to_vec();
4120 let test_small_value = b"foo".to_vec();
4121 let test_large_name = b"large.attribute".to_vec();
4122 let test_large_value = vec![1u8; 500];
4123
4124 directory
4125 .set_extended_attribute(
4126 test_small_name.clone(),
4127 test_small_value.clone(),
4128 SetExtendedAttributeMode::Set,
4129 )
4130 .await
4131 .unwrap();
4132 directory
4133 .set_extended_attribute(
4134 test_large_name.clone(),
4135 test_large_value.clone(),
4136 SetExtendedAttributeMode::Set,
4137 )
4138 .await
4139 .unwrap();
4140
4141 fsck(filesystem.clone()).await.unwrap();
4142 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4143 .await
4144 .unwrap();
4145
4146 let mut transaction = filesystem
4147 .root_store()
4148 .new_transaction(
4149 lock_keys![
4150 LockKey::object(store.store_object_id(), root_directory.object_id()),
4151 LockKey::object(store.store_object_id(), directory.object_id()),
4152 ],
4153 Options::default(),
4154 )
4155 .await
4156 .expect("new_transaction failed");
4157 replace_child(&mut transaction, None, (&root_directory, "foo"))
4158 .await
4159 .expect("replace_child failed");
4160 transaction.commit().await.unwrap();
4161
4162 fsck(filesystem.clone()).await.unwrap();
4163 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4164 .await
4165 .unwrap();
4166
4167 filesystem.close().await.expect("close failed");
4168 }
4169
4170 #[fuchsia::test]
4171 async fn remove_symlink_with_extended_attributes() {
4172 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
4173 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4174 let crypt = Arc::new(new_insecure_crypt());
4175
4176 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
4177 let store = root_volume
4178 .new_volume(
4179 "vol",
4180 NewChildStoreOptions {
4181 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4182 ..Default::default()
4183 },
4184 )
4185 .await
4186 .expect("new_volume failed");
4187 let mut transaction = filesystem
4188 .root_store()
4189 .new_transaction(
4190 lock_keys![LockKey::object(
4191 store.store_object_id(),
4192 store.root_directory_object_id()
4193 )],
4194 Options::default(),
4195 )
4196 .await
4197 .expect("new transaction failed");
4198 let root_directory =
4199 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
4200 let symlink_id = root_directory
4201 .create_symlink(&mut transaction, b"somewhere/else", "foo")
4202 .await
4203 .expect("create_symlink failed");
4204 transaction.commit().await.expect("commit failed");
4205
4206 let symlink = StoreObjectHandle::new(
4207 store.clone(),
4208 symlink_id,
4209 false,
4210 HandleOptions::default(),
4211 false,
4212 );
4213
4214 fsck(filesystem.clone()).await.unwrap();
4215 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4216 .await
4217 .unwrap();
4218
4219 let test_small_name = b"security.selinux".to_vec();
4220 let test_small_value = b"foo".to_vec();
4221 let test_large_name = b"large.attribute".to_vec();
4222 let test_large_value = vec![1u8; 500];
4223
4224 symlink
4225 .set_extended_attribute(
4226 test_small_name.clone(),
4227 test_small_value.clone(),
4228 SetExtendedAttributeMode::Set,
4229 )
4230 .await
4231 .unwrap();
4232 symlink
4233 .set_extended_attribute(
4234 test_large_name.clone(),
4235 test_large_value.clone(),
4236 SetExtendedAttributeMode::Set,
4237 )
4238 .await
4239 .unwrap();
4240
4241 fsck(filesystem.clone()).await.unwrap();
4242 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4243 .await
4244 .unwrap();
4245
4246 let mut transaction = filesystem
4247 .root_store()
4248 .new_transaction(
4249 lock_keys![
4250 LockKey::object(store.store_object_id(), root_directory.object_id()),
4251 LockKey::object(store.store_object_id(), symlink.object_id()),
4252 ],
4253 Options::default(),
4254 )
4255 .await
4256 .expect("new_transaction failed");
4257 replace_child(&mut transaction, None, (&root_directory, "foo"))
4258 .await
4259 .expect("replace_child failed");
4260 transaction.commit().await.unwrap();
4261
4262 fsck(filesystem.clone()).await.unwrap();
4263 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
4264 .await
4265 .unwrap();
4266
4267 filesystem.close().await.expect("close failed");
4268 }
4269
4270 #[fuchsia::test]
4271 async fn test_update_timestamps() {
4272 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4273 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4274 let dir;
4275 let mut transaction = fs
4276 .root_store()
4277 .new_transaction(lock_keys![], Options::default())
4278 .await
4279 .expect("new_transaction failed");
4280
4281 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4284 .await
4285 .expect("create failed");
4286 transaction.commit().await.expect("commit failed");
4287 let mut properties = dir.get_properties().await.expect("get_properties failed");
4288 let starting_time = properties.creation_time;
4289 assert_eq!(properties.creation_time, starting_time);
4290 assert_eq!(properties.modification_time, starting_time);
4291 assert_eq!(properties.change_time, starting_time);
4292 assert_eq!(properties.access_time, starting_time);
4293
4294 transaction = fs
4296 .root_store()
4297 .new_transaction(
4298 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
4299 Options::default(),
4300 )
4301 .await
4302 .expect("new_transaction failed");
4303 let update1_time = Timestamp::now();
4304 dir.update_attributes(
4305 transaction,
4306 Some(&fio::MutableNodeAttributes {
4307 modification_time: Some(update1_time.as_nanos()),
4308 ..Default::default()
4309 }),
4310 0,
4311 Some(update1_time),
4312 )
4313 .await
4314 .expect("update_attributes failed");
4315 properties = dir.get_properties().await.expect("get_properties failed");
4316 assert_eq!(properties.modification_time, update1_time);
4317 assert_eq!(properties.access_time, starting_time);
4318 assert_eq!(properties.creation_time, starting_time);
4319 assert_eq!(properties.change_time, update1_time);
4320 }
4321
4322 #[fuchsia::test]
4323 async fn test_move_dir_timestamps() {
4324 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4325 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4326 let dir;
4327 let child1;
4328 let child2;
4329 let mut transaction = fs
4330 .root_store()
4331 .new_transaction(lock_keys![], Options::default())
4332 .await
4333 .expect("new_transaction failed");
4334 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4335 .await
4336 .expect("create failed");
4337 child1 = dir
4338 .create_child_dir(&mut transaction, "child1")
4339 .await
4340 .expect("create_child_dir failed");
4341 child2 = dir
4342 .create_child_dir(&mut transaction, "child2")
4343 .await
4344 .expect("create_child_dir failed");
4345 transaction.commit().await.expect("commit failed");
4346 let dir_properties = dir.get_properties().await.expect("get_properties failed");
4347 let child2_properties = child2.get_properties().await.expect("get_properties failed");
4348
4349 transaction = fs
4351 .root_store()
4352 .new_transaction(
4353 lock_keys![
4354 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4355 LockKey::object(fs.root_store().store_object_id(), child1.object_id()),
4356 LockKey::object(fs.root_store().store_object_id(), child2.object_id()),
4357 ],
4358 Options::default(),
4359 )
4360 .await
4361 .expect("new_transaction failed");
4362 assert_matches!(
4363 replace_child(&mut transaction, Some((&dir, "child2")), (&child1, "child2"))
4364 .await
4365 .expect("replace_child failed"),
4366 ReplacedChild::None
4367 );
4368 transaction.commit().await.expect("commit failed");
4369 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
4371 let time_of_replacement = new_dir_properties.change_time;
4372 assert!(new_dir_properties.change_time > dir_properties.change_time);
4373 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
4374 let new_child1_properties = child1.get_properties().await.expect("get_properties failed");
4376 assert_eq!(new_child1_properties.modification_time, time_of_replacement);
4377 assert_eq!(new_child1_properties.change_time, time_of_replacement);
4378 let moved_child2_properties = child2.get_properties().await.expect("get_properties failed");
4380 assert_eq!(moved_child2_properties.change_time, time_of_replacement);
4381 assert_eq!(moved_child2_properties.creation_time, child2_properties.creation_time);
4382 assert_eq!(moved_child2_properties.access_time, child2_properties.access_time);
4383 assert_eq!(moved_child2_properties.modification_time, child2_properties.modification_time);
4384 fs.close().await.expect("Close failed");
4385 }
4386
4387 #[fuchsia::test]
4388 async fn test_unlink_timestamps() {
4389 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4390 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4391 let dir;
4392 let foo;
4393 let mut transaction = fs
4394 .root_store()
4395 .new_transaction(lock_keys![], Options::default())
4396 .await
4397 .expect("new_transaction failed");
4398 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4399 .await
4400 .expect("create failed");
4401 foo =
4402 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_dir failed");
4403
4404 transaction.commit().await.expect("commit failed");
4405 let dir_properties = dir.get_properties().await.expect("get_properties failed");
4406 let foo_properties = foo.get_properties().await.expect("get_properties failed");
4407
4408 transaction = fs
4409 .root_store()
4410 .new_transaction(
4411 lock_keys![
4412 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4413 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
4414 ],
4415 Options::default(),
4416 )
4417 .await
4418 .expect("new_transaction failed");
4419 assert_matches!(
4420 replace_child(&mut transaction, None, (&dir, "foo"))
4421 .await
4422 .expect("replace_child failed"),
4423 ReplacedChild::Object(_)
4424 );
4425 transaction.commit().await.expect("commit failed");
4426 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
4428 let time_of_replacement = new_dir_properties.change_time;
4429 assert!(new_dir_properties.change_time > dir_properties.change_time);
4430 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
4431 let moved_foo_properties = foo.get_properties().await.expect("get_properties failed");
4433 assert_eq!(moved_foo_properties.change_time, time_of_replacement);
4434 assert_eq!(moved_foo_properties.creation_time, foo_properties.creation_time);
4435 assert_eq!(moved_foo_properties.access_time, foo_properties.access_time);
4436 assert_eq!(moved_foo_properties.modification_time, foo_properties.modification_time);
4437 fs.close().await.expect("Close failed");
4438 }
4439
4440 #[fuchsia::test]
4441 async fn test_replace_dir_timestamps() {
4442 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4443 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4444 let dir;
4445 let child_dir1;
4446 let child_dir2;
4447 let foo;
4448 let mut transaction = fs
4449 .root_store()
4450 .new_transaction(lock_keys![], Options::default())
4451 .await
4452 .expect("new_transaction failed");
4453 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4454 .await
4455 .expect("create failed");
4456 child_dir1 =
4457 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
4458 child_dir2 =
4459 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
4460 foo = child_dir1
4461 .create_child_dir(&mut transaction, "foo")
4462 .await
4463 .expect("create_child_dir failed");
4464 transaction.commit().await.expect("commit failed");
4465 let dir_props = dir.get_properties().await.expect("get_properties failed");
4466 let foo_props = foo.get_properties().await.expect("get_properties failed");
4467
4468 transaction = fs
4469 .root_store()
4470 .new_transaction(
4471 lock_keys![
4472 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4473 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
4474 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
4475 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
4476 ],
4477 Options::default(),
4478 )
4479 .await
4480 .expect("new_transaction failed");
4481 assert_matches!(
4482 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&dir, "dir2"))
4483 .await
4484 .expect("replace_child failed"),
4485 ReplacedChild::Directory(_)
4486 );
4487 transaction.commit().await.expect("commit failed");
4488 let new_dir_props = dir.get_properties().await.expect("get_properties failed");
4490 let time_of_replacement = new_dir_props.change_time;
4491 assert!(new_dir_props.change_time > dir_props.change_time);
4492 assert_eq!(new_dir_props.modification_time, time_of_replacement);
4493 let new_dir1_props = child_dir1.get_properties().await.expect("get_properties failed");
4495 let time_of_replacement = new_dir1_props.change_time;
4496 assert_eq!(new_dir1_props.change_time, time_of_replacement);
4497 assert_eq!(new_dir1_props.modification_time, time_of_replacement);
4498 let moved_foo_props = foo.get_properties().await.expect("get_properties failed");
4500 assert_eq!(moved_foo_props.change_time, time_of_replacement);
4501 assert_eq!(moved_foo_props.creation_time, foo_props.creation_time);
4502 assert_eq!(moved_foo_props.access_time, foo_props.access_time);
4503 assert_eq!(moved_foo_props.modification_time, foo_props.modification_time);
4504 fs.close().await.expect("Close failed");
4505 }
4506
4507 #[fuchsia::test]
4508 async fn test_create_casefold_directory() {
4509 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4510 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4511 let object_id = {
4512 let mut transaction = fs
4513 .root_store()
4514 .new_transaction(lock_keys![], Options::default())
4515 .await
4516 .expect("new_transaction failed");
4517 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
4518 .await
4519 .expect("create failed");
4520
4521 let child_dir = dir
4522 .create_child_dir(&mut transaction, "foo")
4523 .await
4524 .expect("create_child_dir failed");
4525 let _child_dir_file = child_dir
4526 .create_child_file(&mut transaction, "bAr")
4527 .await
4528 .expect("create_child_file failed");
4529 transaction.commit().await.expect("commit failed");
4530 dir.object_id()
4531 };
4532 fs.close().await.expect("Close failed");
4533 let device = fs.take_device().await;
4534
4535 device.reopen(false);
4538 let fs = FxFilesystem::open(device).await.expect("open failed");
4539 {
4540 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4541 let (object_id, object_descriptor, _) =
4542 dir.lookup("foo").await.expect("lookup failed").expect("not found");
4543 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
4544 let child_dir =
4545 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4546 assert!(!child_dir.dir_type().is_casefold());
4547 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_none());
4548 let (object_id, descriptor, _) =
4549 child_dir.lookup("bAr").await.expect("lookup failed").unwrap();
4550 assert_eq!(descriptor, ObjectDescriptor::File);
4551
4552 child_dir.set_casefold(true).await.expect_err("not empty");
4554
4555 let mut transaction = fs
4557 .root_store()
4558 .new_transaction(
4559 lock_keys![
4560 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
4561 LockKey::object(fs.root_store().store_object_id(), object_id),
4562 ],
4563 Options::default(),
4564 )
4565 .await
4566 .expect("new_transaction failed");
4567 assert_matches!(
4568 replace_child(&mut transaction, None, (&child_dir, "bAr"))
4569 .await
4570 .expect("replace_child failed"),
4571 ReplacedChild::Object(..)
4572 );
4573 transaction.commit().await.expect("commit failed");
4574
4575 child_dir.set_casefold(true).await.expect("set casefold");
4577
4578 assert!(child_dir.dir_type().is_casefold());
4579
4580 let mut transaction = fs
4582 .root_store()
4583 .new_transaction(
4584 lock_keys![LockKey::object(
4585 fs.root_store().store_object_id(),
4586 child_dir.object_id()
4587 ),],
4588 Options::default(),
4589 )
4590 .await
4591 .expect("new_transaction failed");
4592 let _child_dir_file = child_dir
4593 .create_child_file(&mut transaction, "bAr")
4594 .await
4595 .expect("create_child_file failed");
4596 transaction.commit().await.expect("commit failed");
4597
4598 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_some());
4600 assert!(child_dir.lookup("bAr").await.expect("lookup failed").is_some());
4601
4602 child_dir.set_casefold(true).await.expect_err("set casefold");
4604 assert!(child_dir.dir_type().is_casefold());
4605
4606 let mut transaction = fs
4608 .root_store()
4609 .new_transaction(
4610 lock_keys![LockKey::object(
4611 fs.root_store().store_object_id(),
4612 child_dir.object_id()
4613 ),],
4614 Options::default(),
4615 )
4616 .await
4617 .expect("new_transaction failed");
4618 let sub_dir = child_dir
4619 .create_child_dir(&mut transaction, "sub")
4620 .await
4621 .expect("create_sub_dir failed");
4622 transaction.commit().await.expect("commit failed");
4623 assert!(sub_dir.dir_type().is_casefold());
4624 };
4625 fs.close().await.expect("Close failed");
4626 }
4627
4628 #[fuchsia::test]
4629 async fn test_create_casefold_encrypted_directory() {
4630 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4631 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4632 let proxy_filename: ProxyFilename;
4633 let object_id;
4634 {
4635 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4636 let root_volume = root_volume(fs.clone()).await.unwrap();
4637 let store = root_volume
4638 .new_volume(
4639 "vol",
4640 NewChildStoreOptions {
4641 options: StoreOptions {
4642 crypt: Some(crypt.clone()),
4643 ..StoreOptions::default()
4644 },
4645 ..Default::default()
4646 },
4647 )
4648 .await
4649 .unwrap();
4650
4651 crypt
4653 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4654 .expect("add wrapping key failed");
4655
4656 object_id = {
4657 let mut transaction = fs
4658 .root_store()
4659 .new_transaction(lock_keys![], Options::default())
4660 .await
4661 .expect("new_transaction failed");
4662 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4663 .await
4664 .expect("create failed");
4665
4666 transaction.commit().await.expect("commit");
4667 dir.object_id()
4668 };
4669 let dir = Directory::open(&store, object_id).await.expect("open failed");
4670
4671 dir.set_casefold(true).await.expect("set casefold");
4672 assert!(dir.dir_type().is_casefold());
4673
4674 let mut transaction = fs
4675 .root_store()
4676 .new_transaction(
4677 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4678 Options::default(),
4679 )
4680 .await
4681 .expect("new_transaction failed");
4682 let _file = dir
4683 .create_child_file(&mut transaction, "bAr")
4684 .await
4685 .expect("create_child_file failed");
4686 transaction.commit().await.expect("commit failed");
4687
4688 assert!(dir.lookup("bAr").await.expect("original lookup failed").is_some());
4690
4691 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4694 let encrypted_name =
4695 encrypt_filename(&*key, dir.object_id(), "bAr").expect("encrypt_filename");
4696 let hash_code = key.hash_code_casefold("bAr");
4697 proxy_filename = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4698
4699 assert!(dir.lookup("BAR").await.expect("casefold lookup failed").is_some());
4701
4702 assert_eq!(key.hash_code_casefold("bar"), key.hash_code_casefold("BaR"));
4704
4705 let mut count = 0;
4708 let layer_set = dir.store().tree().layer_set();
4709 let mut merger = layer_set.merger();
4710 let mut iter = dir.iter(&mut merger).await.expect("iter");
4711 while let Some(_entry) = iter.get() {
4712 count += 1;
4713 iter.advance().await.expect("advance");
4714 }
4715 assert_eq!(1, count, "unexpected number of entries.");
4716
4717 fs.close().await.expect("Close failed");
4718 }
4719
4720 let device = fs.take_device().await;
4721
4722 device.reopen(false);
4725 let fs = FxFilesystem::open(device).await.expect("open failed");
4726 {
4727 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4728 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4729 let store = root_volume
4730 .volume(
4731 "vol",
4732 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4733 )
4734 .await
4735 .expect("volume failed");
4736 let dir = Directory::open(&store, object_id).await.expect("open failed");
4737 assert!(dir.dir_type().is_casefold());
4738
4739 assert!(dir.lookup("bAr").await.expect("lookup failed").is_none());
4741 let filename: String = proxy_filename.into();
4743 assert!(dir.lookup(&filename).await.expect("lookup failed").is_some());
4744
4745 let layer_set = dir.store().tree().layer_set();
4746 let mut merger = layer_set.merger();
4747 let mut iter = dir.iter(&mut merger).await.expect("iter");
4748 let item = iter.get().expect("expect item");
4749 let filename: String = proxy_filename.into();
4750 assert_eq!(item.0, &filename);
4751 iter.advance().await.expect("advance");
4752 assert_eq!(None, iter.get());
4753
4754 fsck(fs.clone()).await.unwrap();
4755 fsck_volume(fs.as_ref(), store.store_object_id(), Some(crypt.clone())).await.unwrap();
4756
4757 fs.close().await.expect("Close failed");
4758 }
4759 }
4760
4761 #[allow(dead_code)]
4772 fn find_out_of_order_sha256_long_prefix_pair(
4773 object_id: u64,
4774 key: &Arc<dyn Cipher>,
4775 ) -> Option<[String; 2]> {
4776 let mut collision_map: std::collections::HashMap<u32, (usize, ProxyFilename, Vec<u8>)> =
4777 std::collections::HashMap::new();
4778 for i in 0..(1usize << 32) {
4779 let filename = format!("{:0>176}_{i}", 0);
4780 let encrypted_name =
4781 encrypt_filename(&**key, object_id, &filename).expect("encrypt_filename");
4782 let hash_code = key.hash_code_casefold(&filename);
4783 let a = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4784 let hash_code = a.hash_code as u32;
4785 if let Some((j, b, b_encrypted_name)) = collision_map.get(&hash_code) {
4786 assert_eq!(a.filename, b.filename);
4787 if encrypted_name.cmp(b_encrypted_name) != a.sha256.cmp(&b.sha256) {
4788 return Some([format!("{:0>176}_{i}", 0), format!("{:0>176}_{j}", 0)]);
4789 }
4790 } else {
4791 collision_map.insert(hash_code, (i, a, encrypted_name));
4792 }
4793 }
4794 None
4795 }
4796
4797 #[fuchsia::test]
4798 async fn test_proxy_filename() {
4799 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4800 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4801 let mut filenames = Vec::new();
4802 let object_id;
4803 {
4804 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4805 let root_volume = root_volume(fs.clone()).await.unwrap();
4806 let store = root_volume
4807 .new_volume(
4808 "vol",
4809 NewChildStoreOptions {
4810 options: StoreOptions {
4811 crypt: Some(crypt.clone()),
4812 ..StoreOptions::default()
4813 },
4814 ..Default::default()
4815 },
4816 )
4817 .await
4818 .unwrap();
4819
4820 crypt
4822 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4823 .expect("add wrapping key failed");
4824
4825 object_id = {
4826 let mut transaction = fs
4827 .root_store()
4828 .new_transaction(lock_keys![], Options::default())
4829 .await
4830 .expect("new_transaction failed");
4831 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4832 .await
4833 .expect("create failed");
4834
4835 transaction.commit().await.expect("commit");
4836 dir.object_id()
4837 };
4838
4839 let dir = Directory::open(&store, object_id).await.expect("open failed");
4840
4841 dir.set_casefold(true).await.expect("set casefold");
4842 assert!(dir.dir_type().is_casefold());
4843
4844 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4845
4846 let collision_pair =
4856 [format!("{:0>176}_{}", 0, 93515), format!("{:0>176}_{}", 0, 15621)];
4857
4858 for filename in (0..64)
4861 .into_iter()
4862 .map(|i| format!("{:0>176}_{i}", 0))
4863 .chain(collision_pair.into_iter())
4864 {
4865 let hash_code = key.hash_code_casefold(&filename);
4866 let encrypted_name =
4867 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
4868 let proxy_filename =
4869 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4870 let mut transaction = fs
4871 .root_store()
4872 .new_transaction(
4873 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4874 Options::default(),
4875 )
4876 .await
4877 .expect("new_transaction failed");
4878 let file = dir
4879 .create_child_file(&mut transaction, &filename)
4880 .await
4881 .expect("create_child_file failed");
4882 filenames.push((proxy_filename, file.object_id()));
4883 transaction.commit().await.expect("commit failed");
4884 }
4885
4886 fs.close().await.expect("Close failed");
4887 }
4888
4889 let device = fs.take_device().await;
4890
4891 device.reopen(false);
4893 let fs = FxFilesystem::open(device).await.expect("open failed");
4894 {
4895 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4896 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4897 let store = root_volume
4898 .volume(
4899 "vol",
4900 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4901 )
4902 .await
4903 .expect("volume failed");
4904 let dir = Directory::open(&store, object_id).await.expect("open failed");
4905 assert!(dir.dir_type().is_casefold());
4906
4907 assert_eq!(
4909 filenames.iter().map(|(name, _)| (*name).into()).collect::<HashSet<String>>().len(),
4910 filenames.len()
4911 );
4912
4913 let filename = filenames[0].0.filename.clone();
4914 for (proxy_filename, object_id) in &filenames {
4915 assert_eq!(filename, proxy_filename.filename);
4917
4918 let proxy_filename_str: String = (*proxy_filename).into();
4919 let item = dir
4920 .lookup(&proxy_filename_str)
4921 .await
4922 .expect("lookup failed")
4923 .expect("lookup is not None");
4924 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4925 }
4926
4927 fs.close().await.expect("Close failed");
4928 }
4929 }
4930
4931 #[fuchsia::test]
4932 async fn test_replace_directory_and_tombstone_on_remount() {
4933 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
4934 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4935 let crypt = Arc::new(new_insecure_crypt());
4936 {
4937 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4938 let store = root_volume
4939 .new_volume(
4940 "test",
4941 NewChildStoreOptions {
4942 options: StoreOptions {
4943 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4944 ..StoreOptions::default()
4945 },
4946 ..Default::default()
4947 },
4948 )
4949 .await
4950 .expect("new_volume failed");
4951
4952 let mut transaction = fs
4953 .root_store()
4954 .new_transaction(
4955 lock_keys![LockKey::object(
4956 store.store_object_id(),
4957 store.root_directory_object_id()
4958 )],
4959 Options::default(),
4960 )
4961 .await
4962 .expect("new transaction failed");
4963
4964 let root_directory = Directory::open(&store, store.root_directory_object_id())
4965 .await
4966 .expect("open failed");
4967 let _directory = root_directory
4968 .create_child_dir(&mut transaction, "foo")
4969 .await
4970 .expect("create_child_dir failed");
4971 let directory = root_directory
4972 .create_child_dir(&mut transaction, "bar")
4973 .await
4974 .expect("create_child_dir failed");
4975 let oid = directory.object_id();
4976
4977 transaction.commit().await.expect("commit failed");
4978
4979 let mut transaction = fs
4980 .root_store()
4981 .new_transaction(
4982 lock_keys![LockKey::object(
4983 store.store_object_id(),
4984 store.root_directory_object_id()
4985 )],
4986 Options::default(),
4987 )
4988 .await
4989 .expect("new transaction failed");
4990
4991 replace_child_with_object(
4992 &mut transaction,
4993 Some((oid, ObjectDescriptor::Directory)),
4994 (&root_directory, "foo"),
4995 0,
4996 false,
4997 Timestamp::now(),
4998 )
4999 .await
5000 .expect("replace_child_with_object failed");
5001
5002 yield_to_executor().await;
5006
5007 transaction.commit().await.expect("commit failed");
5008
5009 fs.close().await.expect("close failed");
5010 }
5011
5012 let device = fs.take_device().await;
5013 device.reopen(false);
5014 let fs = FxFilesystem::open(device).await.expect("open failed");
5015 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5016 let _store = root_volume
5017 .volume(
5018 "test",
5019 StoreOptions {
5020 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
5021 ..StoreOptions::default()
5022 },
5023 )
5024 .await
5025 .expect("new_volume failed");
5026
5027 yield_to_executor().await;
5029
5030 fs.close().await.expect("close failed");
5031 }
5032
5033 #[test_case(false; "non_casefold")]
5034 #[test_case(true; "casefold")]
5035 #[fuchsia::test]
5036 async fn test_lookup_long_filename_in_locked_directory(casefold: bool) {
5037 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5038 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5039 let object_id;
5040 let mut filenames = Vec::new();
5041 {
5042 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
5043 let root_volume = root_volume(fs.clone()).await.unwrap();
5044 let store = root_volume
5045 .new_volume(
5046 "vol",
5047 NewChildStoreOptions {
5048 options: StoreOptions {
5049 crypt: Some(crypt.clone()),
5050 ..StoreOptions::default()
5051 },
5052 ..Default::default()
5053 },
5054 )
5055 .await
5056 .unwrap();
5057
5058 crypt
5059 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
5060 .expect("add_wrapping_key failed");
5061
5062 object_id = {
5063 let mut transaction = fs
5064 .root_store()
5065 .new_transaction(lock_keys![], Options::default())
5066 .await
5067 .expect("new_transaction failed");
5068 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
5069 .await
5070 .expect("create failed");
5071
5072 transaction.commit().await.expect("commit");
5073 dir.object_id()
5074 };
5075 let dir = Directory::open(&store, object_id).await.expect("open failed");
5076 if casefold {
5077 dir.set_casefold(true).await.expect("set casefold");
5078 }
5079
5080 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
5081
5082 for len in [144, 145, 255] {
5083 let filename = "a".repeat(len);
5084 let encrypted_name =
5085 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
5086 let proxy_filename = if casefold {
5087 let hash_code = key.hash_code_casefold(&filename);
5088 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name)
5089 } else {
5090 ProxyFilename::new(&encrypted_name)
5091 };
5092 let mut transaction = fs
5093 .root_store()
5094 .new_transaction(
5095 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
5096 Options::default(),
5097 )
5098 .await
5099 .expect("new_transaction failed");
5100 let file = dir
5101 .create_child_file(&mut transaction, &filename)
5102 .await
5103 .expect("create_child_file failed");
5104 filenames.push((proxy_filename, file.object_id()));
5105 transaction.commit().await.expect("commit failed");
5106 }
5107
5108 fs.close().await.expect("Close failed");
5109 }
5110
5111 let device = fs.take_device().await;
5112 device.reopen(false);
5113 let fs = FxFilesystem::open(device).await.expect("open failed");
5114 {
5115 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
5116 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5117 let store = root_volume
5118 .volume(
5119 "vol",
5120 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5121 )
5122 .await
5123 .expect("volume failed");
5124 let dir = Directory::open(&store, object_id).await.expect("open failed");
5125
5126 let layer_set = dir.store().tree().layer_set();
5128 let mut merger = layer_set.merger();
5129 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
5130 let mut entries = Vec::new();
5131 while let Some((name, _, _)) = iter.get() {
5132 entries.push(name.to_string());
5133 iter.advance().await.expect("advance failed");
5134 }
5135 assert_eq!(entries.len(), filenames.len());
5136
5137 for (proxy_filename, object_id) in &filenames {
5138 let proxy_filename_str: String = (*proxy_filename).into();
5139 assert!(entries.contains(&proxy_filename_str));
5140 let item = dir
5141 .lookup(&proxy_filename_str)
5142 .await
5143 .expect("lookup failed")
5144 .expect("lookup is not None");
5145 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
5146 }
5147
5148 fs.close().await.expect("Close failed");
5149 }
5150 }
5151
5152 #[fuchsia::test]
5153 async fn test_lookup_cached_entry_after_unlock() {
5154 const FILENAME: &str = "foo";
5155 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5156 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5157 let object_id;
5158 let proxy_filename;
5159 {
5160 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
5161 let root_volume = root_volume(fs.clone()).await.unwrap();
5162 let store = root_volume
5163 .new_volume(
5164 "vol",
5165 NewChildStoreOptions {
5166 options: StoreOptions {
5167 crypt: Some(crypt.clone()),
5168 ..StoreOptions::default()
5169 },
5170 ..Default::default()
5171 },
5172 )
5173 .await
5174 .unwrap();
5175
5176 crypt
5177 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
5178 .expect("add_wrapping_key failed");
5179
5180 let mut transaction = fs
5181 .root_store()
5182 .new_transaction(lock_keys![], Options::default())
5183 .await
5184 .expect("new_transaction failed");
5185 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
5186 .await
5187 .expect("create failed");
5188 transaction.commit().await.expect("commit");
5189 object_id = dir.object_id();
5190
5191 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
5192 let encrypted_name =
5193 encrypt_filename(&*key, object_id, FILENAME).expect("encrypt_filename");
5194 proxy_filename = ProxyFilename::new(&encrypted_name);
5195
5196 let mut transaction = fs
5197 .root_store()
5198 .new_transaction(
5199 lock_keys![LockKey::object(store.store_object_id(), object_id),],
5200 Options::default(),
5201 )
5202 .await
5203 .expect("new_transaction failed");
5204 dir.create_child_file(&mut transaction, FILENAME)
5205 .await
5206 .expect("create_child_file failed");
5207 transaction.commit().await.expect("commit failed");
5208
5209 fs.close().await.expect("Close failed");
5210 }
5211
5212 let device = fs.take_device().await;
5213 device.reopen(false);
5214 let fs = FxFilesystem::open(device).await.expect("open failed");
5215 {
5216 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
5217 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5218 let store = root_volume
5219 .volume(
5220 "vol",
5221 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5222 )
5223 .await
5224 .expect("volume failed");
5225 let dir = Directory::open(&store, object_id).await.expect("open failed");
5226
5227 let proxy_filename_str: String = proxy_filename.into();
5228 dir.lookup(&proxy_filename_str)
5230 .await
5231 .expect("lookup failed")
5232 .expect("lookup is not None");
5233
5234 crypt
5235 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
5236 .expect("add_wrapping_key failed");
5237
5238 assert!(dir.lookup(&proxy_filename_str).await.expect("lookup failed").is_none());
5241
5242 fs.close().await.expect("Close failed");
5243 }
5244 }
5245
5246 #[test_case(false, false; "no_encryption_no_casefold")]
5247 #[test_case(false, true; "no_encryption_casefold")]
5248 #[test_case(true, false; "encryption_no_casefold")]
5249 #[test_case(true, true; "encryption_casefold")]
5250 #[fuchsia::test]
5251 async fn test_traversal_position(encrypted: bool, casefold: bool) {
5252 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5253 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5254 {
5255 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5256 let crypt = Arc::new(new_insecure_crypt());
5257 crypt
5258 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
5259 .expect("add_wrapping_key failed");
5260 let store = root_volume
5261 .new_volume(
5262 "test",
5263 NewChildStoreOptions {
5264 options: StoreOptions {
5265 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
5266 ..StoreOptions::default()
5267 },
5268 ..Default::default()
5269 },
5270 )
5271 .await
5272 .expect("new_volume failed");
5273 let mut root_dir = Directory::open(&store, store.root_directory_object_id())
5274 .await
5275 .expect("open failed");
5276 if encrypted {
5277 let mut transaction = fs
5278 .root_store()
5279 .new_transaction(
5280 lock_keys![LockKey::object(
5281 store.store_object_id(),
5282 store.root_directory_object_id()
5283 )],
5284 Options::default(),
5285 )
5286 .await
5287 .expect("new_transaction failed");
5288 root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await.unwrap();
5289 transaction.commit().await.unwrap();
5290
5291 root_dir = Directory::open(&store, store.root_directory_object_id())
5293 .await
5294 .expect("open failed");
5295 }
5296 if casefold {
5297 root_dir.set_casefold(true).await.unwrap();
5298 }
5299
5300 let mut transaction = fs
5301 .root_store()
5302 .new_transaction(
5303 lock_keys![LockKey::object(
5304 store.store_object_id(),
5305 store.root_directory_object_id()
5306 )],
5307 Options::default(),
5308 )
5309 .await
5310 .expect("new_transaction failed");
5311 let _ = root_dir.create_child_file(&mut transaction, "foo").await.unwrap();
5312 transaction.commit().await.unwrap();
5313
5314 let layer_set = store.tree().layer_set();
5315 let mut merger = layer_set.merger();
5316 let iter = root_dir.iter(&mut merger).await.expect("iter failed");
5317 let pos =
5318 iter.traversal_position(|name| name.to_string(), |bytes| format!("{:?}", bytes));
5319 assert!(
5320 pos.is_some(),
5321 "traversal_position returned None for encrypted={}, casefold={}",
5322 encrypted,
5323 casefold
5324 );
5325 }
5326 fs.close().await.expect("close failed");
5327 }
5328
5329 #[fuchsia::test]
5332 async fn test_casefold_same_dir_rename() -> Result<(), Error> {
5333 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5334 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5335
5336 let root_volume = root_volume(fs.clone()).await.unwrap();
5337 let store = root_volume.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
5338
5339 let dir = {
5340 let mut transaction = fs
5341 .root_store()
5342 .new_transaction(lock_keys![], Options::default())
5343 .await
5344 .expect("new_transaction failed");
5345 let dir =
5346 Directory::create(&mut transaction, &store, None).await.expect("create failed");
5347 transaction.commit().await.expect("commit");
5348 dir
5349 };
5350
5351 dir.set_casefold(true).await.expect("set casefold");
5353
5354 let file_id = {
5356 let mut transaction = fs
5357 .root_store()
5358 .new_transaction(
5359 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
5360 Options::default(),
5361 )
5362 .await
5363 .expect("new_transaction failed");
5364 let file =
5365 dir.create_child_file(&mut transaction, "FOO").await.expect("create file failed");
5366 transaction.commit().await.expect("commit failed");
5367 file.object_id()
5368 };
5369
5370 let (lookup_id_foo, _, _) = dir.lookup("foo").await.unwrap().unwrap();
5372 assert_eq!(lookup_id_foo, file_id);
5373 let (lookup_id_foo_upper, _, _) = dir.lookup("FOO").await.unwrap().unwrap();
5374 assert_eq!(lookup_id_foo_upper, file_id);
5375
5376 {
5378 let mut transaction = fs
5379 .root_store()
5380 .new_transaction(
5381 lock_keys![
5382 LockKey::object(store.store_object_id(), dir.object_id()),
5383 LockKey::object(store.store_object_id(), file_id),
5384 ],
5385 Options::default(),
5386 )
5387 .await
5388 .expect("new_transaction failed");
5389
5390 replace_child(&mut transaction, Some((&dir, "FOO")), (&dir, "foo"))
5391 .await
5392 .expect("same-dir casefold rename failed");
5393
5394 transaction.commit().await.expect("commit failed");
5395 }
5396
5397 let (final_id_foo, _, _) = dir.lookup("foo").await.unwrap().unwrap();
5399 assert_eq!(final_id_foo, file_id);
5400
5401 let file_handle =
5403 ObjectStore::open_object(&dir.owner(), file_id, HandleOptions::default(), None)
5404 .await
5405 .expect("Underlying file object was prematurely tombstoned / graveyarded!");
5406
5407 let properties = file_handle.get_properties().await.unwrap();
5409 assert_eq!(properties.refs, 1);
5410
5411 assert_eq!(dir.store().graveyard_count(), 0);
5413
5414 let mut count = 0;
5416 let mut found_casing = String::new();
5417 let layer_set = dir.store().tree().layer_set();
5418 let mut merger = layer_set.merger();
5419 let mut iter = dir.iter(&mut merger).await.expect("iter");
5420 while let Some(entry) = iter.get() {
5421 count += 1;
5422 found_casing = entry.0.to_string();
5423 iter.advance().await.expect("advance");
5424 }
5425 assert_eq!(count, 1);
5426 assert_eq!(found_casing, "foo"); fs.close().await.expect("Close failed");
5429 Ok(())
5430 }
5431
5432 #[fuchsia::test]
5433 async fn test_casefold_rename_mismatched_casing() -> Result<(), Error> {
5434 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5435 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5436
5437 let root_volume = root_volume(fs.clone()).await.unwrap();
5438 let store = root_volume.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
5439
5440 let dir = {
5441 let mut transaction = fs
5442 .root_store()
5443 .new_transaction(lock_keys![], Options::default())
5444 .await
5445 .expect("new_transaction failed");
5446 let dir =
5447 Directory::create(&mut transaction, &store, None).await.expect("create failed");
5448 transaction.commit().await.expect("commit");
5449 dir
5450 };
5451
5452 dir.set_casefold(true).await.expect("set casefold");
5453
5454 let file_id = {
5456 let mut transaction = fs
5457 .root_store()
5458 .new_transaction(
5459 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
5460 Options::default(),
5461 )
5462 .await
5463 .expect("new_transaction failed");
5464 let file =
5465 dir.create_child_file(&mut transaction, "foo").await.expect("create file failed");
5466 transaction.commit().await.expect("commit failed");
5467 file.object_id()
5468 };
5469
5470 {
5472 let mut transaction = fs
5473 .root_store()
5474 .new_transaction(
5475 lock_keys![
5476 LockKey::object(store.store_object_id(), dir.object_id()),
5477 LockKey::object(store.store_object_id(), file_id),
5478 ],
5479 Options::default(),
5480 )
5481 .await
5482 .expect("new_transaction failed");
5483
5484 replace_child(&mut transaction, Some((&dir, "FOO")), (&dir, "bar"))
5485 .await
5486 .expect("rename failed");
5487
5488 transaction.commit().await.expect("commit failed");
5489 }
5490
5491 let lookup_foo = dir.lookup("foo").await.unwrap();
5493 assert!(
5494 lookup_foo.is_none(),
5495 "Old name 'foo' still exists! Lookup returned: {:?}",
5496 lookup_foo
5497 );
5498
5499 let (lookup_id_bar, _, _) = dir.lookup("bar").await.unwrap().expect("bar not found");
5501 assert_eq!(lookup_id_bar, file_id);
5502
5503 fs.close().await.expect("Close failed");
5504 Ok(())
5505 }
5506
5507 #[fuchsia::test]
5508 async fn test_hard_link_encrypted_symlink_and_fsck_passes() {
5509 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
5510 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5511 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
5512 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
5513
5514 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
5515 let store = root_volume
5516 .new_volume(
5517 "vol",
5518 NewChildStoreOptions {
5519 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
5520 ..Default::default()
5521 },
5522 )
5523 .await
5524 .expect("new_volume failed");
5525
5526 let root_directory =
5527 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5528
5529 let mut transaction = filesystem
5530 .root_store()
5531 .new_transaction(
5532 lock_keys![LockKey::object(
5533 store.store_object_id(),
5534 store.root_directory_object_id()
5535 )],
5536 Options::default(),
5537 )
5538 .await
5539 .expect("new transaction failed");
5540 root_directory.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await.unwrap();
5541 transaction.commit().await.unwrap();
5542
5543 let root_directory =
5544 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5545
5546 let mut transaction = filesystem
5547 .root_store()
5548 .new_transaction(
5549 lock_keys![LockKey::object(
5550 store.store_object_id(),
5551 store.root_directory_object_id()
5552 )],
5553 Options::default(),
5554 )
5555 .await
5556 .expect("new transaction failed");
5557 let symlink_id = root_directory
5558 .create_symlink(&mut transaction, b"target_path", "symlink")
5559 .await
5560 .expect("create_symlink failed");
5561 transaction.commit().await.expect("commit failed");
5562
5563 fsck(filesystem.clone()).await.expect("fsck failed");
5564 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
5565 .await
5566 .expect("fsck_volume failed");
5567
5568 let mut transaction = filesystem
5569 .root_store()
5570 .new_transaction(
5571 lock_keys![
5572 LockKey::object(store.store_object_id(), root_directory.object_id()),
5573 LockKey::object(store.store_object_id(), symlink_id)
5574 ],
5575 Options::default(),
5576 )
5577 .await
5578 .expect("new transaction failed");
5579 root_directory
5580 .insert_child(&mut transaction, "symlink_link", symlink_id, ObjectDescriptor::Symlink)
5581 .await
5582 .expect("insert_child failed");
5583 store.adjust_refs(&mut transaction, symlink_id, 1).await.expect("adjust_refs failed");
5584 transaction.commit().await.expect("commit failed");
5585
5586 fsck(filesystem.clone()).await.expect("fsck failed");
5587 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
5588 .await
5589 .expect("fsck_volume failed");
5590
5591 let mut transaction = filesystem
5592 .root_store()
5593 .new_transaction(
5594 lock_keys![
5595 LockKey::object(store.store_object_id(), root_directory.object_id()),
5596 LockKey::object(store.store_object_id(), symlink_id)
5597 ],
5598 Options::default(),
5599 )
5600 .await
5601 .expect("new transaction failed");
5602 replace_child(&mut transaction, None, (&root_directory, "symlink"))
5603 .await
5604 .expect("replace_child failed");
5605 transaction.commit().await.expect("commit failed");
5606
5607 fsck(filesystem.clone()).await.expect("fsck failed");
5608 fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
5609 .await
5610 .expect("fsck_volume failed");
5611
5612 filesystem.close().await.expect("close failed");
5613 }
5614
5615 #[test_case(false, false; "unencrypted_store")]
5616 #[test_case(true, false; "encrypted_store_normal_dir")]
5617 #[test_case(true, true; "encrypted_store_fscrypt_dir")]
5618 #[fuchsia::test]
5619 async fn test_large_symlinks(encrypted_store: bool, fscrypt_dir: bool) {
5620 let device = DeviceHolder::new(FakeDevice::new(16384, TEST_DEVICE_BLOCK_SIZE));
5621 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5622 let crypt: Option<Arc<CryptBase>> = if encrypted_store {
5623 let crypt = Arc::new(new_insecure_crypt());
5624 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key");
5625 Some(crypt)
5626 } else {
5627 None
5628 };
5629
5630 let root_vol = root_volume(fs.clone()).await.expect("root_volume failed");
5631 let store = root_vol
5632 .new_volume(
5633 "vol",
5634 NewChildStoreOptions {
5635 options: StoreOptions {
5636 crypt: crypt.clone().map(|c| c as Arc<dyn Crypt>),
5637 ..StoreOptions::default()
5638 },
5639 ..Default::default()
5640 },
5641 )
5642 .await
5643 .expect("new_volume failed");
5644
5645 if fscrypt_dir {
5646 let root_dir = Directory::open(&store, store.root_directory_object_id())
5647 .await
5648 .expect("open failed");
5649 let mut transaction = fs
5650 .root_store()
5651 .new_transaction(
5652 lock_keys![LockKey::object(
5653 store.store_object_id(),
5654 store.root_directory_object_id()
5655 )],
5656 Options::default(),
5657 )
5658 .await
5659 .expect("new_transaction failed");
5660 root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await.unwrap();
5661 transaction.commit().await.unwrap();
5662 }
5663
5664 let root_dir =
5665 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
5666
5667 {
5669 let target = vec![b'a'; MAX_SYMLINK_LEN + 1];
5670 let mut transaction = fs
5671 .root_store()
5672 .new_transaction(
5673 lock_keys![LockKey::object(
5674 store.store_object_id(),
5675 store.root_directory_object_id()
5676 )],
5677 Options::default(),
5678 )
5679 .await
5680 .expect("new_transaction failed");
5681 let err = root_dir
5682 .create_symlink(&mut transaction, &target, "bad_symlink")
5683 .await
5684 .expect_err("create_symlink should fail");
5685 assert_eq!(err.downcast::<FxfsError>().expect("wrong error"), FxfsError::BadPath);
5686 }
5687
5688 let inline_target = vec![b'x'; MAX_INLINE_SYMLINK_SIZE];
5689 let spilled_min_target = vec![b'y'; MAX_INLINE_SYMLINK_SIZE + 1];
5690 let spilled_max_target = vec![b'z'; MAX_SYMLINK_LEN];
5691
5692 let mut created = Vec::new();
5693 for (name, target) in [
5694 ("inline_256", &inline_target),
5695 ("spilled_257", &spilled_min_target),
5696 ("spilled_4093", &spilled_max_target),
5697 ] {
5698 let mut transaction = fs
5699 .root_store()
5700 .new_transaction(
5701 lock_keys![LockKey::object(
5702 store.store_object_id(),
5703 store.root_directory_object_id()
5704 )],
5705 Options::default(),
5706 )
5707 .await
5708 .expect("new_transaction failed");
5709 let id = root_dir
5710 .create_symlink(&mut transaction, target, name)
5711 .await
5712 .expect("create_symlink failed");
5713 transaction.commit().await.expect("commit failed");
5714 created.push((name, id, target.clone()));
5715 }
5716
5717 for (name, id, expected_target) in &created {
5718 let actual = store.read_symlink(*id).await.expect("read_symlink failed");
5719 assert_eq!(&actual, expected_target, "mismatch for {name}");
5720
5721 let value = store
5722 .tree()
5723 .find_value(&ObjectKey::object(*id))
5724 .await
5725 .expect("find_value failed")
5726 .expect("missing object");
5727 match value {
5728 ObjectValue::Object {
5729 kind: ObjectKind::Symlink { .. } | ObjectKind::EncryptedSymlink { .. },
5730 attributes,
5731 } => {
5732 assert!(expected_target.len() <= MAX_INLINE_SYMLINK_SIZE);
5733 assert_eq!(attributes.allocated_size, 0);
5734 }
5735 ObjectValue::Object { kind: ObjectKind::NonInlineSymlink { .. }, attributes } => {
5736 assert!(expected_target.len() > MAX_INLINE_SYMLINK_SIZE);
5737 assert_eq!(attributes.allocated_size, fs.block_size());
5738 }
5739 _ => panic!("unexpected object value: {value:?}"),
5740 }
5741 }
5742
5743 fsck(fs.clone()).await.expect("fsck failed");
5744 fsck_volume(
5745 fs.as_ref(),
5746 store.store_object_id(),
5747 crypt.clone().map(|c| c as Arc<dyn Crypt>),
5748 )
5749 .await
5750 .expect("fsck_volume failed");
5751
5752 let (_, spilled_257_id, _) = created[1];
5754 let alloc_before = fs.allocator().get_allocated_bytes();
5755 let mut transaction = fs
5756 .root_store()
5757 .new_transaction(
5758 lock_keys![
5759 LockKey::object(store.store_object_id(), root_dir.object_id()),
5760 LockKey::object(store.store_object_id(), spilled_257_id),
5761 ],
5762 Options::default(),
5763 )
5764 .await
5765 .expect("new_transaction failed");
5766 assert_matches!(
5767 replace_child_with_purge(&mut transaction, None, (&root_dir, "spilled_257"), true)
5768 .await
5769 .expect("replace_child_with_purge failed"),
5770 ReplacedChild::Purged(id) if id == spilled_257_id
5771 );
5772 transaction.commit().await.expect("commit failed");
5773 assert_eq!(fs.allocator().get_allocated_bytes(), alloc_before - fs.block_size());
5774
5775 fsck(fs.clone()).await.expect("fsck failed");
5776 fsck_volume(
5777 fs.as_ref(),
5778 store.store_object_id(),
5779 crypt.clone().map(|c| c as Arc<dyn Crypt>),
5780 )
5781 .await
5782 .expect("fsck_volume failed");
5783
5784 drop(root_dir);
5785 drop(store);
5786 drop(root_vol);
5787 fs.close().await.expect("close failed");
5788
5789 if fscrypt_dir {
5790 let device = fs.take_device().await;
5791 device.reopen(false);
5792 let fs = FxFilesystem::open(device).await.expect("open failed");
5793 let locked_crypt = Arc::new(new_insecure_crypt());
5794 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
5795 let store = root_volume
5796 .volume(
5797 "vol",
5798 StoreOptions {
5799 crypt: Some(locked_crypt.clone() as Arc<dyn Crypt>),
5800 ..StoreOptions::default()
5801 },
5802 )
5803 .await
5804 .expect("volume failed");
5805
5806 let (_, spilled_4093_id, expected_4093) = &created[2];
5807 let handle = StoreObjectHandle::new(
5808 store.clone(),
5809 *spilled_4093_id,
5810 false,
5811 HandleOptions::default(),
5812 false,
5813 );
5814 let layer_set = store.tree().layer_set();
5815 let mut merger = layer_set.merger();
5816 let iter = merger
5817 .query(Query::FullRange(&ObjectKey::attribute(
5818 *spilled_4093_id,
5819 AttributeId::DATA,
5820 AttributeKey::Attribute,
5821 )))
5822 .await
5823 .expect("query failed");
5824 let raw_encrypted =
5825 handle.read_raw_attr_from_iter(iter).await.expect("read_raw_attr_from_iter failed");
5826 let expected_proxy: String =
5827 ProxyFilename::new_with_hash_code(0, &raw_encrypted).into();
5828 let locked_target =
5829 store.read_symlink(*spilled_4093_id).await.expect("read_symlink locked failed");
5830 assert_eq!(locked_target, expected_proxy.as_bytes());
5831
5832 locked_crypt
5834 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
5835 .expect("add_wrapping_key");
5836 let unlocked_target =
5837 store.read_symlink(*spilled_4093_id).await.expect("read_symlink unlocked failed");
5838 assert_eq!(&unlocked_target, expected_4093);
5839
5840 fs.close().await.expect("close failed");
5841 }
5842 }
5843}