1use crate::errors::FxfsError;
5use crate::lsm_tree::Query;
6use crate::lsm_tree::merge::{Merger, MergerIterator};
7use crate::lsm_tree::types::{Item, ItemRef, LayerIterator};
8use crate::object_handle::{INVALID_OBJECT_ID, ObjectHandle, ObjectProperties};
9use crate::object_store::object_record::{
10 ChildValue, DirType, EncryptedCasefoldChild, EncryptedChild, ObjectAttributes,
11 ObjectDescriptor, ObjectItem, ObjectKey, ObjectKeyData, ObjectKind, ObjectValue, Timestamp,
12};
13use crate::object_store::transaction::{
14 LockKey, LockKeys, Mutation, Options, Transaction, lock_keys,
15};
16use crate::object_store::{
17 DataObjectHandle, HandleOptions, HandleOwner, ObjectStore, SetExtendedAttributeMode,
18 StoreObjectHandle,
19};
20use anyhow::{Error, anyhow, bail, ensure};
21use fidl_fuchsia_io as fio;
22use fscrypt::proxy_filename::ProxyFilename;
23use fuchsia_sync::Mutex;
24use fxfs_crypto::{Cipher, CipherHolder, ObjectType, WrappingKeyId, key_to_cipher};
25use std::fmt;
26use std::ops::ControlFlow;
27use std::sync::Arc;
28use std::sync::atomic::{AtomicBool, Ordering};
29use zerocopy::IntoBytes;
30
31use super::FSCRYPT_KEY_ID;
32
33type BoxPredicate<'a> = Box<dyn Fn(&ObjectKey) -> ControlFlow<bool> + Send + 'a>;
34
35pub struct ReplaceContext<'a> {
38 pub transaction: Transaction<'a>,
39 pub src_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
40 pub dst_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
41}
42
43pub struct Directory<S: HandleOwner> {
45 handle: StoreObjectHandle<S>,
46 is_deleted: AtomicBool,
48 dir_type: Mutex<DirType>,
50}
51
52#[derive(Clone, Default)]
53pub struct MutableAttributesInternal {
54 sub_dirs: i64,
55 change_time: Option<Timestamp>,
56 modification_time: Option<u64>,
57 creation_time: Option<u64>,
58}
59
60impl MutableAttributesInternal {
61 pub fn new(
62 sub_dirs: i64,
63 change_time: Option<Timestamp>,
64 modification_time: Option<u64>,
65 creation_time: Option<u64>,
66 ) -> Self {
67 Self { sub_dirs, change_time, modification_time, creation_time }
68 }
69}
70
71pub(crate) fn encrypt_filename(
73 key: &dyn Cipher,
74 object_id: u64,
75 name: &str,
76) -> Result<Vec<u8>, Error> {
77 let mut name_bytes = name.to_string().into_bytes();
78 key.encrypt_filename(object_id, &mut name_bytes)?;
79 Ok(name_bytes)
80}
81
82pub(crate) fn decrypt_filename(
84 key: &dyn Cipher,
85 object_id: u64,
86 data: &Vec<u8>,
87) -> Result<String, Error> {
88 let mut raw = data.clone();
89 key.decrypt_filename(object_id, &mut raw)?;
90 Ok(String::from_utf8(raw)?)
91}
92
93#[fxfs_trace::trace]
94impl<S: HandleOwner> Directory<S> {
95 fn new(owner: Arc<S>, object_id: u64, dir_type: DirType) -> Self {
96 Directory {
97 handle: StoreObjectHandle::new(
98 owner,
99 object_id,
100 false,
101 HandleOptions::default(),
102 false,
103 ),
104 is_deleted: AtomicBool::new(false),
105 dir_type: Mutex::new(dir_type),
106 }
107 }
108
109 pub fn object_id(&self) -> u64 {
110 self.handle.object_id()
111 }
112
113 pub fn wrapping_key_id(&self) -> Option<WrappingKeyId> {
114 self.dir_type.lock().wrapping_key_id()
115 }
116
117 pub async fn get_fscrypt_key(&self) -> Result<CipherHolder, Error> {
121 let object_id = self.object_id();
122 let store = self.store();
123 store
124 .key_manager()
125 .get_fscrypt_key(object_id, store.crypt().unwrap().as_ref(), async || {
126 store.get_keys(object_id).await
127 })
128 .await
129 }
130
131 pub fn owner(&self) -> &Arc<S> {
132 self.handle.owner()
133 }
134
135 pub fn store(&self) -> &ObjectStore {
136 self.handle.store()
137 }
138
139 pub fn handle(&self) -> &StoreObjectHandle<S> {
140 &self.handle
141 }
142
143 pub fn is_deleted(&self) -> bool {
144 self.is_deleted.load(Ordering::Relaxed)
145 }
146
147 pub fn set_deleted(&self) {
148 self.is_deleted.store(true, Ordering::Relaxed);
149 }
150
151 pub fn dir_type(&self) -> DirType {
153 *self.dir_type.lock()
154 }
155
156 pub async fn set_casefold(&self, val: bool) -> Result<(), Error> {
158 let dir_type = self.dir_type().with_casefold(val);
159 let fs = self.store().filesystem();
160 let mut transaction = fs
162 .new_transaction(
163 lock_keys![LockKey::object(self.store().store_object_id(), self.object_id())],
164 Options::default(),
165 )
166 .await?;
167 ensure!(!self.has_children().await?, FxfsError::InvalidArgs);
168 let mut mutation =
169 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
170 if let ObjectValue::Object {
171 kind: ObjectKind::Directory { dir_type: dest_dir_type, .. },
172 ..
173 } = &mut mutation.item.value
174 {
175 *dest_dir_type = dir_type;
176 } else {
177 return Err(
178 anyhow!(FxfsError::Inconsistent).context("casefold only applies to directories")
179 );
180 }
181 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
182 transaction.commit_with_callback(|_| *self.dir_type.lock() = dir_type).await?;
183 Ok(())
184 }
185
186 pub async fn create(
187 transaction: &mut Transaction<'_>,
188 owner: &Arc<S>,
189 wrapping_key_id: Option<WrappingKeyId>,
190 ) -> Result<Directory<S>, Error> {
191 let dir_type = match wrapping_key_id {
192 Some(id) => DirType::Encrypted(id),
193 None => DirType::Normal,
194 };
195 Self::create_with_options(transaction, owner, dir_type).await
196 }
197
198 pub async fn create_with_options(
199 transaction: &mut Transaction<'_>,
200 owner: &Arc<S>,
201 dir_type: DirType,
202 ) -> Result<Directory<S>, Error> {
203 let store = owner.as_ref().as_ref();
204 let object_id = store.get_next_object_id(transaction.txn_guard()).await?;
205 let now = Timestamp::now();
206
207 let object_id = object_id.release();
209 transaction.add(
210 store.store_object_id(),
211 Mutation::insert_object(
212 ObjectKey::object(object_id),
213 ObjectValue::Object {
214 kind: ObjectKind::Directory { sub_dirs: 0, dir_type },
215 attributes: ObjectAttributes {
216 creation_time: now.clone(),
217 modification_time: now.clone(),
218 project_id: 0,
219 posix_attributes: None,
220 allocated_size: 0,
221 access_time: now.clone(),
222 change_time: now,
223 },
224 },
225 ),
226 );
227 if let Some(wrapping_key_id) = dir_type.wrapping_key_id() {
228 if let Some(crypt) = store.crypt() {
229 let (key, unwrapped_key) = crypt
230 .create_key_with_id(object_id, wrapping_key_id, ObjectType::Directory)
231 .await?;
232 let cipher = key_to_cipher(&key, &unwrapped_key)?;
233 transaction.add(
234 store.store_object_id(),
235 Mutation::insert_object(
236 ObjectKey::keys(object_id),
237 ObjectValue::keys(vec![(FSCRYPT_KEY_ID, key)].into()),
238 ),
239 );
240 store.key_manager.insert(
245 object_id,
246 Arc::new(vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher))].into()),
247 false,
248 );
249 } else {
250 return Err(anyhow!("No crypt"));
251 }
252 }
253 Ok(Directory::new(owner.clone(), object_id, dir_type))
254 }
255
256 pub async fn set_wrapping_key(
264 &self,
265 transaction: &mut Transaction<'_>,
266 id: WrappingKeyId,
267 ) -> Result<Arc<dyn Cipher>, Error> {
268 let object_id = self.object_id();
269 let store = self.store();
270 if let Some(crypt) = store.crypt() {
271 let (key, unwrapped_key) =
272 crypt.create_key_with_id(object_id, id, ObjectType::Directory).await?;
273 let mut mutation = store.txn_get_object_mutation(transaction, object_id).await?;
274 if let ObjectValue::Object { kind: ObjectKind::Directory { dir_type, .. }, .. } =
275 &mut mutation.item.value
276 {
277 if dir_type.is_encrypted() {
278 return Err(anyhow!("wrapping key id is already set"));
279 }
280 if self.has_children().await? {
281 return Err(FxfsError::NotEmpty.into());
282 }
283 *dir_type = dir_type.with_encryption(id);
284 } else {
285 match mutation.item.value {
286 ObjectValue::None => bail!(FxfsError::NotFound),
287 _ => bail!(FxfsError::NotDir),
288 }
289 }
290 transaction.add(store.store_object_id(), Mutation::ObjectStore(mutation));
291
292 let keys_key = ObjectKey::keys(object_id);
293 let item = if let Some(mutation) =
294 transaction.get_object_mutation(store.store_object_id(), keys_key.clone())
295 {
296 Some(mutation.item.clone())
297 } else {
298 store.tree.find(&keys_key).await?
299 };
300
301 let cipher = key_to_cipher(&key, &unwrapped_key)?;
302 match item {
303 None | Some(Item { value: ObjectValue::None, .. }) => {
304 transaction.add(
305 store.store_object_id(),
306 Mutation::insert_object(
307 ObjectKey::keys(object_id),
308 ObjectValue::keys(vec![(FSCRYPT_KEY_ID, key)].into()),
309 ),
310 );
311 }
312 Some(Item { value: ObjectValue::Keys(mut keys), .. }) => {
313 keys.insert(FSCRYPT_KEY_ID, key.into());
314 transaction.add(
315 store.store_object_id(),
316 Mutation::replace_or_insert_object(
317 ObjectKey::keys(object_id),
318 ObjectValue::keys(keys),
319 ),
320 );
321 }
322 Some(item) => bail!("Unexpected item in lookup: {item:?}"),
323 }
324 Ok(cipher)
325 } else {
326 Err(anyhow!("No crypt"))
327 }
328 }
329
330 #[trace]
331 pub async fn open(owner: &Arc<S>, object_id: u64) -> Result<Directory<S>, Error> {
332 let store = owner.as_ref().as_ref();
333 match store.tree.find(&ObjectKey::object(object_id)).await?.ok_or(FxfsError::NotFound)? {
334 ObjectItem {
335 value: ObjectValue::Object { kind: ObjectKind::Directory { dir_type, .. }, .. },
336 ..
337 } => Ok(Directory::new(owner.clone(), object_id, dir_type)),
338 _ => bail!(FxfsError::NotDir),
339 }
340 }
341
342 pub fn open_unchecked(owner: Arc<S>, object_id: u64, dir_type: DirType) -> Self {
345 Self::new(owner, object_id, dir_type)
346 }
347
348 pub async fn acquire_context_for_replace(
361 &self,
362 src: Option<(&Directory<S>, &str)>,
363 dst: &str,
364 borrow_metadata_space: bool,
365 ) -> Result<ReplaceContext<'_>, Error> {
366 let store = self.store();
377 let mut child_object_id = INVALID_OBJECT_ID;
378 let mut src_object_id = src.map(|_| INVALID_OBJECT_ID);
379 let mut lock_keys = LockKeys::with_capacity(4);
380 lock_keys.push(LockKey::object(store.store_object_id(), self.object_id()));
381 loop {
382 lock_keys.truncate(1);
383 if let Some(src) = src {
384 lock_keys.push(LockKey::object(store.store_object_id(), src.0.object_id()));
385 if let Some(src_object_id) = src_object_id {
386 if src_object_id != INVALID_OBJECT_ID {
387 lock_keys.push(LockKey::object(store.store_object_id(), src_object_id));
388 }
389 }
390 }
391 if child_object_id != INVALID_OBJECT_ID {
392 lock_keys.push(LockKey::object(store.store_object_id(), child_object_id));
393 };
394 let fs = store.filesystem().clone();
395 let transaction = fs
396 .new_transaction(
397 lock_keys.clone(),
398 Options { borrow_metadata_space, ..Default::default() },
399 )
400 .await?;
401
402 let mut have_required_locks = true;
403 let mut src_id_and_descriptor = None;
404 if let Some((src_dir, src_name)) = src {
405 match src_dir.lookup(src_name).await? {
406 Some((object_id, object_descriptor, _)) => match object_descriptor {
407 ObjectDescriptor::File
408 | ObjectDescriptor::Directory
409 | ObjectDescriptor::Symlink => {
410 if src_object_id != Some(object_id) {
411 have_required_locks = false;
412 src_object_id = Some(object_id);
413 }
414 src_id_and_descriptor = Some((object_id, object_descriptor));
415 }
416 _ => bail!(FxfsError::Inconsistent),
417 },
418 None => {
419 bail!(FxfsError::NotFound)
421 }
422 }
423 };
424 let dst_id_and_descriptor = match self.lookup(dst).await? {
425 Some((object_id, object_descriptor, _)) => match object_descriptor {
426 ObjectDescriptor::File
427 | ObjectDescriptor::Directory
428 | ObjectDescriptor::Symlink => {
429 if child_object_id != object_id {
430 have_required_locks = false;
431 child_object_id = object_id
432 }
433 Some((object_id, object_descriptor))
434 }
435 _ => bail!(FxfsError::Inconsistent),
436 },
437 None => {
438 if child_object_id != INVALID_OBJECT_ID {
439 have_required_locks = false;
440 child_object_id = INVALID_OBJECT_ID;
441 }
442 None
443 }
444 };
445 if have_required_locks {
446 return Ok(ReplaceContext {
447 transaction,
448 src_id_and_descriptor,
449 dst_id_and_descriptor,
450 });
451 }
452 }
453 }
454
455 async fn has_children(&self) -> Result<bool, Error> {
456 if self.is_deleted() {
457 return Ok(false);
458 }
459 let layer_set = self.store().tree().layer_set();
460 let mut merger = layer_set.merger();
461 Ok(self.iter(&mut merger).await?.get().is_some())
462 }
463
464 #[trace]
468 pub async fn lookup(&self, name: &str) -> Result<Option<(u64, ObjectDescriptor, bool)>, Error> {
469 let _measure =
470 crate::metrics::DurationMeasureScope::new(&crate::metrics::directory_metrics().lookup);
471 if self.is_deleted() {
472 return Ok(None);
473 }
474 let cipher;
475 let proxy_name;
476 let (key, predicate, locked): (_, Option<BoxPredicate<'_>>, _) = if self
480 .dir_type()
481 .is_encrypted()
482 {
483 cipher = self.get_fscrypt_key().await?;
484 match &cipher {
485 CipherHolder::Cipher(cipher) => {
486 if self.dir_type().is_casefold() {
487 let target_hash_code = cipher.hash_code_casefold(name);
490 let key = ObjectKey::encrypted_child(
491 self.object_id(),
492 vec![],
493 Some(target_hash_code),
494 );
495 (
496 key,
497 Some(Box::new(encrypted_casefold_predicate(
498 cipher.as_ref(),
499 self.object_id(),
500 target_hash_code,
501 name,
502 ))),
503 false,
504 )
505 } else {
506 let encrypted_name =
507 encrypt_filename(cipher.as_ref(), self.object_id(), name)?;
508 let hash_code = cipher.hash_code(encrypted_name.as_bytes(), name);
509 (
510 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
511 None,
512 false,
513 )
514 }
515 }
516 CipherHolder::Unavailable => {
517 proxy_name = match ProxyFilename::try_from(name) {
518 Ok(name) => name,
519 Err(_) => return Ok(None),
520 };
521 let (key, predicate) =
522 self.get_key_and_predicate_for_unavailable_cipher(&proxy_name);
523 (key, predicate, true)
524 }
525 }
526 } else {
527 match self.dir_type() {
528 DirType::Casefold => {
529 let target_key = ObjectKey::child(self.object_id(), name, DirType::Casefold);
530 let target_hash_code = match &target_key.data {
531 ObjectKeyData::CasefoldChild { hash_code, .. } => *hash_code,
532 _ => unreachable!(),
533 };
534 (
535 ObjectKey {
536 object_id: self.object_id(),
537 data: ObjectKeyData::CasefoldChild {
538 hash_code: target_hash_code,
539 name: "".to_string(),
540 },
541 },
542 Some(Box::new(casefold_predicate(
543 self.object_id(),
544 target_hash_code,
545 name,
546 ))),
547 false,
548 )
549 }
550 DirType::LegacyCasefold | DirType::Normal => {
551 (ObjectKey::child(self.object_id(), name, self.dir_type()), None, false)
552 }
553 DirType::Encrypted(_) | DirType::EncryptedCasefold(_) => {
554 unreachable!("is_encrypted() was already checked")
555 }
556 }
557 };
558
559 if locked || predicate.is_some() {
563 let layer_set = self.store().tree().layer_set();
564 let mut merger = layer_set.merger();
565 let mut iter = merger.query(Query::FullRange(&key)).await?;
566 if let Some(predicate) = predicate {
567 if !self.advance_until(&mut iter, predicate).await? {
568 return Ok(None);
569 }
570 } else if iter
571 .get()
572 .is_none_or(|item| item.key != &key || matches!(item.value, ObjectValue::None))
573 {
574 return Ok(None);
575 }
576 let item = iter.get().unwrap();
577 match item.value {
578 ObjectValue::Child(ChildValue { object_id, object_descriptor }) => {
579 Ok(Some((*object_id, object_descriptor.clone(), locked)))
580 }
581 _ => Err(anyhow!(FxfsError::Inconsistent)
582 .context(format!("Unexpected item in lookup: {item:?}"))),
583 }
584 } else {
585 let item = self.store().tree().find(&key).await?;
586 match item {
587 None => Ok(None),
588 Some(ObjectItem {
589 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
590 ..
591 }) => Ok(Some((object_id, object_descriptor, false))),
592 _ => Err(anyhow!(FxfsError::Inconsistent)
593 .context(format!("Unexpected item in lookup: {item:?}",))),
594 }
595 }
596 }
597
598 pub async fn create_child_dir(
599 &self,
600 transaction: &mut Transaction<'_>,
601 name: &str,
602 ) -> Result<Directory<S>, Error> {
603 ensure!(!self.is_deleted(), FxfsError::Deleted);
604
605 let handle =
606 Directory::create_with_options(transaction, self.owner(), self.dir_type()).await?;
607 if self.dir_type().is_encrypted() {
608 let fscrypt_key =
609 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
610 let encrypted_name =
611 encrypt_filename(&*fscrypt_key, self.object_id(), name).expect("encrypt_filename");
612 let hash_code = if self.dir_type().is_casefold() {
613 Some(fscrypt_key.hash_code_casefold(name))
614 } else {
615 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
616 };
617 transaction.add(
618 self.store().store_object_id(),
619 Mutation::replace_or_insert_object(
620 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
621 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
622 ),
623 );
624 } else {
625 transaction.add(
626 self.store().store_object_id(),
627 Mutation::replace_or_insert_object(
628 ObjectKey::child(self.object_id(), &name, self.dir_type()),
629 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
630 ),
631 );
632 }
633 let now = Timestamp::now();
634 self.update_dir_attributes_internal(
635 transaction,
636 self.object_id(),
637 MutableAttributesInternal {
638 sub_dirs: 1,
639 modification_time: Some(now.as_nanos()),
640 change_time: Some(now),
641 ..Default::default()
642 },
643 )
644 .await?;
645 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
646 Ok(handle)
647 }
648
649 pub async fn add_child_file<'a>(
650 &self,
651 transaction: &mut Transaction<'a>,
652 name: &str,
653 handle: &DataObjectHandle<S>,
654 ) -> Result<(), Error> {
655 ensure!(!self.is_deleted(), FxfsError::Deleted);
656 if self.dir_type().is_encrypted() {
657 let fscrypt_key =
658 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
659 let encrypted_name =
660 encrypt_filename(&*fscrypt_key, self.object_id(), name).expect("encrypt_filename");
661 let hash_code = if self.dir_type().is_casefold() {
662 Some(fscrypt_key.hash_code_casefold(name))
663 } else {
664 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
665 };
666 transaction.add(
667 self.store().store_object_id(),
668 Mutation::replace_or_insert_object(
669 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
670 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
671 ),
672 );
673 } else {
674 transaction.add(
675 self.store().store_object_id(),
676 Mutation::replace_or_insert_object(
677 ObjectKey::child(self.object_id(), &name, self.dir_type()),
678 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
679 ),
680 );
681 }
682 let now = Timestamp::now();
683 self.update_dir_attributes_internal(
684 transaction,
685 self.object_id(),
686 MutableAttributesInternal {
687 modification_time: Some(now.as_nanos()),
688 change_time: Some(now),
689 ..Default::default()
690 },
691 )
692 .await
693 }
694
695 fn copy_project_id_to_object_in_txn<'a>(
700 &self,
701 transaction: &mut Transaction<'a>,
702 object_id: u64,
703 ) -> Result<(), Error> {
704 let store_id = self.store().store_object_id();
705 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
707 transaction
708 .get_object_mutation(store_id, ObjectKey::object(self.object_id()))
709 .unwrap()
710 .item
711 .value
712 else {
713 return Err(anyhow!(FxfsError::Inconsistent));
714 };
715 if project_id > 0 {
716 let mut mutation = transaction
719 .get_object_mutation(store_id, ObjectKey::object(object_id))
720 .unwrap()
721 .clone();
722 if let ObjectValue::Object {
723 attributes: ObjectAttributes { project_id: child_project_id, .. },
724 ..
725 } = &mut mutation.item.value
726 {
727 *child_project_id = project_id;
728 } else {
729 return Err(anyhow!(FxfsError::Inconsistent));
730 }
731 transaction.add(store_id, Mutation::ObjectStore(mutation));
732 transaction.add(
733 store_id,
734 Mutation::merge_object(
735 ObjectKey::project_usage(self.store().root_directory_object_id(), project_id),
736 ObjectValue::BytesAndNodes { bytes: 0, nodes: 1 },
737 ),
738 );
739 }
740 Ok(())
741 }
742
743 pub async fn create_child_file<'a>(
744 &self,
745 transaction: &mut Transaction<'a>,
746 name: &str,
747 ) -> Result<DataObjectHandle<S>, Error> {
748 self.create_child_file_with_options(transaction, name, HandleOptions::default()).await
749 }
750
751 pub async fn create_child_file_with_options<'a>(
752 &self,
753 transaction: &mut Transaction<'a>,
754 name: &str,
755 options: HandleOptions,
756 ) -> Result<DataObjectHandle<S>, Error> {
757 ensure!(!self.is_deleted(), FxfsError::Deleted);
758 let wrapping_key_id = self.wrapping_key_id();
759 let handle =
760 ObjectStore::create_object(self.owner(), transaction, options, wrapping_key_id).await?;
761 self.add_child_file(transaction, name, &handle).await?;
762 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
763 Ok(handle)
764 }
765
766 pub async fn create_child_unnamed_temporary_file<'a>(
767 &self,
768 transaction: &mut Transaction<'a>,
769 ) -> Result<DataObjectHandle<S>, Error> {
770 ensure!(!self.is_deleted(), FxfsError::Deleted);
771 let wrapping_key_id = self.wrapping_key_id();
772 let handle = ObjectStore::create_object(
773 self.owner(),
774 transaction,
775 HandleOptions::default(),
776 wrapping_key_id,
777 )
778 .await?;
779
780 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } = self
782 .store()
783 .txn_get_object_mutation(&transaction, self.object_id())
784 .await
785 .unwrap()
786 .item
787 .value
788 else {
789 bail!(
790 anyhow!(FxfsError::Inconsistent)
791 .context("Directory.create_child_file_with_options: expected mutation object")
792 );
793 };
794
795 let mut child_mutation = transaction
797 .get_object_mutation(
798 self.store().store_object_id(),
799 ObjectKey::object(handle.object_id()),
800 )
801 .unwrap()
802 .clone();
803 if let ObjectValue::Object {
804 attributes: ObjectAttributes { project_id: child_project_id, .. },
805 ..
806 } = &mut child_mutation.item.value
807 {
808 *child_project_id = project_id;
809 } else {
810 bail!(
811 anyhow!(FxfsError::Inconsistent)
812 .context("Directory.create_child_file_with_options: expected file object")
813 );
814 }
815 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(child_mutation));
816
817 self.store().add_to_graveyard(transaction, handle.object_id());
819
820 Ok(handle)
821 }
822
823 pub async fn create_symlink(
824 &self,
825 transaction: &mut Transaction<'_>,
826 link: &[u8],
827 name: &str,
828 ) -> Result<u64, Error> {
829 ensure!(!self.is_deleted(), FxfsError::Deleted);
830 ensure!(link.len() <= 256, FxfsError::BadPath);
834 let reserved_symlink_id = self.store().get_next_object_id(transaction.txn_guard()).await?;
835 let symlink_id = reserved_symlink_id.get();
836 let mut link = link.to_vec();
837
838 match self.dir_type() {
839 DirType::Encrypted(wrapping_key_id) | DirType::EncryptedCasefold(wrapping_key_id) => {
840 if let Some(crypt) = self.store().crypt() {
841 let (key, unwrapped_key) = crypt
842 .create_key_with_id(symlink_id, wrapping_key_id, ObjectType::Symlink)
843 .await?;
844
845 let cipher = key_to_cipher(&key, &unwrapped_key)?;
850 self.store().key_manager.insert(
851 symlink_id,
852 Arc::new(
853 vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher.clone()))].into(),
854 ),
855 false,
856 );
857
858 let dir_key =
859 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
860 let encrypted_name = encrypt_filename(&*dir_key, self.object_id(), name)?;
861 let hash_code = if self.dir_type().is_casefold() {
862 Some(dir_key.hash_code_casefold(name))
863 } else {
864 dir_key.hash_code(encrypted_name.as_bytes(), name)
865 };
866 cipher.encrypt_symlink(symlink_id, &mut link)?;
867
868 transaction.add(
869 self.store().store_object_id(),
870 Mutation::insert_object(
871 ObjectKey::object(reserved_symlink_id.release()),
872 ObjectValue::encrypted_symlink(
873 link,
874 Timestamp::now(),
875 Timestamp::now(),
876 0,
877 ),
878 ),
879 );
880 transaction.add(
881 self.store().store_object_id(),
882 Mutation::insert_object(
883 ObjectKey::keys(symlink_id),
884 ObjectValue::keys(vec![(FSCRYPT_KEY_ID, key)].into()),
885 ),
886 );
887 transaction.add(
888 self.store().store_object_id(),
889 Mutation::replace_or_insert_object(
890 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
891 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
892 ),
893 );
894 } else {
895 return Err(anyhow!("No crypt"));
896 }
897 }
898 _ => {
899 transaction.add(
900 self.store().store_object_id(),
901 Mutation::insert_object(
902 ObjectKey::object(reserved_symlink_id.release()),
903 ObjectValue::symlink(link, Timestamp::now(), Timestamp::now(), 0),
904 ),
905 );
906 transaction.add(
907 self.store().store_object_id(),
908 Mutation::replace_or_insert_object(
909 ObjectKey::child(self.object_id(), &name, self.dir_type()),
910 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
911 ),
912 );
913 }
914 }
915
916 let now = Timestamp::now();
917 self.update_dir_attributes_internal(
918 transaction,
919 self.object_id(),
920 MutableAttributesInternal {
921 modification_time: Some(now.as_nanos()),
922 change_time: Some(now),
923 ..Default::default()
924 },
925 )
926 .await?;
927 Ok(symlink_id)
928 }
929
930 pub async fn add_child_volume(
931 &self,
932 transaction: &mut Transaction<'_>,
933 volume_name: &str,
934 store_object_id: u64,
935 ) -> Result<(), Error> {
936 ensure!(!self.is_deleted(), FxfsError::Deleted);
937 transaction.add(
938 self.store().store_object_id(),
939 Mutation::replace_or_insert_object(
940 ObjectKey::child(self.object_id(), volume_name, self.dir_type()),
941 ObjectValue::child(store_object_id, ObjectDescriptor::Volume),
942 ),
943 );
944 let now = Timestamp::now();
945 self.update_dir_attributes_internal(
946 transaction,
947 self.object_id(),
948 MutableAttributesInternal {
949 modification_time: Some(now.as_nanos()),
950 change_time: Some(now),
951 ..Default::default()
952 },
953 )
954 .await
955 }
956
957 pub fn delete_child_volume<'a>(
958 &self,
959 transaction: &mut Transaction<'a>,
960 volume_name: &str,
961 store_object_id: u64,
962 ) -> Result<(), Error> {
963 ensure!(!self.is_deleted(), FxfsError::Deleted);
964 transaction.add(
965 self.store().store_object_id(),
966 Mutation::replace_or_insert_object(
967 ObjectKey::child(self.object_id(), volume_name, self.dir_type()),
968 ObjectValue::None,
969 ),
970 );
971 transaction.add(store_object_id, Mutation::DeleteVolume);
976 Ok(())
977 }
978
979 pub async fn insert_child<'a>(
983 &self,
984 transaction: &mut Transaction<'a>,
985 name: &str,
986 object_id: u64,
987 descriptor: ObjectDescriptor,
988 ) -> Result<(), Error> {
989 ensure!(!self.is_deleted(), FxfsError::Deleted);
990 let sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
991 if self.dir_type().is_encrypted() {
992 let fscrypt_key =
993 self.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
994 let encrypted_name = encrypt_filename(&*fscrypt_key, self.object_id(), name)?;
995 let hash_code = if self.dir_type().is_casefold() {
996 Some(fscrypt_key.hash_code_casefold(name))
997 } else {
998 fscrypt_key.hash_code(encrypted_name.as_bytes(), name)
999 };
1000 transaction.add(
1001 self.store().store_object_id(),
1002 Mutation::replace_or_insert_object(
1003 ObjectKey::encrypted_child(self.object_id(), encrypted_name, hash_code),
1004 ObjectValue::child(object_id, descriptor),
1005 ),
1006 );
1007 } else {
1008 transaction.add(
1009 self.store().store_object_id(),
1010 Mutation::replace_or_insert_object(
1011 ObjectKey::child(self.object_id(), &name, self.dir_type()),
1012 ObjectValue::child(object_id, descriptor),
1013 ),
1014 );
1015 }
1016 let now = Timestamp::now();
1017 self.update_dir_attributes_internal(
1018 transaction,
1019 self.object_id(),
1020 MutableAttributesInternal {
1021 sub_dirs: sub_dirs_delta,
1022 modification_time: Some(now.as_nanos()),
1023 change_time: Some(now),
1024 ..Default::default()
1025 },
1026 )
1027 .await
1028 }
1029
1030 pub async fn update_attributes<'a>(
1033 &self,
1034 mut transaction: Transaction<'a>,
1035 node_attributes: Option<&fio::MutableNodeAttributes>,
1036 sub_dirs_delta: i64,
1037 change_time: Option<Timestamp>,
1038 ) -> Result<(), Error> {
1039 ensure!(!self.is_deleted(), FxfsError::Deleted);
1040
1041 if sub_dirs_delta != 0 {
1042 let mut mutation =
1043 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
1044 if let ObjectValue::Object { kind: ObjectKind::Directory { sub_dirs, .. }, .. } =
1045 &mut mutation.item.value
1046 {
1047 *sub_dirs = sub_dirs.saturating_add_signed(sub_dirs_delta);
1048 } else {
1049 bail!(
1050 anyhow!(FxfsError::Inconsistent)
1051 .context("Directory.update_attributes: expected directory object")
1052 );
1053 };
1054
1055 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1056 }
1057
1058 let wrapping_key =
1059 if let Some(fio::MutableNodeAttributes { wrapping_key_id: Some(id), .. }) =
1060 node_attributes
1061 {
1062 Some((*id, self.set_wrapping_key(&mut transaction, *id).await?))
1063 } else {
1064 None
1065 };
1066
1067 if node_attributes.is_some() || change_time.is_some() {
1069 self.handle.update_attributes(&mut transaction, node_attributes, change_time).await?;
1070 }
1071 transaction
1072 .commit_with_callback(|_| {
1073 if let Some((wrapping_key_id, cipher)) = wrapping_key {
1074 {
1075 let mut dir_type = self.dir_type.lock();
1076 *dir_type = match *dir_type {
1077 DirType::Normal => DirType::Encrypted(wrapping_key_id),
1078 DirType::Casefold => DirType::EncryptedCasefold(wrapping_key_id),
1079 _ => *dir_type,
1080 };
1081 }
1082 self.store().key_manager.merge(self.object_id(), |existing| match existing {
1083 Some(existing) => {
1084 let mut cipher_set = (**existing).clone();
1085 cipher_set.add_key(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher));
1086 Arc::new(cipher_set)
1087 }
1088 None => {
1089 Arc::new(vec![(FSCRYPT_KEY_ID, CipherHolder::Cipher(cipher))].into())
1090 }
1091 });
1092 }
1093 })
1094 .await?;
1095 Ok(())
1096 }
1097
1098 pub async fn update_dir_attributes_internal<'a>(
1102 &self,
1103 transaction: &mut Transaction<'a>,
1104 object_id: u64,
1105 mutable_node_attributes: MutableAttributesInternal,
1106 ) -> Result<(), Error> {
1107 ensure!(!self.is_deleted(), FxfsError::Deleted);
1108
1109 let mut mutation = self.store().txn_get_object_mutation(transaction, object_id).await?;
1110 if let ObjectValue::Object {
1111 kind: ObjectKind::Directory { sub_dirs, .. },
1112 attributes,
1113 ..
1114 } = &mut mutation.item.value
1115 {
1116 if let Some(time) = mutable_node_attributes.modification_time {
1117 attributes.modification_time = Timestamp::from_nanos(time);
1118 }
1119 if let Some(time) = mutable_node_attributes.change_time {
1120 attributes.change_time = time;
1121 }
1122 if mutable_node_attributes.sub_dirs != 0 {
1123 *sub_dirs = sub_dirs.saturating_add_signed(mutable_node_attributes.sub_dirs);
1124 }
1125 if let Some(time) = mutable_node_attributes.creation_time {
1126 attributes.creation_time = Timestamp::from_nanos(time);
1127 }
1128 } else {
1129 bail!(
1130 anyhow!(FxfsError::Inconsistent)
1131 .context("Directory.update_attributes: expected directory object")
1132 );
1133 };
1134 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1135 Ok(())
1136 }
1137
1138 pub async fn get_properties(&self) -> Result<ObjectProperties, Error> {
1139 if self.is_deleted() {
1140 return Ok(ObjectProperties {
1141 refs: 0,
1142 allocated_size: 0,
1143 data_attribute_size: 0,
1144 creation_time: Timestamp::zero(),
1145 modification_time: Timestamp::zero(),
1146 access_time: Timestamp::zero(),
1147 change_time: Timestamp::zero(),
1148 sub_dirs: 0,
1149 posix_attributes: None,
1150 dir_type: DirType::Normal,
1151 });
1152 }
1153
1154 let item = self
1155 .store()
1156 .tree()
1157 .find(&ObjectKey::object(self.object_id()))
1158 .await?
1159 .ok_or(FxfsError::NotFound)?;
1160 match item.value {
1161 ObjectValue::Object {
1162 kind: ObjectKind::Directory { sub_dirs, dir_type },
1163 attributes:
1164 ObjectAttributes {
1165 creation_time,
1166 modification_time,
1167 posix_attributes,
1168 access_time,
1169 change_time,
1170 ..
1171 },
1172 } => Ok(ObjectProperties {
1173 refs: 1,
1174 allocated_size: 0,
1175 data_attribute_size: 0,
1176 creation_time,
1177 modification_time,
1178 access_time,
1179 change_time,
1180 sub_dirs,
1181 posix_attributes,
1182 dir_type,
1183 }),
1184 _ => {
1185 bail!(
1186 anyhow!(FxfsError::Inconsistent)
1187 .context("get_properties: Expected object value")
1188 )
1189 }
1190 }
1191 }
1192
1193 pub async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, Error> {
1194 ensure!(!self.is_deleted(), FxfsError::Deleted);
1195 self.handle.list_extended_attributes().await
1196 }
1197
1198 pub async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, Error> {
1199 ensure!(!self.is_deleted(), FxfsError::Deleted);
1200 self.handle.get_extended_attribute(name).await
1201 }
1202
1203 pub async fn set_extended_attribute(
1204 &self,
1205 name: Vec<u8>,
1206 value: Vec<u8>,
1207 mode: SetExtendedAttributeMode,
1208 ) -> Result<(), Error> {
1209 ensure!(!self.is_deleted(), FxfsError::Deleted);
1210 self.handle.set_extended_attribute(name, value, mode).await
1211 }
1212
1213 pub async fn remove_extended_attribute(&self, name: Vec<u8>) -> Result<(), Error> {
1214 ensure!(!self.is_deleted(), FxfsError::Deleted);
1215 self.handle.remove_extended_attribute(name).await
1216 }
1217
1218 pub async fn iter<'a, 'b>(
1226 &self,
1227 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1228 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1229 self.iter_from_key(
1234 merger,
1235 &if self.dir_type().is_encrypted() {
1236 ObjectKey::encrypted_child(self.object_id(), Vec::new(), Some(0))
1240 } else {
1241 ObjectKey::child(self.object_id(), "", self.dir_type())
1242 },
1243 )
1244 .await
1245 }
1246
1247 pub async fn iter_from_key<'a, 'b>(
1249 &self,
1250 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1251 key: &ObjectKey,
1252 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1253 ensure!(!self.is_deleted(), FxfsError::Deleted);
1254
1255 DirectoryIterator::new(
1256 self.object_id(),
1257 merger.query(Query::FullRange(key)).await?,
1258 if self.dir_type().is_encrypted() {
1259 self.get_fscrypt_key().await?.into_cipher()
1260 } else {
1261 None
1262 },
1263 )
1264 .await
1265 }
1266
1267 pub async fn iter_from<'a, 'b>(
1278 &self,
1279 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1280 from: &str,
1281 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1282 debug_assert!(!self.dir_type().is_encrypted());
1283
1284 self.iter_from_key(merger, &ObjectKey::child(self.object_id(), from, self.dir_type())).await
1285 }
1286
1287 pub async fn iter_from_bytes<'a, 'b>(
1291 &self,
1292 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1293 from: &[u8],
1294 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1295 debug_assert!(self.dir_type().is_encrypted());
1296
1297 self.iter_from_key(merger, &bincode::deserialize(&from).unwrap()).await
1298 }
1299
1300 async fn advance_until(
1303 &self,
1304 iter: &mut MergerIterator<'_, '_, ObjectKey, ObjectValue>,
1305 predicate: impl Fn(&ObjectKey) -> ControlFlow<bool>,
1306 ) -> Result<bool, Error> {
1307 while let Some(item) = iter.get()
1308 && matches!(
1309 item,
1310 ItemRef { key: ObjectKey { object_id, .. }, .. }
1311 if *object_id == self.object_id()
1312 )
1313 {
1314 match item {
1315 ItemRef { value: ObjectValue::None, .. } => {}
1317 ItemRef { key, .. } => match predicate(key) {
1318 ControlFlow::Continue(()) => {}
1319 ControlFlow::Break(result) => return Ok(result),
1320 },
1321 }
1322 iter.advance().await?
1323 }
1324 Ok(false)
1325 }
1326
1327 fn get_key_and_predicate_for_unavailable_cipher<'a>(
1330 &self,
1331 proxy_name: &'a ProxyFilename,
1332 ) -> (ObjectKey, Option<BoxPredicate<'a>>) {
1333 if self.dir_type().is_casefold() {
1334 (
1335 ObjectKey::encrypted_child(
1336 self.object_id(),
1337 proxy_name.raw_filename().to_vec(),
1338 Some(proxy_name.hash_code as u32),
1339 ),
1340 proxy_name
1341 .is_truncated()
1342 .then(|| Box::new(long_proxy_prefix_casefold_predicate(&proxy_name)) as Box<_>),
1343 )
1344 } else {
1345 (
1346 ObjectKey::encrypted_child(
1347 self.object_id(),
1348 proxy_name.raw_filename().to_vec(),
1349 None,
1350 ),
1351 proxy_name
1352 .is_truncated()
1353 .then(|| Box::new(long_proxy_prefix_predicate(&proxy_name)) as Box<_>),
1354 )
1355 }
1356 }
1357}
1358
1359fn encrypted_casefold_predicate<'a>(
1361 cipher: &'a dyn Cipher,
1362 object_id: u64,
1363 target_hash_code: u32,
1364 name: &'a str,
1365) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + 'a {
1366 move |key| match key {
1367 ObjectKey {
1368 data:
1369 ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
1370 hash_code,
1371 name: encrypted_name,
1372 }),
1373 ..
1374 } if *hash_code == target_hash_code => {
1375 let decrypted_name = decrypt_filename(cipher, object_id, encrypted_name);
1376 match decrypted_name {
1377 Ok(decrypted_name) => {
1378 if fxfs_unicode::casefold_cmp(name, &decrypted_name)
1379 == std::cmp::Ordering::Equal
1380 {
1381 ControlFlow::Break(true)
1382 } else {
1383 ControlFlow::Continue(())
1384 }
1385 }
1386 Err(_) => ControlFlow::Continue(()),
1387 }
1388 }
1389 _ => ControlFlow::Break(false),
1390 }
1391}
1392
1393fn casefold_predicate(
1394 object_id: u64,
1395 target_hash_code: u32,
1396 name: &str,
1397) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1398 move |key| match key {
1399 ObjectKey {
1400 object_id: oid,
1401 data: ObjectKeyData::CasefoldChild { hash_code, name: actual_name },
1402 } if *oid == object_id && *hash_code == target_hash_code => {
1403 if fxfs_unicode::casefold_cmp(name, actual_name) == std::cmp::Ordering::Equal {
1404 ControlFlow::Break(true)
1405 } else {
1406 ControlFlow::Continue(())
1407 }
1408 }
1409 _ => ControlFlow::Break(false),
1410 }
1411}
1412
1413fn long_proxy_prefix_casefold_predicate(
1415 proxy_name: &ProxyFilename,
1416) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1417 move |key| match key {
1418 ObjectKey {
1419 data: ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild { hash_code, name }),
1420 ..
1421 } if *hash_code as u64 == proxy_name.hash_code
1422 && name.starts_with(&proxy_name.filename) =>
1423 {
1424 if ProxyFilename::compute_sha256(&name) == proxy_name.sha256 {
1425 ControlFlow::Break(true)
1426 } else {
1427 ControlFlow::Continue(())
1428 }
1429 }
1430 _ => ControlFlow::Break(false),
1431 }
1432}
1433
1434fn long_proxy_prefix_predicate(
1436 proxy_name: &ProxyFilename,
1437) -> impl Fn(&ObjectKey) -> ControlFlow<bool> + '_ {
1438 move |key| match key {
1439 ObjectKey { data: ObjectKeyData::EncryptedChild(EncryptedChild(name)), .. }
1440 if name.starts_with(&proxy_name.filename) =>
1441 {
1442 if ProxyFilename::compute_hash_code(name) == proxy_name.hash_code
1443 && ProxyFilename::compute_sha256(name) == proxy_name.sha256
1444 {
1445 ControlFlow::Break(true)
1446 } else {
1447 ControlFlow::Continue(())
1448 }
1449 }
1450 _ => ControlFlow::Break(false),
1451 }
1452}
1453
1454impl<S: HandleOwner> fmt::Debug for Directory<S> {
1455 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1456 f.debug_struct("Directory")
1457 .field("store_id", &self.store().store_object_id())
1458 .field("object_id", &self.object_id())
1459 .finish()
1460 }
1461}
1462
1463pub struct DirectoryIterator<'a, 'b> {
1464 object_id: u64,
1465 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1466 cipher: Option<Arc<dyn Cipher>>,
1467 filename: Option<String>,
1469}
1470
1471impl<'a, 'b> DirectoryIterator<'a, 'b> {
1472 pub async fn new(
1473 object_id: u64,
1474 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1475 cipher: Option<Arc<dyn Cipher>>,
1476 ) -> Result<Self, Error> {
1477 let mut this = DirectoryIterator { object_id, iter, cipher, filename: None };
1478 this.init_item().await?;
1479 Ok(this)
1480 }
1481
1482 pub fn get(&self) -> Option<(&str, u64, &ObjectDescriptor)> {
1483 match self.iter.get() {
1484 Some(ItemRef {
1485 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1486 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1487 ..
1488 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1489 Some(ItemRef {
1490 key:
1491 ObjectKey {
1492 object_id: oid,
1493 data: ObjectKeyData::CasefoldChild { hash_code: _, name },
1494 },
1495 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1496 ..
1497 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1498 Some(ItemRef {
1499 key: ObjectKey { object_id: oid, data: ObjectKeyData::LegacyCasefoldChild(name) },
1500 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1501 ..
1502 }) if *oid == self.object_id => Some((name, *object_id, object_descriptor)),
1503 Some(ItemRef {
1504 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedChild(_) },
1505 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1506 ..
1507 }) if *oid == self.object_id => {
1508 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1509 }
1510 Some(ItemRef {
1511 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedCasefoldChild(_) },
1512 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1513 ..
1514 }) if *oid == self.object_id => {
1515 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1516 }
1517 _ => None,
1518 }
1519 }
1520
1521 pub async fn advance(&mut self) -> Result<(), Error> {
1522 self.iter.advance().await?;
1523 self.init_item().await
1524 }
1525
1526 pub fn traversal_position<R>(
1528 &self,
1529 name_visitor: impl FnOnce(&str) -> R,
1530 bytes_visitor: impl FnOnce(Box<[u8]>) -> R,
1531 ) -> Option<R> {
1532 match self.iter.get() {
1533 Some(ItemRef {
1534 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1535 ..
1536 }) if *oid == self.object_id => Some(name_visitor(name)),
1537 Some(ItemRef {
1538 key:
1539 ObjectKey {
1540 object_id: oid,
1541 data: ObjectKeyData::CasefoldChild { hash_code: _, name },
1542 },
1543 ..
1544 }) if *oid == self.object_id => Some(name_visitor(&name)),
1545 Some(ItemRef {
1546 key: ObjectKey { object_id: oid, data: ObjectKeyData::LegacyCasefoldChild(name) },
1547 ..
1548 }) if *oid == self.object_id => Some(name_visitor(name)),
1549
1550 Some(ItemRef {
1551 key:
1552 key @ ObjectKey {
1553 object_id: oid,
1554 data:
1555 ObjectKeyData::EncryptedChild(_) | ObjectKeyData::EncryptedCasefoldChild(_),
1556 },
1557 ..
1558 }) if *oid == self.object_id => {
1559 Some(bytes_visitor(bincode::serialize(key).unwrap().into()))
1560 }
1561 _ => None,
1562 }
1563 }
1564
1565 async fn init_item(&mut self) -> Result<(), Error> {
1567 loop {
1568 match self.iter.get() {
1569 Some(ItemRef {
1570 key: ObjectKey { object_id, .. },
1571 value: ObjectValue::None,
1572 ..
1573 }) if *object_id == self.object_id => {}
1574 Some(ItemRef {
1575 key:
1576 ObjectKey {
1577 object_id,
1578 data:
1579 ObjectKeyData::EncryptedCasefoldChild(EncryptedCasefoldChild {
1580 hash_code,
1581 name,
1582 }),
1583 },
1584 value: ObjectValue::Child(_),
1585 ..
1586 }) if *object_id == self.object_id => {
1587 self.update_encrypted_filename(Some(*hash_code), name.clone())?;
1590 return Ok(());
1591 }
1592 Some(ItemRef {
1593 key:
1594 ObjectKey {
1595 object_id,
1596 data: ObjectKeyData::EncryptedChild(EncryptedChild(name)),
1597 },
1598 value: ObjectValue::Child(_),
1599 ..
1600 }) if *object_id == self.object_id => {
1601 self.update_encrypted_filename(None, name.clone())?;
1604 return Ok(());
1605 }
1606 _ => return Ok(()),
1607 }
1608 self.iter.advance().await?;
1609 }
1610 }
1611
1612 fn update_encrypted_filename(
1615 &mut self,
1616 hash_code: Option<u32>,
1617 mut name: Vec<u8>,
1618 ) -> Result<(), Error> {
1619 if let Some(cipher) = &self.cipher {
1620 cipher.decrypt_filename(self.object_id, &mut name)?;
1621 self.filename = Some(String::from_utf8(name).map_err(|_| {
1622 anyhow!(FxfsError::Internal).context("Bad UTF-8 encrypted filename")
1623 })?);
1624 } else if let Some(hash_code) = hash_code {
1625 self.filename = Some(ProxyFilename::new_with_hash_code(hash_code as u64, &name).into());
1626 } else {
1627 self.filename = Some(ProxyFilename::new(&name).into());
1628 }
1629 Ok(())
1630 }
1631}
1632
1633#[derive(Debug)]
1636pub enum ReplacedChild {
1637 None,
1638 Object(u64),
1640 ObjectWithRemainingLinks(u64),
1641 Directory(u64),
1642}
1643
1644pub async fn replace_child<'a, S: HandleOwner>(
1652 transaction: &mut Transaction<'a>,
1653 src: Option<(&'a Directory<S>, &str)>,
1654 dst: (&'a Directory<S>, &str),
1655) -> Result<ReplacedChild, Error> {
1656 let mut sub_dirs_delta: i64 = 0;
1657 let now = Timestamp::now();
1658
1659 let src = if let Some((src_dir, src_name)) = src {
1660 let store_id = dst.0.store().store_object_id();
1661 assert_eq!(store_id, src_dir.store().store_object_id());
1662 match (src_dir.dir_type(), dst.0.dir_type()) {
1663 (
1664 DirType::Encrypted(src_id) | DirType::EncryptedCasefold(src_id),
1665 DirType::Encrypted(dst_id) | DirType::EncryptedCasefold(dst_id),
1666 ) => {
1667 ensure!(src_id == dst_id, FxfsError::NotSupported);
1668 let key = src_dir.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
1671 let encrypted_src_name = encrypt_filename(&*key, src_dir.object_id(), src_name)?;
1672 let src_hash_code = if src_dir.dir_type().is_casefold() {
1673 Some(key.hash_code_casefold(src_name))
1674 } else {
1675 key.hash_code(encrypted_src_name.as_bytes(), src_name)
1676 };
1677 transaction.add(
1678 store_id,
1679 Mutation::replace_or_insert_object(
1680 ObjectKey::encrypted_child(
1681 src_dir.object_id(),
1682 encrypted_src_name,
1683 src_hash_code,
1684 ),
1685 ObjectValue::None,
1686 ),
1687 );
1688 }
1689 (DirType::Normal | DirType::Casefold | DirType::LegacyCasefold, _) => {
1690 transaction.add(
1691 store_id,
1692 Mutation::replace_or_insert_object(
1693 ObjectKey::child(src_dir.object_id(), src_name, src_dir.dir_type()),
1694 ObjectValue::None,
1695 ),
1696 );
1697 }
1698 _ => bail!(FxfsError::NotSupported),
1700 }
1701 let (id, descriptor, _) = src_dir.lookup(src_name).await?.ok_or(FxfsError::NotFound)?;
1702 src_dir.store().update_attributes(transaction, id, None, Some(now)).await?;
1703 if src_dir.object_id() != dst.0.object_id() {
1704 sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1705 src_dir
1706 .update_dir_attributes_internal(
1707 transaction,
1708 src_dir.object_id(),
1709 MutableAttributesInternal {
1710 sub_dirs: -sub_dirs_delta,
1711 modification_time: Some(now.as_nanos()),
1712 change_time: Some(now),
1713 ..Default::default()
1714 },
1715 )
1716 .await?;
1717 }
1718 Some((id, descriptor))
1719 } else {
1720 None
1721 };
1722 replace_child_with_object(transaction, src, dst, sub_dirs_delta, now).await
1723}
1724
1725pub async fn replace_child_with_object<'a, S: HandleOwner>(
1735 transaction: &mut Transaction<'a>,
1736 src: Option<(u64, ObjectDescriptor)>,
1737 dst: (&'a Directory<S>, &str),
1738 mut sub_dirs_delta: i64,
1739 timestamp: Timestamp,
1740) -> Result<ReplacedChild, Error> {
1741 let deleted_id_and_descriptor = dst.0.lookup(dst.1).await?;
1742 let store_id = dst.0.store().store_object_id();
1743 let result = match deleted_id_and_descriptor {
1746 Some((old_id, ObjectDescriptor::File | ObjectDescriptor::Symlink, _)) => {
1747 let was_last_ref = dst.0.store().adjust_refs(transaction, old_id, -1).await?;
1748 dst.0.store().update_attributes(transaction, old_id, None, Some(timestamp)).await?;
1749 if was_last_ref {
1750 ReplacedChild::Object(old_id)
1751 } else {
1752 ReplacedChild::ObjectWithRemainingLinks(old_id)
1753 }
1754 }
1755 Some((old_id, ObjectDescriptor::Directory, _)) => {
1756 let dir = Directory::open(&dst.0.owner(), old_id).await?;
1757 if dir.has_children().await? {
1758 bail!(FxfsError::NotEmpty);
1759 }
1760 dst.0.store().add_to_graveyard(transaction, old_id);
1763 sub_dirs_delta -= 1;
1764 ReplacedChild::Directory(old_id)
1765 }
1766 Some((_, ObjectDescriptor::Volume, _)) => {
1767 bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected volume child"))
1768 }
1769 None => {
1770 if src.is_none() {
1771 bail!(FxfsError::NotFound);
1773 }
1774 ReplacedChild::None
1775 }
1776 };
1777 let new_value = match src {
1778 Some((id, descriptor)) => ObjectValue::child(id, descriptor),
1779 None => ObjectValue::None,
1780 };
1781 if dst.0.dir_type().is_encrypted() {
1782 match dst.0.get_fscrypt_key().await? {
1783 CipherHolder::Cipher(cipher) => {
1784 let encrypted_dst_name = encrypt_filename(&*cipher, dst.0.object_id(), dst.1)?;
1785 let dst_hash_code = if dst.0.dir_type().is_casefold() {
1786 Some(cipher.hash_code_casefold(dst.1))
1787 } else {
1788 cipher.hash_code(encrypted_dst_name.as_bytes(), dst.1)
1789 };
1790 transaction.add(
1791 store_id,
1792 Mutation::replace_or_insert_object(
1793 ObjectKey::encrypted_child(
1794 dst.0.object_id(),
1795 encrypted_dst_name,
1796 dst_hash_code,
1797 ),
1798 new_value,
1799 ),
1800 );
1801 }
1802 CipherHolder::Unavailable => {
1803 if !matches!(new_value, ObjectValue::None) {
1804 bail!(FxfsError::NoKey);
1806 }
1807
1808 let proxy_filename: ProxyFilename = dst.1.try_into().unwrap_or_default();
1809
1810 let layer_set = dst.0.store().tree().layer_set();
1811 let mut merger = layer_set.merger();
1812 let (key, predicate) =
1813 dst.0.get_key_and_predicate_for_unavailable_cipher(&proxy_filename);
1814 let mut iter = merger.query(Query::FullRange(&key)).await?;
1815
1816 if let Some(predicate) = predicate {
1817 if !dst.0.advance_until(&mut iter, predicate).await? {
1818 bail!(FxfsError::NotFound);
1819 }
1820 } else if iter
1821 .get()
1822 .is_none_or(|item| item.key != &key || item.value == &ObjectValue::None)
1823 {
1824 bail!(FxfsError::NotFound);
1825 }
1826
1827 transaction.add(
1828 store_id,
1829 Mutation::replace_or_insert_object(iter.get().unwrap().key.clone(), new_value),
1830 );
1831 }
1832 }
1833 } else {
1834 transaction.add(
1835 store_id,
1836 Mutation::replace_or_insert_object(
1837 ObjectKey::child(dst.0.object_id(), dst.1, dst.0.dir_type()),
1838 new_value,
1839 ),
1840 );
1841 }
1842 dst.0
1843 .update_dir_attributes_internal(
1844 transaction,
1845 dst.0.object_id(),
1846 MutableAttributesInternal {
1847 sub_dirs: sub_dirs_delta,
1848 modification_time: Some(timestamp.as_nanos()),
1849 change_time: Some(timestamp),
1850 ..Default::default()
1851 },
1852 )
1853 .await?;
1854 Ok(result)
1855}
1856
1857#[cfg(test)]
1858mod tests {
1859 use super::{ProxyFilename, encrypt_filename, replace_child_with_object};
1860 use crate::errors::FxfsError;
1861 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
1862 use crate::object_handle::{ObjectHandle, ReadObjectHandle, WriteObjectHandle};
1863 use crate::object_store::directory::{
1864 Directory, MutableAttributesInternal, ReplacedChild, replace_child,
1865 };
1866 use crate::object_store::object_record::{ObjectKey, ObjectValue, Timestamp};
1867 use crate::object_store::transaction::{Options, lock_keys};
1868 use crate::object_store::volume::root_volume;
1869 use crate::object_store::{
1870 HandleOptions, LockKey, NewChildStoreOptions, ObjectDescriptor, ObjectKind, ObjectStore,
1871 SetExtendedAttributeMode, StoreObjectHandle, StoreOptions,
1872 };
1873 use anyhow::Error;
1874 use assert_matches::assert_matches;
1875 use fidl_fuchsia_io as fio;
1876 use fxfs_crypt_common::CryptBase;
1877 use fxfs_crypto::{Cipher, Crypt, WrappingKeyId};
1878 use fxfs_insecure_crypto::new_insecure_crypt;
1879 use std::collections::HashSet;
1880 use std::future::poll_fn;
1881 use std::sync::Arc;
1882 use std::task::Poll;
1883 use storage_device::DeviceHolder;
1884 use storage_device::fake_device::FakeDevice;
1885 use test_case::test_case;
1886
1887 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
1888 const WRAPPING_KEY_ID: WrappingKeyId = u128::to_le_bytes(2);
1889
1890 #[fuchsia::test]
1894 async fn test_reopen_with_different_crypt_shows_proxy_name() -> Result<(), Error> {
1895 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
1896 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1897 let symlink_object_id;
1898 {
1899 let crypt = Arc::new(new_insecure_crypt());
1900 crypt
1901 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
1902 .expect("add_wrapping_key failed");
1903 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1904 let store = root_volume
1905 .new_volume(
1906 "test",
1907 NewChildStoreOptions {
1908 options: StoreOptions {
1909 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
1910 ..StoreOptions::default()
1911 },
1912 ..Default::default()
1913 },
1914 )
1915 .await
1916 .expect("new_volume failed");
1917 let mut transaction = fs
1918 .clone()
1919 .new_transaction(
1920 lock_keys![LockKey::object(
1921 store.store_object_id(),
1922 store.root_directory_object_id()
1923 )],
1924 Options::default(),
1925 )
1926 .await
1927 .expect("new_transaction failed");
1928 let root_dir = Directory::open(&store, store.root_directory_object_id())
1929 .await
1930 .expect("open failed");
1931 let _ = root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await?;
1932 transaction.commit().await.unwrap();
1933
1934 let mut transaction = fs
1935 .clone()
1936 .new_transaction(
1937 lock_keys![LockKey::object(
1938 store.store_object_id(),
1939 store.root_directory_object_id()
1940 )],
1941 Options::default(),
1942 )
1943 .await
1944 .expect("new_transaction failed");
1945 let root_dir = Directory::open(&store, store.root_directory_object_id())
1946 .await
1947 .expect("open failed");
1948 symlink_object_id = root_dir
1949 .create_symlink(&mut transaction, b"some_link_text", "a")
1950 .await
1951 .expect("create_symlink failed");
1952 transaction.commit().await.expect("commit failed");
1953 };
1954 fs.close().await.expect("close failed");
1955 let device = fs.take_device().await;
1956 device.reopen(false);
1957
1958 let fs = FxFilesystem::open(device).await.expect("open failed");
1959 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1960 let store = root_volume
1962 .volume(
1963 "test",
1964 StoreOptions {
1965 crypt: Some(Arc::new(new_insecure_crypt())),
1966 ..StoreOptions::default()
1967 },
1968 )
1969 .await
1970 .expect("volume failed");
1971
1972 let item = store
1973 .tree()
1974 .find(&ObjectKey::object(symlink_object_id))
1975 .await
1976 .expect("find failed")
1977 .expect("found record");
1978 let raw_link = match item.value {
1979 ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. } => link,
1980 _ => panic!("Unexpected item {item:?}"),
1981 };
1982 let symlink_target = store.read_symlink(symlink_object_id).await?;
1983 let expected_symlink_target: String =
1985 ProxyFilename::new_with_hash_code(0, &raw_link).into();
1986 assert_eq!(symlink_target, expected_symlink_target.as_bytes());
1987
1988 fs.close().await.expect("Close failed");
1989 Ok(())
1990 }
1991
1992 async fn yield_to_executor() {
1993 let mut done = false;
1994 poll_fn(|cx| {
1995 if done {
1996 Poll::Ready(())
1997 } else {
1998 done = true;
1999 cx.waker().wake_by_ref();
2000 Poll::Pending
2001 }
2002 })
2003 .await;
2004 }
2005
2006 #[fuchsia::test]
2007 async fn test_create_directory() {
2008 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2009 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2010 let object_id = {
2011 let mut transaction = fs
2012 .clone()
2013 .new_transaction(lock_keys![], Options::default())
2014 .await
2015 .expect("new_transaction failed");
2016 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
2017 .await
2018 .expect("create failed");
2019
2020 let child_dir = dir
2021 .create_child_dir(&mut transaction, "foo")
2022 .await
2023 .expect("create_child_dir failed");
2024 let _child_dir_file = child_dir
2025 .create_child_file(&mut transaction, "bar")
2026 .await
2027 .expect("create_child_file failed");
2028 let _child_file = dir
2029 .create_child_file(&mut transaction, "baz")
2030 .await
2031 .expect("create_child_file failed");
2032 dir.add_child_volume(&mut transaction, "corge", 100)
2033 .await
2034 .expect("add_child_volume failed");
2035 transaction.commit().await.expect("commit failed");
2036 fs.sync(SyncOptions::default()).await.expect("sync failed");
2037 dir.object_id()
2038 };
2039 fs.close().await.expect("Close failed");
2040 let device = fs.take_device().await;
2041 device.reopen(false);
2042 let fs = FxFilesystem::open(device).await.expect("open failed");
2043 {
2044 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2045 let (object_id, object_descriptor, _) =
2046 dir.lookup("foo").await.expect("lookup failed").expect("not found");
2047 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
2048 let child_dir =
2049 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2050 let (object_id, object_descriptor, _) =
2051 child_dir.lookup("bar").await.expect("lookup failed").expect("not found");
2052 assert_eq!(object_descriptor, ObjectDescriptor::File);
2053 let _child_dir_file = ObjectStore::open_object(
2054 &fs.root_store(),
2055 object_id,
2056 HandleOptions::default(),
2057 None,
2058 )
2059 .await
2060 .expect("open object failed");
2061 let (object_id, object_descriptor, _) =
2062 dir.lookup("baz").await.expect("lookup failed").expect("not found");
2063 assert_eq!(object_descriptor, ObjectDescriptor::File);
2064 let _child_file = ObjectStore::open_object(
2065 &fs.root_store(),
2066 object_id,
2067 HandleOptions::default(),
2068 None,
2069 )
2070 .await
2071 .expect("open object failed");
2072 let (object_id, object_descriptor, _) =
2073 dir.lookup("corge").await.expect("lookup failed").expect("not found");
2074 assert_eq!(object_id, 100);
2075 if let ObjectDescriptor::Volume = object_descriptor {
2076 } else {
2077 panic!("wrong ObjectDescriptor");
2078 }
2079
2080 assert_eq!(dir.lookup("qux").await.expect("lookup failed"), None);
2081 }
2082 fs.close().await.expect("Close failed");
2083 }
2084
2085 #[fuchsia::test]
2086 async fn test_set_wrapping_key_does_not_exist() {
2087 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2088 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2089 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2090 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2091 let store = root_volume
2092 .new_volume(
2093 "test",
2094 NewChildStoreOptions {
2095 options: StoreOptions {
2096 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2097 ..StoreOptions::default()
2098 },
2099 ..NewChildStoreOptions::default()
2100 },
2101 )
2102 .await
2103 .expect("new_volume failed");
2104
2105 let mut transaction = fs
2106 .clone()
2107 .new_transaction(
2108 lock_keys![LockKey::object(
2109 store.store_object_id(),
2110 store.root_directory_object_id()
2111 )],
2112 Options::default(),
2113 )
2114 .await
2115 .expect("new transaction failed");
2116 let root_directory =
2117 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2118 let directory = root_directory
2119 .create_child_dir(&mut transaction, "foo")
2120 .await
2121 .expect("create_child_dir failed");
2122 transaction.commit().await.expect("commit failed");
2123 let mut transaction = fs
2124 .clone()
2125 .new_transaction(
2126 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2127 Options::default(),
2128 )
2129 .await
2130 .expect("new transaction failed");
2131 directory
2132 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2133 .await
2134 .expect_err("wrapping key id 2 has not been added");
2135 transaction.commit().await.expect("commit failed");
2136 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2137 let mut transaction = fs
2138 .clone()
2139 .new_transaction(
2140 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2141 Options::default(),
2142 )
2143 .await
2144 .expect("new transaction failed");
2145 directory
2146 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2147 .await
2148 .expect("wrapping key id 2 has been added");
2149 fs.close().await.expect("Close failed");
2150 }
2151
2152 #[fuchsia::test]
2153 async fn test_set_encryption_policy_on_unencrypted_nonempty_dir() {
2154 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2155 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2156 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2157 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2158 let store = root_volume
2159 .new_volume(
2160 "test",
2161 NewChildStoreOptions {
2162 options: StoreOptions {
2163 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2164 ..StoreOptions::default()
2165 },
2166 ..NewChildStoreOptions::default()
2167 },
2168 )
2169 .await
2170 .expect("new_volume failed");
2171
2172 let mut transaction = fs
2173 .clone()
2174 .new_transaction(
2175 lock_keys![LockKey::object(
2176 store.store_object_id(),
2177 store.root_directory_object_id()
2178 )],
2179 Options::default(),
2180 )
2181 .await
2182 .expect("new transaction failed");
2183 let root_directory =
2184 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2185 let directory = root_directory
2186 .create_child_dir(&mut transaction, "foo")
2187 .await
2188 .expect("create_child_dir failed");
2189 let _file = directory
2190 .create_child_file(&mut transaction, "bar")
2191 .await
2192 .expect("create_child_file failed");
2193 transaction.commit().await.expect("commit failed");
2194 let mut transaction = fs
2195 .clone()
2196 .new_transaction(
2197 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2198 Options::default(),
2199 )
2200 .await
2201 .expect("new transaction failed");
2202 directory
2203 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2204 .await
2205 .expect_err("directory is not empty");
2206 transaction.commit().await.expect("commit failed");
2207 fs.close().await.expect("Close failed");
2208 }
2209
2210 #[fuchsia::test]
2211 async fn test_create_file_or_subdir_in_locked_directory() {
2212 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2213 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2214 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2215 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2216 let store = root_volume
2217 .new_volume(
2218 "test",
2219 NewChildStoreOptions {
2220 options: StoreOptions {
2221 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2222 ..StoreOptions::default()
2223 },
2224 ..NewChildStoreOptions::default()
2225 },
2226 )
2227 .await
2228 .expect("new_volume failed");
2229
2230 let mut transaction = fs
2231 .clone()
2232 .new_transaction(
2233 lock_keys![LockKey::object(
2234 store.store_object_id(),
2235 store.root_directory_object_id()
2236 )],
2237 Options::default(),
2238 )
2239 .await
2240 .expect("new transaction failed");
2241 let root_directory =
2242 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2243 let directory = root_directory
2244 .create_child_dir(&mut transaction, "foo")
2245 .await
2246 .expect("create_child_dir failed");
2247 transaction.commit().await.expect("commit failed");
2248 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2249 let transaction = fs
2250 .clone()
2251 .new_transaction(
2252 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2253 Options::default(),
2254 )
2255 .await
2256 .expect("new transaction failed");
2257 directory
2258 .update_attributes(
2259 transaction,
2260 Some(&fio::MutableNodeAttributes {
2261 wrapping_key_id: Some(WRAPPING_KEY_ID),
2262 ..Default::default()
2263 }),
2264 0,
2265 None,
2266 )
2267 .await
2268 .expect("update attributes failed");
2269 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget wrapping key failed");
2270 let mut transaction = fs
2271 .clone()
2272 .new_transaction(
2273 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2274 Options::default(),
2275 )
2276 .await
2277 .expect("new transaction failed");
2278 directory
2279 .create_child_dir(&mut transaction, "bar")
2280 .await
2281 .expect_err("cannot create a dir inside of a locked encrypted directory");
2282 directory
2283 .create_child_file(&mut transaction, "baz")
2284 .await
2285 .map(|_| ())
2286 .expect_err("cannot create a file inside of a locked encrypted directory");
2287 fs.close().await.expect("Close failed");
2288 }
2289
2290 #[fuchsia::test]
2291 async fn test_replace_child_with_object_in_locked_directory() {
2292 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2293 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2294 let crypt = Arc::new(new_insecure_crypt());
2295
2296 let (parent_oid, src_oid, dst_oid) = {
2297 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2298 let store = root_volume
2299 .new_volume(
2300 "test",
2301 NewChildStoreOptions {
2302 options: StoreOptions {
2303 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2304 ..StoreOptions::default()
2305 },
2306 ..Default::default()
2307 },
2308 )
2309 .await
2310 .expect("new_volume failed");
2311
2312 let mut transaction = fs
2313 .clone()
2314 .new_transaction(
2315 lock_keys![LockKey::object(
2316 store.store_object_id(),
2317 store.root_directory_object_id()
2318 )],
2319 Options::default(),
2320 )
2321 .await
2322 .expect("new transaction failed");
2323 let root_directory = Directory::open(&store, store.root_directory_object_id())
2324 .await
2325 .expect("open failed");
2326 let directory = root_directory
2327 .create_child_dir(&mut transaction, "foo")
2328 .await
2329 .expect("create_child_dir failed");
2330 transaction.commit().await.expect("commit failed");
2331 crypt
2332 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
2333 .expect("add_wrapping_key failed");
2334 let transaction = fs
2335 .clone()
2336 .new_transaction(
2337 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2338 Options::default(),
2339 )
2340 .await
2341 .expect("new transaction failed");
2342 directory
2343 .update_attributes(
2344 transaction,
2345 Some(&fio::MutableNodeAttributes {
2346 wrapping_key_id: Some(WRAPPING_KEY_ID),
2347 ..Default::default()
2348 }),
2349 0,
2350 None,
2351 )
2352 .await
2353 .expect("update attributes failed");
2354 let mut transaction = fs
2355 .clone()
2356 .new_transaction(
2357 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2358 Options::default(),
2359 )
2360 .await
2361 .expect("new transaction failed");
2362 let src_child = directory
2363 .create_child_dir(&mut transaction, "fee")
2364 .await
2365 .expect("create_child_dir failed");
2366 let dst_child = directory
2367 .create_child_dir(&mut transaction, "faa")
2368 .await
2369 .expect("create_child_dir failed");
2370 transaction.commit().await.expect("commit failed");
2371 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget_wrapping_key failed");
2372 (directory.object_id(), src_child.object_id(), dst_child.object_id())
2373 };
2374 fs.close().await.expect("Close failed");
2375 let device = fs.take_device().await;
2376 device.reopen(false);
2377 let fs = FxFilesystem::open(device).await.expect("open failed");
2378 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2379 let store = root_volume
2380 .volume(
2381 "test",
2382 StoreOptions {
2383 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2384 ..StoreOptions::default()
2385 },
2386 )
2387 .await
2388 .expect("volume failed");
2389
2390 {
2391 let parent_directory = Directory::open(&store, parent_oid).await.expect("open failed");
2392 let layer_set = store.tree().layer_set();
2393 let mut merger = layer_set.merger();
2394 let mut encrypted_src_name = None;
2395 let mut encrypted_dst_name = None;
2396 let mut iter = parent_directory.iter(&mut merger).await.expect("iter_from failed");
2397 while let Some((name, object_id, object_descriptor)) = iter.get() {
2398 assert!(matches!(object_descriptor, ObjectDescriptor::Directory));
2399 if object_id == dst_oid {
2400 encrypted_dst_name = Some(name.to_string());
2401 } else if object_id == src_oid {
2402 encrypted_src_name = Some(name.to_string());
2403 }
2404 iter.advance().await.expect("iter advance failed");
2405 }
2406
2407 let src_child = parent_directory
2408 .lookup(&encrypted_src_name.expect("src child not found"))
2409 .await
2410 .expect("lookup failed")
2411 .expect("not found");
2412 let mut transaction = fs
2413 .clone()
2414 .new_transaction(
2415 lock_keys![LockKey::object(
2416 store.store_object_id(),
2417 parent_directory.object_id(),
2418 )],
2419 Options::default(),
2420 )
2421 .await
2422 .expect("new transaction failed");
2423 replace_child_with_object(
2424 &mut transaction,
2425 Some((src_child.0, src_child.1)),
2426 (&parent_directory, &encrypted_dst_name.expect("dst child not found")),
2427 0,
2428 Timestamp::now(),
2429 )
2430 .await
2431 .expect_err("renames should fail within a locked directory");
2432 }
2433 fs.close().await.expect("Close failed");
2434 }
2435
2436 #[fuchsia::test]
2437 async fn test_set_encryption_policy_on_unencrypted_file() {
2438 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2439 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2440 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2441 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2442 let store = root_volume
2443 .new_volume(
2444 "test",
2445 NewChildStoreOptions {
2446 options: StoreOptions {
2447 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2448 ..StoreOptions::default()
2449 },
2450 ..NewChildStoreOptions::default()
2451 },
2452 )
2453 .await
2454 .expect("new_volume failed");
2455
2456 let mut transaction = fs
2457 .clone()
2458 .new_transaction(
2459 lock_keys![LockKey::object(
2460 store.store_object_id(),
2461 store.root_directory_object_id()
2462 )],
2463 Options::default(),
2464 )
2465 .await
2466 .expect("new transaction failed");
2467 let root_directory =
2468 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2469 let file_handle = root_directory
2470 .create_child_file(&mut transaction, "foo")
2471 .await
2472 .expect("create_child_dir failed");
2473 transaction.commit().await.expect("commit failed");
2474 let mut transaction = fs
2475 .clone()
2476 .new_transaction(
2477 lock_keys![LockKey::object(store.store_object_id(), file_handle.object_id())],
2478 Options::default(),
2479 )
2480 .await
2481 .expect("new transaction failed");
2482 file_handle
2483 .update_attributes(
2484 &mut transaction,
2485 Some(&fio::MutableNodeAttributes {
2486 wrapping_key_id: Some(WRAPPING_KEY_ID),
2487 ..Default::default()
2488 }),
2489 None,
2490 )
2491 .await
2492 .expect_err("Cannot update the wrapping key id of a file");
2493 fs.close().await.expect("Close failed");
2494 }
2495
2496 #[fuchsia::test]
2497 async fn test_delete_child() {
2498 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2499 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2500 let dir;
2501 let child;
2502 let mut transaction = fs
2503 .clone()
2504 .new_transaction(lock_keys![], Options::default())
2505 .await
2506 .expect("new_transaction failed");
2507 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2508 .await
2509 .expect("create failed");
2510
2511 child =
2512 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2513 transaction.commit().await.expect("commit failed");
2514
2515 transaction = fs
2516 .clone()
2517 .new_transaction(
2518 lock_keys![
2519 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2520 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2521 ],
2522 Options::default(),
2523 )
2524 .await
2525 .expect("new_transaction failed");
2526 assert_matches!(
2527 replace_child(&mut transaction, None, (&dir, "foo"))
2528 .await
2529 .expect("replace_child failed"),
2530 ReplacedChild::Object(..)
2531 );
2532 transaction.commit().await.expect("commit failed");
2533
2534 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2535 fs.close().await.expect("Close failed");
2536 }
2537
2538 #[fuchsia::test]
2539 async fn test_delete_child_with_children_fails() {
2540 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2541 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2542 let dir;
2543 let child;
2544 let bar;
2545 let mut transaction = fs
2546 .clone()
2547 .new_transaction(lock_keys![], Options::default())
2548 .await
2549 .expect("new_transaction failed");
2550 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2551 .await
2552 .expect("create failed");
2553
2554 child =
2555 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2556 bar = child
2557 .create_child_file(&mut transaction, "bar")
2558 .await
2559 .expect("create_child_file failed");
2560 transaction.commit().await.expect("commit failed");
2561
2562 transaction = fs
2563 .clone()
2564 .new_transaction(
2565 lock_keys![
2566 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2567 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2568 ],
2569 Options::default(),
2570 )
2571 .await
2572 .expect("new_transaction failed");
2573 assert_eq!(
2574 replace_child(&mut transaction, None, (&dir, "foo"))
2575 .await
2576 .expect_err("replace_child succeeded")
2577 .downcast::<FxfsError>()
2578 .expect("wrong error"),
2579 FxfsError::NotEmpty
2580 );
2581 transaction.commit().await.expect("commit failed");
2582
2583 transaction = fs
2584 .clone()
2585 .new_transaction(
2586 lock_keys![
2587 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2588 LockKey::object(fs.root_store().store_object_id(), bar.object_id()),
2589 ],
2590 Options::default(),
2591 )
2592 .await
2593 .expect("new_transaction failed");
2594 assert_matches!(
2595 replace_child(&mut transaction, None, (&child, "bar"))
2596 .await
2597 .expect("replace_child failed"),
2598 ReplacedChild::Object(..)
2599 );
2600 transaction.commit().await.expect("commit failed");
2601
2602 transaction = fs
2603 .clone()
2604 .new_transaction(
2605 lock_keys![
2606 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2607 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2608 ],
2609 Options::default(),
2610 )
2611 .await
2612 .expect("new_transaction failed");
2613 assert_matches!(
2614 replace_child(&mut transaction, None, (&dir, "foo"))
2615 .await
2616 .expect("replace_child failed"),
2617 ReplacedChild::Directory(..)
2618 );
2619 transaction.commit().await.expect("commit failed");
2620
2621 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2622 fs.close().await.expect("Close failed");
2623 }
2624
2625 #[fuchsia::test]
2626 async fn test_delete_and_reinsert_child() {
2627 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2628 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2629 let dir;
2630 let child;
2631 let mut transaction = fs
2632 .clone()
2633 .new_transaction(lock_keys![], Options::default())
2634 .await
2635 .expect("new_transaction failed");
2636 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2637 .await
2638 .expect("create failed");
2639
2640 child =
2641 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2642 transaction.commit().await.expect("commit failed");
2643
2644 transaction = fs
2645 .clone()
2646 .new_transaction(
2647 lock_keys![
2648 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2649 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2650 ],
2651 Options::default(),
2652 )
2653 .await
2654 .expect("new_transaction failed");
2655 assert_matches!(
2656 replace_child(&mut transaction, None, (&dir, "foo"))
2657 .await
2658 .expect("replace_child failed"),
2659 ReplacedChild::Object(..)
2660 );
2661 transaction.commit().await.expect("commit failed");
2662
2663 transaction = fs
2664 .clone()
2665 .new_transaction(
2666 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2667 Options::default(),
2668 )
2669 .await
2670 .expect("new_transaction failed");
2671 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2672 transaction.commit().await.expect("commit failed");
2673
2674 dir.lookup("foo").await.expect("lookup failed");
2675 fs.close().await.expect("Close failed");
2676 }
2677
2678 #[fuchsia::test]
2679 async fn test_delete_child_persists() {
2680 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2681 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2682 let object_id = {
2683 let dir;
2684 let child;
2685 let mut transaction = fs
2686 .clone()
2687 .new_transaction(lock_keys![], Options::default())
2688 .await
2689 .expect("new_transaction failed");
2690 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2691 .await
2692 .expect("create failed");
2693
2694 child = dir
2695 .create_child_file(&mut transaction, "foo")
2696 .await
2697 .expect("create_child_file failed");
2698 transaction.commit().await.expect("commit failed");
2699 dir.lookup("foo").await.expect("lookup failed");
2700
2701 transaction = fs
2702 .clone()
2703 .new_transaction(
2704 lock_keys![
2705 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2706 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2707 ],
2708 Options::default(),
2709 )
2710 .await
2711 .expect("new_transaction failed");
2712 assert_matches!(
2713 replace_child(&mut transaction, None, (&dir, "foo"))
2714 .await
2715 .expect("replace_child failed"),
2716 ReplacedChild::Object(..)
2717 );
2718 transaction.commit().await.expect("commit failed");
2719
2720 fs.sync(SyncOptions::default()).await.expect("sync failed");
2721 dir.object_id()
2722 };
2723
2724 fs.close().await.expect("Close failed");
2725 let device = fs.take_device().await;
2726 device.reopen(false);
2727 let fs = FxFilesystem::open(device).await.expect("open failed");
2728 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2729 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2730 fs.close().await.expect("Close failed");
2731 }
2732
2733 #[fuchsia::test]
2734 async fn test_replace_child() {
2735 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2736 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2737 let dir;
2738 let child_dir1;
2739 let child_dir2;
2740 let mut transaction = fs
2741 .clone()
2742 .new_transaction(lock_keys![], Options::default())
2743 .await
2744 .expect("new_transaction failed");
2745 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2746 .await
2747 .expect("create failed");
2748
2749 child_dir1 =
2750 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2751 child_dir2 =
2752 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2753 let file = child_dir1
2754 .create_child_file(&mut transaction, "foo")
2755 .await
2756 .expect("create_child_file failed");
2757 transaction.commit().await.expect("commit failed");
2758
2759 transaction = fs
2760 .clone()
2761 .new_transaction(
2762 lock_keys![
2763 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2764 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2765 LockKey::object(fs.root_store().store_object_id(), file.object_id()),
2766 ],
2767 Options::default(),
2768 )
2769 .await
2770 .expect("new_transaction failed");
2771 assert_matches!(
2772 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2773 .await
2774 .expect("replace_child failed"),
2775 ReplacedChild::None
2776 );
2777 transaction.commit().await.expect("commit failed");
2778
2779 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2780 child_dir2.lookup("bar").await.expect("lookup failed");
2781 fs.close().await.expect("Close failed");
2782 }
2783
2784 #[fuchsia::test]
2785 async fn test_replace_child_overwrites_dst() {
2786 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2787 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2788 let dir;
2789 let child_dir1;
2790 let child_dir2;
2791 let mut transaction = fs
2792 .clone()
2793 .new_transaction(lock_keys![], Options::default())
2794 .await
2795 .expect("new_transaction failed");
2796 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2797 .await
2798 .expect("create failed");
2799
2800 child_dir1 =
2801 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2802 child_dir2 =
2803 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2804 let foo = child_dir1
2805 .create_child_file(&mut transaction, "foo")
2806 .await
2807 .expect("create_child_file failed");
2808 let bar = child_dir2
2809 .create_child_file(&mut transaction, "bar")
2810 .await
2811 .expect("create_child_file failed");
2812 let foo_oid = foo.object_id();
2813 let bar_oid = bar.object_id();
2814 transaction.commit().await.expect("commit failed");
2815
2816 {
2817 let mut buf = foo.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2818 buf.as_mut_slice().fill(0xaa);
2819 foo.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2820 buf.as_mut_slice().fill(0xbb);
2821 bar.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2822 }
2823 std::mem::drop(bar);
2824 std::mem::drop(foo);
2825
2826 transaction = fs
2827 .clone()
2828 .new_transaction(
2829 lock_keys![
2830 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2831 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2832 LockKey::object(fs.root_store().store_object_id(), foo_oid),
2833 LockKey::object(fs.root_store().store_object_id(), bar_oid),
2834 ],
2835 Options::default(),
2836 )
2837 .await
2838 .expect("new_transaction failed");
2839 assert_matches!(
2840 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2841 .await
2842 .expect("replace_child failed"),
2843 ReplacedChild::Object(..)
2844 );
2845 transaction.commit().await.expect("commit failed");
2846
2847 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2848
2849 let (oid, object_descriptor, _) =
2851 child_dir2.lookup("bar").await.expect("lookup failed").expect("not found");
2852 assert_eq!(object_descriptor, ObjectDescriptor::File);
2853 let bar =
2854 ObjectStore::open_object(&child_dir2.owner(), oid, HandleOptions::default(), None)
2855 .await
2856 .expect("Open failed");
2857 let mut buf = bar.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2858 bar.read(0, buf.as_mut()).await.expect("read failed");
2859 assert_eq!(buf.as_slice(), vec![0xaa; TEST_DEVICE_BLOCK_SIZE as usize]);
2860 fs.close().await.expect("Close failed");
2861 }
2862
2863 #[fuchsia::test]
2864 async fn test_replace_child_fails_if_would_overwrite_nonempty_dir() {
2865 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2866 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2867 let dir;
2868 let child_dir1;
2869 let child_dir2;
2870 let mut transaction = fs
2871 .clone()
2872 .new_transaction(lock_keys![], Options::default())
2873 .await
2874 .expect("new_transaction failed");
2875 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2876 .await
2877 .expect("create failed");
2878
2879 child_dir1 =
2880 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2881 child_dir2 =
2882 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2883 let foo = child_dir1
2884 .create_child_file(&mut transaction, "foo")
2885 .await
2886 .expect("create_child_file failed");
2887 let nested_child = child_dir2
2888 .create_child_dir(&mut transaction, "bar")
2889 .await
2890 .expect("create_child_file failed");
2891 nested_child
2892 .create_child_file(&mut transaction, "baz")
2893 .await
2894 .expect("create_child_file failed");
2895 transaction.commit().await.expect("commit failed");
2896
2897 transaction = fs
2898 .clone()
2899 .new_transaction(
2900 lock_keys![
2901 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2902 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2903 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2904 LockKey::object(fs.root_store().store_object_id(), nested_child.object_id()),
2905 ],
2906 Options::default(),
2907 )
2908 .await
2909 .expect("new_transaction failed");
2910 assert_eq!(
2911 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2912 .await
2913 .expect_err("replace_child succeeded")
2914 .downcast::<FxfsError>()
2915 .expect("wrong error"),
2916 FxfsError::NotEmpty
2917 );
2918 fs.close().await.expect("Close failed");
2919 }
2920
2921 #[fuchsia::test]
2922 async fn test_replace_child_within_dir() {
2923 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2924 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2925 let dir;
2926 let mut transaction = fs
2927 .clone()
2928 .new_transaction(lock_keys![], Options::default())
2929 .await
2930 .expect("new_transaction failed");
2931 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2932 .await
2933 .expect("create failed");
2934 let foo =
2935 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2936 transaction.commit().await.expect("commit failed");
2937
2938 transaction = fs
2939 .clone()
2940 .new_transaction(
2941 lock_keys![
2942 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2943 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2944 ],
2945 Options::default(),
2946 )
2947 .await
2948 .expect("new_transaction failed");
2949 assert_matches!(
2950 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
2951 .await
2952 .expect("replace_child failed"),
2953 ReplacedChild::None
2954 );
2955 transaction.commit().await.expect("commit failed");
2956
2957 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2958 dir.lookup("bar").await.expect("lookup new name failed");
2959 fs.close().await.expect("Close failed");
2960 }
2961
2962 #[fuchsia::test]
2963 async fn test_iterate() {
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 dir;
2967 let mut transaction = fs
2968 .clone()
2969 .new_transaction(lock_keys![], Options::default())
2970 .await
2971 .expect("new_transaction failed");
2972 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2973 .await
2974 .expect("create failed");
2975 let _cat =
2976 dir.create_child_file(&mut transaction, "cat").await.expect("create_child_file failed");
2977 let _ball = dir
2978 .create_child_file(&mut transaction, "ball")
2979 .await
2980 .expect("create_child_file failed");
2981 let apple = dir
2982 .create_child_file(&mut transaction, "apple")
2983 .await
2984 .expect("create_child_file failed");
2985 let _dog =
2986 dir.create_child_file(&mut transaction, "dog").await.expect("create_child_file failed");
2987 transaction.commit().await.expect("commit failed");
2988 transaction = fs
2989 .clone()
2990 .new_transaction(
2991 lock_keys![
2992 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2993 LockKey::object(fs.root_store().store_object_id(), apple.object_id()),
2994 ],
2995 Options::default(),
2996 )
2997 .await
2998 .expect("new_transaction failed");
2999 replace_child(&mut transaction, None, (&dir, "apple")).await.expect("replace_child failed");
3000 transaction.commit().await.expect("commit failed");
3001 let layer_set = dir.store().tree().layer_set();
3002 let mut merger = layer_set.merger();
3003 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
3004 let mut entries = Vec::new();
3005 while let Some((name, _, _)) = iter.get() {
3006 entries.push(name.to_string());
3007 iter.advance().await.expect("advance failed");
3008 }
3009 assert_eq!(&entries, &["ball", "cat", "dog"]);
3010 fs.close().await.expect("Close failed");
3011 }
3012
3013 #[fuchsia::test]
3014 async fn test_sub_dir_count() {
3015 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3016 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3017 let dir;
3018 let child_dir;
3019 let mut transaction = fs
3020 .clone()
3021 .new_transaction(lock_keys![], Options::default())
3022 .await
3023 .expect("new_transaction failed");
3024 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3025 .await
3026 .expect("create failed");
3027 child_dir =
3028 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3029 transaction.commit().await.expect("commit failed");
3030 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3031
3032 transaction = fs
3034 .clone()
3035 .new_transaction(
3036 lock_keys![
3037 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3038 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3039 ],
3040 Options::default(),
3041 )
3042 .await
3043 .expect("new_transaction failed");
3044 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
3045 .await
3046 .expect("replace_child failed");
3047 transaction.commit().await.expect("commit failed");
3048
3049 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3050 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3051
3052 transaction = fs
3054 .clone()
3055 .new_transaction(
3056 lock_keys![LockKey::object(
3057 fs.root_store().store_object_id(),
3058 child_dir.object_id()
3059 )],
3060 Options::default(),
3061 )
3062 .await
3063 .expect("new_transaction failed");
3064 let second_child = child_dir
3065 .create_child_dir(&mut transaction, "baz")
3066 .await
3067 .expect("create_child_dir failed");
3068 transaction.commit().await.expect("commit failed");
3069
3070 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3071
3072 transaction = fs
3073 .clone()
3074 .new_transaction(
3075 lock_keys![
3076 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3077 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3078 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3079 ],
3080 Options::default(),
3081 )
3082 .await
3083 .expect("new_transaction failed");
3084 replace_child(&mut transaction, Some((&child_dir, "baz")), (&dir, "foo"))
3085 .await
3086 .expect("replace_child failed");
3087 transaction.commit().await.expect("commit failed");
3088
3089 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 2);
3090 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3091
3092 transaction = fs
3094 .clone()
3095 .new_transaction(
3096 lock_keys![
3097 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3098 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3099 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3100 ],
3101 Options::default(),
3102 )
3103 .await
3104 .expect("new_transaction failed");
3105 replace_child(&mut transaction, Some((&dir, "bar")), (&dir, "foo"))
3106 .await
3107 .expect("replace_child failed");
3108 transaction.commit().await.expect("commit failed");
3109
3110 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3111
3112 transaction = fs
3114 .clone()
3115 .new_transaction(
3116 lock_keys![
3117 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3118 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3119 ],
3120 Options::default(),
3121 )
3122 .await
3123 .expect("new_transaction failed");
3124 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3125 transaction.commit().await.expect("commit failed");
3126
3127 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3128 fs.close().await.expect("Close failed");
3129 }
3130
3131 #[fuchsia::test]
3132 async fn test_deleted_dir() {
3133 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3134 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3135 let dir;
3136 let mut transaction = fs
3137 .clone()
3138 .new_transaction(lock_keys![], Options::default())
3139 .await
3140 .expect("new_transaction failed");
3141 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3142 .await
3143 .expect("create failed");
3144 let child =
3145 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3146 dir.create_child_dir(&mut transaction, "bar").await.expect("create_child_dir failed");
3147 transaction.commit().await.expect("commit failed");
3148
3149 dir.store().flush().await.expect("flush failed");
3151
3152 transaction = fs
3154 .clone()
3155 .new_transaction(
3156 lock_keys![
3157 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3158 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
3159 ],
3160 Options::default(),
3161 )
3162 .await
3163 .expect("new_transaction failed");
3164 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3165 transaction.commit().await.expect("commit failed");
3166
3167 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3169
3170 assert!(dir.lookup("bar").await.expect("lookup failed").is_some());
3172
3173 dir.set_deleted();
3175
3176 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3177 assert_eq!(dir.lookup("bar").await.expect("lookup failed"), None);
3178 assert!(!dir.has_children().await.expect("has_children failed"));
3179
3180 transaction = fs
3181 .clone()
3182 .new_transaction(lock_keys![], Options::default())
3183 .await
3184 .expect("new_transaction failed");
3185
3186 let assert_access_denied = |result| {
3187 if let Err(e) = result {
3188 assert!(FxfsError::Deleted.matches(&e));
3189 } else {
3190 panic!();
3191 }
3192 };
3193 assert_access_denied(dir.create_child_dir(&mut transaction, "baz").await.map(|_| {}));
3194 assert_access_denied(dir.create_child_file(&mut transaction, "baz").await.map(|_| {}));
3195 assert_access_denied(dir.add_child_volume(&mut transaction, "baz", 1).await);
3196 assert_access_denied(
3197 dir.insert_child(&mut transaction, "baz", 1, ObjectDescriptor::File).await,
3198 );
3199 assert_access_denied(
3200 dir.update_dir_attributes_internal(
3201 &mut transaction,
3202 dir.object_id(),
3203 MutableAttributesInternal {
3204 creation_time: Some(Timestamp::zero().as_nanos()),
3205 ..Default::default()
3206 },
3207 )
3208 .await,
3209 );
3210 let layer_set = dir.store().tree().layer_set();
3211 let mut merger = layer_set.merger();
3212 assert_access_denied(dir.iter(&mut merger).await.map(|_| {}));
3213 }
3214
3215 #[fuchsia::test]
3216 async fn test_create_symlink() {
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_id, symlink_id) = {
3220 let mut transaction = fs
3221 .clone()
3222 .new_transaction(lock_keys![], Options::default())
3223 .await
3224 .expect("new_transaction failed");
3225 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
3226 .await
3227 .expect("create failed");
3228
3229 let symlink_id = dir
3230 .create_symlink(&mut transaction, b"link", "foo")
3231 .await
3232 .expect("create_symlink failed");
3233 transaction.commit().await.expect("commit failed");
3234
3235 fs.sync(SyncOptions::default()).await.expect("sync failed");
3236 (dir.object_id(), symlink_id)
3237 };
3238 fs.close().await.expect("Close failed");
3239 let device = fs.take_device().await;
3240 device.reopen(false);
3241 let fs = FxFilesystem::open(device).await.expect("open failed");
3242 {
3243 let dir = Directory::open(&fs.root_store(), dir_id).await.expect("open failed");
3244 assert_eq!(
3245 dir.lookup("foo").await.expect("lookup failed").expect("not found"),
3246 (symlink_id, ObjectDescriptor::Symlink, false)
3247 );
3248 }
3249 fs.close().await.expect("Close failed");
3250 }
3251
3252 #[fuchsia::test]
3253 async fn test_read_symlink() {
3254 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3255 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3256 let mut transaction = fs
3257 .clone()
3258 .new_transaction(lock_keys![], Options::default())
3259 .await
3260 .expect("new_transaction failed");
3261 let store = fs.root_store();
3262 let dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3263
3264 let symlink_id = dir
3265 .create_symlink(&mut transaction, b"link", "foo")
3266 .await
3267 .expect("create_symlink failed");
3268 transaction.commit().await.expect("commit failed");
3269
3270 let link = store.read_symlink(symlink_id).await.expect("read_symlink failed");
3271 assert_eq!(&link, b"link");
3272 fs.close().await.expect("Close failed");
3273 }
3274
3275 #[fuchsia::test]
3276 async fn test_unlink_symlink() {
3277 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3278 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3279 let dir;
3280 let mut transaction = fs
3281 .clone()
3282 .new_transaction(lock_keys![], Options::default())
3283 .await
3284 .expect("new_transaction failed");
3285 let store = fs.root_store();
3286 dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3287
3288 let symlink_id = dir
3289 .create_symlink(&mut transaction, b"link", "foo")
3290 .await
3291 .expect("create_symlink failed");
3292 transaction.commit().await.expect("commit failed");
3293 transaction = fs
3294 .clone()
3295 .new_transaction(
3296 lock_keys![
3297 LockKey::object(store.store_object_id(), dir.object_id()),
3298 LockKey::object(store.store_object_id(), symlink_id),
3299 ],
3300 Options::default(),
3301 )
3302 .await
3303 .expect("new_transaction failed");
3304 assert_matches!(
3305 replace_child(&mut transaction, None, (&dir, "foo"))
3306 .await
3307 .expect("replace_child failed"),
3308 ReplacedChild::Object(_)
3309 );
3310 transaction.commit().await.expect("commit failed");
3311
3312 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3313 fs.close().await.expect("Close failed");
3314 }
3315
3316 #[fuchsia::test]
3317 async fn test_get_properties() {
3318 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3319 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3320 let dir;
3321 let mut transaction = fs
3322 .clone()
3323 .new_transaction(lock_keys![], Options::default())
3324 .await
3325 .expect("new_transaction failed");
3326
3327 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3328 .await
3329 .expect("create failed");
3330 transaction.commit().await.expect("commit failed");
3331
3332 let mut properties = dir.get_properties().await.expect("get_properties failed");
3334 let dir_creation_time = properties.creation_time;
3335 assert_eq!(dir_creation_time, properties.modification_time);
3336 assert_eq!(properties.sub_dirs, 0);
3337 assert!(properties.posix_attributes.is_none());
3338
3339 transaction = fs
3341 .clone()
3342 .new_transaction(
3343 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3344 Options::default(),
3345 )
3346 .await
3347 .expect("new_transaction failed");
3348 let child_dir =
3349 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3350 transaction.commit().await.expect("commit failed");
3351
3352 properties = dir.get_properties().await.expect("get_properties failed");
3354 assert_eq!(dir_creation_time, properties.creation_time);
3356 assert!(dir_creation_time < properties.modification_time);
3357 assert_eq!(properties.sub_dirs, 1);
3358 assert!(properties.posix_attributes.is_none());
3359
3360 properties = child_dir.get_properties().await.expect("get_properties failed");
3362 assert_eq!(properties.creation_time, properties.modification_time);
3363 assert_eq!(properties.sub_dirs, 0);
3364 assert!(properties.posix_attributes.is_none());
3365
3366 transaction = fs
3368 .clone()
3369 .new_transaction(
3370 lock_keys![LockKey::object(
3371 fs.root_store().store_object_id(),
3372 child_dir.object_id()
3373 )],
3374 Options::default(),
3375 )
3376 .await
3377 .expect("new_transaction failed");
3378 let child_dir_file = child_dir
3379 .create_child_file(&mut transaction, "bar")
3380 .await
3381 .expect("create_child_file failed");
3382 child_dir_file
3383 .update_attributes(
3384 &mut transaction,
3385 Some(&fio::MutableNodeAttributes { gid: Some(1), ..Default::default() }),
3386 None,
3387 )
3388 .await
3389 .expect("Updating attributes");
3390 transaction.commit().await.expect("commit failed");
3391
3392 properties = child_dir.get_properties().await.expect("get_properties failed");
3394 assert!(properties.creation_time < properties.modification_time);
3395 assert!(properties.posix_attributes.is_none());
3396
3397 properties = child_dir_file.get_properties().await.expect("get_properties failed");
3399 assert_eq!(properties.creation_time, properties.modification_time);
3400 assert_eq!(properties.sub_dirs, 0);
3401 assert!(properties.posix_attributes.is_some());
3402 assert_eq!(properties.posix_attributes.unwrap().gid, 1);
3403 assert_eq!(properties.posix_attributes.unwrap().uid, 0);
3405 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3406 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3407 }
3408
3409 #[fuchsia::test]
3410 async fn test_update_create_attributes() {
3411 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3412 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3413 let dir;
3414 let mut transaction = fs
3415 .clone()
3416 .new_transaction(lock_keys![], Options::default())
3417 .await
3418 .expect("new_transaction failed");
3419
3420 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3421 .await
3422 .expect("create failed");
3423 transaction.commit().await.expect("commit failed");
3424 let mut properties = dir.get_properties().await.expect("get_properties failed");
3425 assert_eq!(properties.sub_dirs, 0);
3426 assert!(properties.posix_attributes.is_none());
3427 let creation_time = properties.creation_time;
3428 let modification_time = properties.modification_time;
3429 assert_eq!(creation_time, modification_time);
3430
3431 transaction = fs
3437 .clone()
3438 .new_transaction(
3439 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3440 Options::default(),
3441 )
3442 .await
3443 .expect("new_transaction failed");
3444 let now = Timestamp::now();
3445 dir.update_attributes(
3446 transaction,
3447 Some(&fio::MutableNodeAttributes {
3448 modification_time: Some(now.as_nanos()),
3449 uid: Some(1),
3450 gid: Some(2),
3451 ..Default::default()
3452 }),
3453 0,
3454 None,
3455 )
3456 .await
3457 .expect("update_attributes failed");
3458 properties = dir.get_properties().await.expect("get_properties failed");
3459 assert_eq!(properties.modification_time, now);
3461 assert!(properties.posix_attributes.is_some());
3462 assert_eq!(properties.posix_attributes.unwrap().uid, 1);
3463 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3464 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3466 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3467 assert_eq!(properties.sub_dirs, 0);
3469 assert_eq!(properties.creation_time, creation_time);
3470
3471 let transaction = fs
3474 .clone()
3475 .new_transaction(
3476 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3477 Options::default(),
3478 )
3479 .await
3480 .expect("new_transaction failed");
3481 dir.update_attributes(
3482 transaction,
3483 Some(&fio::MutableNodeAttributes {
3484 creation_time: Some(now.as_nanos()),
3485 uid: Some(3),
3486 rdev: Some(10),
3487 ..Default::default()
3488 }),
3489 0,
3490 None,
3491 )
3492 .await
3493 .expect("update_attributes failed");
3494 properties = dir.get_properties().await.expect("get_properties failed");
3495 assert_eq!(properties.creation_time, now);
3496 assert!(properties.posix_attributes.is_some());
3497 assert_eq!(properties.posix_attributes.unwrap().uid, 3);
3498 assert_eq!(properties.posix_attributes.unwrap().rdev, 10);
3499 assert_eq!(properties.sub_dirs, 0);
3501 assert_eq!(properties.modification_time, now);
3502 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3503 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3504 }
3505
3506 #[fuchsia::test]
3507 async fn write_to_directory_attribute_creates_keys() {
3508 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3509 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3510 let crypt = Arc::new(new_insecure_crypt());
3511
3512 {
3513 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3514 let store = root_volume
3515 .new_volume(
3516 "vol",
3517 NewChildStoreOptions {
3518 options: StoreOptions {
3519 crypt: Some(crypt.clone()),
3520 ..StoreOptions::default()
3521 },
3522 ..Default::default()
3523 },
3524 )
3525 .await
3526 .expect("new_volume failed");
3527 let mut transaction = filesystem
3528 .clone()
3529 .new_transaction(
3530 lock_keys![LockKey::object(
3531 store.store_object_id(),
3532 store.root_directory_object_id()
3533 )],
3534 Options::default(),
3535 )
3536 .await
3537 .expect("new transaction failed");
3538 let root_directory = Directory::open(&store, store.root_directory_object_id())
3539 .await
3540 .expect("open failed");
3541 let directory = root_directory
3542 .create_child_dir(&mut transaction, "foo")
3543 .await
3544 .expect("create_child_dir failed");
3545 transaction.commit().await.expect("commit failed");
3546
3547 let mut transaction = filesystem
3548 .clone()
3549 .new_transaction(
3550 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
3551 Options::default(),
3552 )
3553 .await
3554 .expect("new transaction failed");
3555 let _ = directory
3556 .handle
3557 .write_attr(&mut transaction, 1, b"bar")
3558 .await
3559 .expect("write_attr failed");
3560 transaction.commit().await.expect("commit failed");
3561 }
3562
3563 filesystem.close().await.expect("Close failed");
3564 let device = filesystem.take_device().await;
3565 device.reopen(false);
3566 let filesystem = FxFilesystem::open(device).await.expect("open failed");
3567
3568 {
3569 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3570 let volume = root_volume
3571 .volume("vol", StoreOptions { crypt: Some(crypt), ..StoreOptions::default() })
3572 .await
3573 .expect("volume failed");
3574 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
3575 .await
3576 .expect("open failed");
3577 let directory = Directory::open(
3578 &volume,
3579 root_directory.lookup("foo").await.expect("lookup failed").expect("not found").0,
3580 )
3581 .await
3582 .expect("open failed");
3583 let mut buffer = directory.handle.allocate_buffer(10).await;
3584 assert_eq!(directory.handle.read(1, 0, buffer.as_mut()).await.expect("read failed"), 3);
3585 assert_eq!(&buffer.as_slice()[..3], b"bar");
3586 }
3587
3588 filesystem.close().await.expect("Close failed");
3589 }
3590
3591 #[fuchsia::test]
3592 async fn directory_with_extended_attributes() {
3593 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3594 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3595 let crypt = Arc::new(new_insecure_crypt());
3596
3597 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3598 let store = root_volume
3599 .new_volume(
3600 "vol",
3601 NewChildStoreOptions {
3602 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3603 ..Default::default()
3604 },
3605 )
3606 .await
3607 .expect("new_volume failed");
3608 let directory =
3609 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3610
3611 let test_small_name = b"security.selinux".to_vec();
3612 let test_small_value = b"foo".to_vec();
3613 let test_large_name = b"large.attribute".to_vec();
3614 let test_large_value = vec![1u8; 500];
3615
3616 directory
3617 .set_extended_attribute(
3618 test_small_name.clone(),
3619 test_small_value.clone(),
3620 SetExtendedAttributeMode::Set,
3621 )
3622 .await
3623 .unwrap();
3624 assert_eq!(
3625 directory.get_extended_attribute(test_small_name.clone()).await.unwrap(),
3626 test_small_value
3627 );
3628
3629 directory
3630 .set_extended_attribute(
3631 test_large_name.clone(),
3632 test_large_value.clone(),
3633 SetExtendedAttributeMode::Set,
3634 )
3635 .await
3636 .unwrap();
3637 assert_eq!(
3638 directory.get_extended_attribute(test_large_name.clone()).await.unwrap(),
3639 test_large_value
3640 );
3641
3642 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3643 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3644 .await
3645 .unwrap();
3646
3647 directory.remove_extended_attribute(test_small_name.clone()).await.unwrap();
3648 directory.remove_extended_attribute(test_large_name.clone()).await.unwrap();
3649
3650 filesystem.close().await.expect("close failed");
3651 }
3652
3653 #[fuchsia::test]
3654 async fn remove_directory_with_extended_attributes() {
3655 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3656 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3657 let crypt = Arc::new(new_insecure_crypt());
3658
3659 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3660 let store = root_volume
3661 .new_volume(
3662 "vol",
3663 NewChildStoreOptions {
3664 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3665 ..Default::default()
3666 },
3667 )
3668 .await
3669 .expect("new_volume failed");
3670 let mut transaction = filesystem
3671 .clone()
3672 .new_transaction(
3673 lock_keys![LockKey::object(
3674 store.store_object_id(),
3675 store.root_directory_object_id()
3676 )],
3677 Options::default(),
3678 )
3679 .await
3680 .expect("new transaction failed");
3681 let root_directory =
3682 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3683 let directory = root_directory
3684 .create_child_dir(&mut transaction, "foo")
3685 .await
3686 .expect("create_child_dir failed");
3687 transaction.commit().await.expect("commit failed");
3688
3689 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3690 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3691 .await
3692 .unwrap();
3693
3694 let test_small_name = b"security.selinux".to_vec();
3695 let test_small_value = b"foo".to_vec();
3696 let test_large_name = b"large.attribute".to_vec();
3697 let test_large_value = vec![1u8; 500];
3698
3699 directory
3700 .set_extended_attribute(
3701 test_small_name.clone(),
3702 test_small_value.clone(),
3703 SetExtendedAttributeMode::Set,
3704 )
3705 .await
3706 .unwrap();
3707 directory
3708 .set_extended_attribute(
3709 test_large_name.clone(),
3710 test_large_value.clone(),
3711 SetExtendedAttributeMode::Set,
3712 )
3713 .await
3714 .unwrap();
3715
3716 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3717 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3718 .await
3719 .unwrap();
3720
3721 let mut transaction = filesystem
3722 .clone()
3723 .new_transaction(
3724 lock_keys![
3725 LockKey::object(store.store_object_id(), root_directory.object_id()),
3726 LockKey::object(store.store_object_id(), directory.object_id()),
3727 ],
3728 Options::default(),
3729 )
3730 .await
3731 .expect("new_transaction failed");
3732 replace_child(&mut transaction, None, (&root_directory, "foo"))
3733 .await
3734 .expect("replace_child failed");
3735 transaction.commit().await.unwrap();
3736
3737 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3738 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3739 .await
3740 .unwrap();
3741
3742 filesystem.close().await.expect("close failed");
3743 }
3744
3745 #[fuchsia::test]
3746 async fn remove_symlink_with_extended_attributes() {
3747 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3748 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3749 let crypt = Arc::new(new_insecure_crypt());
3750
3751 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3752 let store = root_volume
3753 .new_volume(
3754 "vol",
3755 NewChildStoreOptions {
3756 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3757 ..Default::default()
3758 },
3759 )
3760 .await
3761 .expect("new_volume failed");
3762 let mut transaction = filesystem
3763 .clone()
3764 .new_transaction(
3765 lock_keys![LockKey::object(
3766 store.store_object_id(),
3767 store.root_directory_object_id()
3768 )],
3769 Options::default(),
3770 )
3771 .await
3772 .expect("new transaction failed");
3773 let root_directory =
3774 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3775 let symlink_id = root_directory
3776 .create_symlink(&mut transaction, b"somewhere/else", "foo")
3777 .await
3778 .expect("create_symlink failed");
3779 transaction.commit().await.expect("commit failed");
3780
3781 let symlink = StoreObjectHandle::new(
3782 store.clone(),
3783 symlink_id,
3784 false,
3785 HandleOptions::default(),
3786 false,
3787 );
3788
3789 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3790 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3791 .await
3792 .unwrap();
3793
3794 let test_small_name = b"security.selinux".to_vec();
3795 let test_small_value = b"foo".to_vec();
3796 let test_large_name = b"large.attribute".to_vec();
3797 let test_large_value = vec![1u8; 500];
3798
3799 symlink
3800 .set_extended_attribute(
3801 test_small_name.clone(),
3802 test_small_value.clone(),
3803 SetExtendedAttributeMode::Set,
3804 )
3805 .await
3806 .unwrap();
3807 symlink
3808 .set_extended_attribute(
3809 test_large_name.clone(),
3810 test_large_value.clone(),
3811 SetExtendedAttributeMode::Set,
3812 )
3813 .await
3814 .unwrap();
3815
3816 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3817 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3818 .await
3819 .unwrap();
3820
3821 let mut transaction = filesystem
3822 .clone()
3823 .new_transaction(
3824 lock_keys![
3825 LockKey::object(store.store_object_id(), root_directory.object_id()),
3826 LockKey::object(store.store_object_id(), symlink.object_id()),
3827 ],
3828 Options::default(),
3829 )
3830 .await
3831 .expect("new_transaction failed");
3832 replace_child(&mut transaction, None, (&root_directory, "foo"))
3833 .await
3834 .expect("replace_child failed");
3835 transaction.commit().await.unwrap();
3836
3837 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3838 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3839 .await
3840 .unwrap();
3841
3842 filesystem.close().await.expect("close failed");
3843 }
3844
3845 #[fuchsia::test]
3846 async fn test_update_timestamps() {
3847 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3848 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3849 let dir;
3850 let mut transaction = fs
3851 .clone()
3852 .new_transaction(lock_keys![], Options::default())
3853 .await
3854 .expect("new_transaction failed");
3855
3856 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3859 .await
3860 .expect("create failed");
3861 transaction.commit().await.expect("commit failed");
3862 let mut properties = dir.get_properties().await.expect("get_properties failed");
3863 let starting_time = properties.creation_time;
3864 assert_eq!(properties.creation_time, starting_time);
3865 assert_eq!(properties.modification_time, starting_time);
3866 assert_eq!(properties.change_time, starting_time);
3867 assert_eq!(properties.access_time, starting_time);
3868
3869 transaction = fs
3871 .clone()
3872 .new_transaction(
3873 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3874 Options::default(),
3875 )
3876 .await
3877 .expect("new_transaction failed");
3878 let update1_time = Timestamp::now();
3879 dir.update_attributes(
3880 transaction,
3881 Some(&fio::MutableNodeAttributes {
3882 modification_time: Some(update1_time.as_nanos()),
3883 ..Default::default()
3884 }),
3885 0,
3886 Some(update1_time),
3887 )
3888 .await
3889 .expect("update_attributes failed");
3890 properties = dir.get_properties().await.expect("get_properties failed");
3891 assert_eq!(properties.modification_time, update1_time);
3892 assert_eq!(properties.access_time, starting_time);
3893 assert_eq!(properties.creation_time, starting_time);
3894 assert_eq!(properties.change_time, update1_time);
3895 }
3896
3897 #[fuchsia::test]
3898 async fn test_move_dir_timestamps() {
3899 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3900 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3901 let dir;
3902 let child1;
3903 let child2;
3904 let mut transaction = fs
3905 .clone()
3906 .new_transaction(lock_keys![], Options::default())
3907 .await
3908 .expect("new_transaction failed");
3909 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3910 .await
3911 .expect("create failed");
3912 child1 = dir
3913 .create_child_dir(&mut transaction, "child1")
3914 .await
3915 .expect("create_child_dir failed");
3916 child2 = dir
3917 .create_child_dir(&mut transaction, "child2")
3918 .await
3919 .expect("create_child_dir failed");
3920 transaction.commit().await.expect("commit failed");
3921 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3922 let child2_properties = child2.get_properties().await.expect("get_properties failed");
3923
3924 transaction = fs
3926 .clone()
3927 .new_transaction(
3928 lock_keys![
3929 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3930 LockKey::object(fs.root_store().store_object_id(), child1.object_id()),
3931 LockKey::object(fs.root_store().store_object_id(), child2.object_id()),
3932 ],
3933 Options::default(),
3934 )
3935 .await
3936 .expect("new_transaction failed");
3937 assert_matches!(
3938 replace_child(&mut transaction, Some((&dir, "child2")), (&child1, "child2"))
3939 .await
3940 .expect("replace_child failed"),
3941 ReplacedChild::None
3942 );
3943 transaction.commit().await.expect("commit failed");
3944 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
3946 let time_of_replacement = new_dir_properties.change_time;
3947 assert!(new_dir_properties.change_time > dir_properties.change_time);
3948 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
3949 let new_child1_properties = child1.get_properties().await.expect("get_properties failed");
3951 assert_eq!(new_child1_properties.modification_time, time_of_replacement);
3952 assert_eq!(new_child1_properties.change_time, time_of_replacement);
3953 let moved_child2_properties = child2.get_properties().await.expect("get_properties failed");
3955 assert_eq!(moved_child2_properties.change_time, time_of_replacement);
3956 assert_eq!(moved_child2_properties.creation_time, child2_properties.creation_time);
3957 assert_eq!(moved_child2_properties.access_time, child2_properties.access_time);
3958 assert_eq!(moved_child2_properties.modification_time, child2_properties.modification_time);
3959 fs.close().await.expect("Close failed");
3960 }
3961
3962 #[fuchsia::test]
3963 async fn test_unlink_timestamps() {
3964 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3965 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3966 let dir;
3967 let foo;
3968 let mut transaction = fs
3969 .clone()
3970 .new_transaction(lock_keys![], Options::default())
3971 .await
3972 .expect("new_transaction failed");
3973 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3974 .await
3975 .expect("create failed");
3976 foo =
3977 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_dir failed");
3978
3979 transaction.commit().await.expect("commit failed");
3980 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3981 let foo_properties = foo.get_properties().await.expect("get_properties failed");
3982
3983 transaction = fs
3984 .clone()
3985 .new_transaction(
3986 lock_keys![
3987 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3988 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3989 ],
3990 Options::default(),
3991 )
3992 .await
3993 .expect("new_transaction failed");
3994 assert_matches!(
3995 replace_child(&mut transaction, None, (&dir, "foo"))
3996 .await
3997 .expect("replace_child failed"),
3998 ReplacedChild::Object(_)
3999 );
4000 transaction.commit().await.expect("commit failed");
4001 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
4003 let time_of_replacement = new_dir_properties.change_time;
4004 assert!(new_dir_properties.change_time > dir_properties.change_time);
4005 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
4006 let moved_foo_properties = foo.get_properties().await.expect("get_properties failed");
4008 assert_eq!(moved_foo_properties.change_time, time_of_replacement);
4009 assert_eq!(moved_foo_properties.creation_time, foo_properties.creation_time);
4010 assert_eq!(moved_foo_properties.access_time, foo_properties.access_time);
4011 assert_eq!(moved_foo_properties.modification_time, foo_properties.modification_time);
4012 fs.close().await.expect("Close failed");
4013 }
4014
4015 #[fuchsia::test]
4016 async fn test_replace_dir_timestamps() {
4017 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4018 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4019 let dir;
4020 let child_dir1;
4021 let child_dir2;
4022 let foo;
4023 let mut transaction = fs
4024 .clone()
4025 .new_transaction(lock_keys![], Options::default())
4026 .await
4027 .expect("new_transaction failed");
4028 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4029 .await
4030 .expect("create failed");
4031 child_dir1 =
4032 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
4033 child_dir2 =
4034 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
4035 foo = child_dir1
4036 .create_child_dir(&mut transaction, "foo")
4037 .await
4038 .expect("create_child_dir failed");
4039 transaction.commit().await.expect("commit failed");
4040 let dir_props = dir.get_properties().await.expect("get_properties failed");
4041 let foo_props = foo.get_properties().await.expect("get_properties failed");
4042
4043 transaction = fs
4044 .clone()
4045 .new_transaction(
4046 lock_keys![
4047 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4048 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
4049 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
4050 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
4051 ],
4052 Options::default(),
4053 )
4054 .await
4055 .expect("new_transaction failed");
4056 assert_matches!(
4057 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&dir, "dir2"))
4058 .await
4059 .expect("replace_child failed"),
4060 ReplacedChild::Directory(_)
4061 );
4062 transaction.commit().await.expect("commit failed");
4063 let new_dir_props = dir.get_properties().await.expect("get_properties failed");
4065 let time_of_replacement = new_dir_props.change_time;
4066 assert!(new_dir_props.change_time > dir_props.change_time);
4067 assert_eq!(new_dir_props.modification_time, time_of_replacement);
4068 let new_dir1_props = child_dir1.get_properties().await.expect("get_properties failed");
4070 let time_of_replacement = new_dir1_props.change_time;
4071 assert_eq!(new_dir1_props.change_time, time_of_replacement);
4072 assert_eq!(new_dir1_props.modification_time, time_of_replacement);
4073 let moved_foo_props = foo.get_properties().await.expect("get_properties failed");
4075 assert_eq!(moved_foo_props.change_time, time_of_replacement);
4076 assert_eq!(moved_foo_props.creation_time, foo_props.creation_time);
4077 assert_eq!(moved_foo_props.access_time, foo_props.access_time);
4078 assert_eq!(moved_foo_props.modification_time, foo_props.modification_time);
4079 fs.close().await.expect("Close failed");
4080 }
4081
4082 #[fuchsia::test]
4083 async fn test_create_casefold_directory() {
4084 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4085 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4086 let object_id = {
4087 let mut transaction = fs
4088 .clone()
4089 .new_transaction(lock_keys![], Options::default())
4090 .await
4091 .expect("new_transaction failed");
4092 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
4093 .await
4094 .expect("create failed");
4095
4096 let child_dir = dir
4097 .create_child_dir(&mut transaction, "foo")
4098 .await
4099 .expect("create_child_dir failed");
4100 let _child_dir_file = child_dir
4101 .create_child_file(&mut transaction, "bAr")
4102 .await
4103 .expect("create_child_file failed");
4104 transaction.commit().await.expect("commit failed");
4105 dir.object_id()
4106 };
4107 fs.close().await.expect("Close failed");
4108 let device = fs.take_device().await;
4109
4110 device.reopen(false);
4113 let fs = FxFilesystem::open(device).await.expect("open failed");
4114 {
4115 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4116 let (object_id, object_descriptor, _) =
4117 dir.lookup("foo").await.expect("lookup failed").expect("not found");
4118 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
4119 let child_dir =
4120 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4121 assert!(!child_dir.dir_type().is_casefold());
4122 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_none());
4123 let (object_id, descriptor, _) =
4124 child_dir.lookup("bAr").await.expect("lookup failed").unwrap();
4125 assert_eq!(descriptor, ObjectDescriptor::File);
4126
4127 child_dir.set_casefold(true).await.expect_err("not empty");
4129
4130 let mut transaction = fs
4132 .clone()
4133 .new_transaction(
4134 lock_keys![
4135 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
4136 LockKey::object(fs.root_store().store_object_id(), object_id),
4137 ],
4138 Options::default(),
4139 )
4140 .await
4141 .expect("new_transaction failed");
4142 assert_matches!(
4143 replace_child(&mut transaction, None, (&child_dir, "bAr"))
4144 .await
4145 .expect("replace_child failed"),
4146 ReplacedChild::Object(..)
4147 );
4148 transaction.commit().await.expect("commit failed");
4149
4150 child_dir.set_casefold(true).await.expect("set casefold");
4152
4153 assert!(child_dir.dir_type().is_casefold());
4154
4155 let mut transaction = fs
4157 .clone()
4158 .new_transaction(
4159 lock_keys![LockKey::object(
4160 fs.root_store().store_object_id(),
4161 child_dir.object_id()
4162 ),],
4163 Options::default(),
4164 )
4165 .await
4166 .expect("new_transaction failed");
4167 let _child_dir_file = child_dir
4168 .create_child_file(&mut transaction, "bAr")
4169 .await
4170 .expect("create_child_file failed");
4171 transaction.commit().await.expect("commit failed");
4172
4173 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_some());
4175 assert!(child_dir.lookup("bAr").await.expect("lookup failed").is_some());
4176
4177 child_dir.set_casefold(true).await.expect_err("set casefold");
4179 assert!(child_dir.dir_type().is_casefold());
4180
4181 let mut transaction = fs
4183 .clone()
4184 .new_transaction(
4185 lock_keys![LockKey::object(
4186 fs.root_store().store_object_id(),
4187 child_dir.object_id()
4188 ),],
4189 Options::default(),
4190 )
4191 .await
4192 .expect("new_transaction failed");
4193 let sub_dir = child_dir
4194 .create_child_dir(&mut transaction, "sub")
4195 .await
4196 .expect("create_sub_dir failed");
4197 transaction.commit().await.expect("commit failed");
4198 assert!(sub_dir.dir_type().is_casefold());
4199 };
4200 fs.close().await.expect("Close failed");
4201 }
4202
4203 #[fuchsia::test]
4204 async fn test_create_casefold_encrypted_directory() {
4205 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4206 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4207 let proxy_filename: ProxyFilename;
4208 let object_id;
4209 {
4210 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4211 let root_volume = root_volume(fs.clone()).await.unwrap();
4212 let store = root_volume
4213 .new_volume(
4214 "vol",
4215 NewChildStoreOptions {
4216 options: StoreOptions {
4217 crypt: Some(crypt.clone()),
4218 ..StoreOptions::default()
4219 },
4220 ..Default::default()
4221 },
4222 )
4223 .await
4224 .unwrap();
4225
4226 crypt
4228 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4229 .expect("add wrapping key failed");
4230
4231 object_id = {
4232 let mut transaction = fs
4233 .clone()
4234 .new_transaction(lock_keys![], Options::default())
4235 .await
4236 .expect("new_transaction failed");
4237 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4238 .await
4239 .expect("create failed");
4240
4241 transaction.commit().await.expect("commit");
4242 dir.object_id()
4243 };
4244 let dir = Directory::open(&store, object_id).await.expect("open failed");
4245
4246 dir.set_casefold(true).await.expect("set casefold");
4247 assert!(dir.dir_type().is_casefold());
4248
4249 let mut transaction = fs
4250 .clone()
4251 .new_transaction(
4252 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4253 Options::default(),
4254 )
4255 .await
4256 .expect("new_transaction failed");
4257 let _file = dir
4258 .create_child_file(&mut transaction, "bAr")
4259 .await
4260 .expect("create_child_file failed");
4261 transaction.commit().await.expect("commit failed");
4262
4263 assert!(dir.lookup("bAr").await.expect("original lookup failed").is_some());
4265
4266 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4269 let encrypted_name =
4270 encrypt_filename(&*key, dir.object_id(), "bAr").expect("encrypt_filename");
4271 let hash_code = key.hash_code_casefold("bAr");
4272 proxy_filename = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4273
4274 assert!(dir.lookup("BAR").await.expect("casefold lookup failed").is_some());
4276
4277 assert_eq!(key.hash_code_casefold("bar"), key.hash_code_casefold("BaR"));
4279
4280 let mut count = 0;
4283 let layer_set = dir.store().tree().layer_set();
4284 let mut merger = layer_set.merger();
4285 let mut iter = dir.iter(&mut merger).await.expect("iter");
4286 while let Some(_entry) = iter.get() {
4287 count += 1;
4288 iter.advance().await.expect("advance");
4289 }
4290 assert_eq!(1, count, "unexpected number of entries.");
4291
4292 fs.close().await.expect("Close failed");
4293 }
4294
4295 let device = fs.take_device().await;
4296
4297 device.reopen(false);
4300 let fs = FxFilesystem::open(device).await.expect("open failed");
4301 {
4302 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4303 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4304 let store = root_volume
4305 .volume(
4306 "vol",
4307 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4308 )
4309 .await
4310 .expect("volume failed");
4311 let dir = Directory::open(&store, object_id).await.expect("open failed");
4312 assert!(dir.dir_type().is_casefold());
4313
4314 assert!(dir.lookup("bAr").await.expect("lookup failed").is_none());
4316 let filename: String = proxy_filename.into();
4318 assert!(dir.lookup(&filename).await.expect("lookup failed").is_some());
4319
4320 let layer_set = dir.store().tree().layer_set();
4321 let mut merger = layer_set.merger();
4322 let mut iter = dir.iter(&mut merger).await.expect("iter");
4323 let item = iter.get().expect("expect item");
4324 let filename: String = proxy_filename.into();
4325 assert_eq!(item.0, &filename);
4326 iter.advance().await.expect("advance");
4327 assert_eq!(None, iter.get());
4328
4329 crate::fsck::fsck(fs.clone()).await.unwrap();
4330 crate::fsck::fsck_volume(fs.as_ref(), store.store_object_id(), Some(crypt.clone()))
4331 .await
4332 .unwrap();
4333
4334 fs.close().await.expect("Close failed");
4335 }
4336 }
4337
4338 #[allow(dead_code)]
4349 fn find_out_of_order_sha256_long_prefix_pair(
4350 object_id: u64,
4351 key: &Arc<dyn Cipher>,
4352 ) -> Option<[String; 2]> {
4353 let mut collision_map: std::collections::HashMap<u32, (usize, ProxyFilename, Vec<u8>)> =
4354 std::collections::HashMap::new();
4355 for i in 0..(1usize << 32) {
4356 let filename = format!("{:0>176}_{i}", 0);
4357 let encrypted_name =
4358 encrypt_filename(&**key, object_id, &filename).expect("encrypt_filename");
4359 let hash_code = key.hash_code_casefold(&filename);
4360 let a = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4361 let hash_code = a.hash_code as u32;
4362 if let Some((j, b, b_encrypted_name)) = collision_map.get(&hash_code) {
4363 assert_eq!(a.filename, b.filename);
4364 if encrypted_name.cmp(b_encrypted_name) != a.sha256.cmp(&b.sha256) {
4365 return Some([format!("{:0>176}_{i}", 0), format!("{:0>176}_{j}", 0)]);
4366 }
4367 } else {
4368 collision_map.insert(hash_code, (i, a, encrypted_name));
4369 }
4370 }
4371 None
4372 }
4373
4374 #[fuchsia::test]
4375 async fn test_proxy_filename() {
4376 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4377 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4378 let mut filenames = Vec::new();
4379 let object_id;
4380 {
4381 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4382 let root_volume = root_volume(fs.clone()).await.unwrap();
4383 let store = root_volume
4384 .new_volume(
4385 "vol",
4386 NewChildStoreOptions {
4387 options: StoreOptions {
4388 crypt: Some(crypt.clone()),
4389 ..StoreOptions::default()
4390 },
4391 ..Default::default()
4392 },
4393 )
4394 .await
4395 .unwrap();
4396
4397 crypt
4399 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4400 .expect("add wrapping key failed");
4401
4402 object_id = {
4403 let mut transaction = fs
4404 .clone()
4405 .new_transaction(lock_keys![], Options::default())
4406 .await
4407 .expect("new_transaction failed");
4408 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4409 .await
4410 .expect("create failed");
4411
4412 transaction.commit().await.expect("commit");
4413 dir.object_id()
4414 };
4415
4416 let dir = Directory::open(&store, object_id).await.expect("open failed");
4417
4418 dir.set_casefold(true).await.expect("set casefold");
4419 assert!(dir.dir_type().is_casefold());
4420
4421 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4422
4423 let collision_pair =
4433 [format!("{:0>176}_{}", 0, 93515), format!("{:0>176}_{}", 0, 15621)];
4434
4435 for filename in (0..64)
4438 .into_iter()
4439 .map(|i| format!("{:0>176}_{i}", 0))
4440 .chain(collision_pair.into_iter())
4441 {
4442 let hash_code = key.hash_code_casefold(&filename);
4443 let encrypted_name =
4444 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
4445 let proxy_filename =
4446 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4447 let mut transaction = fs
4448 .clone()
4449 .new_transaction(
4450 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4451 Options::default(),
4452 )
4453 .await
4454 .expect("new_transaction failed");
4455 let file = dir
4456 .create_child_file(&mut transaction, &filename)
4457 .await
4458 .expect("create_child_file failed");
4459 filenames.push((proxy_filename, file.object_id()));
4460 transaction.commit().await.expect("commit failed");
4461 }
4462
4463 fs.close().await.expect("Close failed");
4464 }
4465
4466 let device = fs.take_device().await;
4467
4468 device.reopen(false);
4470 let fs = FxFilesystem::open(device).await.expect("open failed");
4471 {
4472 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4473 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4474 let store = root_volume
4475 .volume(
4476 "vol",
4477 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4478 )
4479 .await
4480 .expect("volume failed");
4481 let dir = Directory::open(&store, object_id).await.expect("open failed");
4482 assert!(dir.dir_type().is_casefold());
4483
4484 assert_eq!(
4486 filenames.iter().map(|(name, _)| (*name).into()).collect::<HashSet<String>>().len(),
4487 filenames.len()
4488 );
4489
4490 let filename = filenames[0].0.filename.clone();
4491 for (proxy_filename, object_id) in &filenames {
4492 assert_eq!(filename, proxy_filename.filename);
4494
4495 let proxy_filename_str: String = (*proxy_filename).into();
4496 let item = dir
4497 .lookup(&proxy_filename_str)
4498 .await
4499 .expect("lookup failed")
4500 .expect("lookup is not None");
4501 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4502 }
4503
4504 fs.close().await.expect("Close failed");
4505 }
4506 }
4507
4508 #[fuchsia::test]
4509 async fn test_replace_directory_and_tombstone_on_remount() {
4510 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
4511 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4512 let crypt = Arc::new(new_insecure_crypt());
4513 {
4514 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4515 let store = root_volume
4516 .new_volume(
4517 "test",
4518 NewChildStoreOptions {
4519 options: StoreOptions {
4520 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4521 ..StoreOptions::default()
4522 },
4523 ..Default::default()
4524 },
4525 )
4526 .await
4527 .expect("new_volume failed");
4528
4529 let mut transaction = fs
4530 .clone()
4531 .new_transaction(
4532 lock_keys![LockKey::object(
4533 store.store_object_id(),
4534 store.root_directory_object_id()
4535 )],
4536 Options::default(),
4537 )
4538 .await
4539 .expect("new transaction failed");
4540
4541 let root_directory = Directory::open(&store, store.root_directory_object_id())
4542 .await
4543 .expect("open failed");
4544 let _directory = root_directory
4545 .create_child_dir(&mut transaction, "foo")
4546 .await
4547 .expect("create_child_dir failed");
4548 let directory = root_directory
4549 .create_child_dir(&mut transaction, "bar")
4550 .await
4551 .expect("create_child_dir failed");
4552 let oid = directory.object_id();
4553
4554 transaction.commit().await.expect("commit failed");
4555
4556 let mut transaction = fs
4557 .clone()
4558 .new_transaction(
4559 lock_keys![LockKey::object(
4560 store.store_object_id(),
4561 store.root_directory_object_id()
4562 )],
4563 Options::default(),
4564 )
4565 .await
4566 .expect("new transaction failed");
4567
4568 replace_child_with_object(
4569 &mut transaction,
4570 Some((oid, ObjectDescriptor::Directory)),
4571 (&root_directory, "foo"),
4572 0,
4573 Timestamp::now(),
4574 )
4575 .await
4576 .expect("replace_child_with_object failed");
4577
4578 yield_to_executor().await;
4582
4583 transaction.commit().await.expect("commit failed");
4584
4585 fs.close().await.expect("close failed");
4586 }
4587
4588 let device = fs.take_device().await;
4589 device.reopen(false);
4590 let fs = FxFilesystem::open(device).await.expect("open failed");
4591 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4592 let _store = root_volume
4593 .volume(
4594 "test",
4595 StoreOptions {
4596 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4597 ..StoreOptions::default()
4598 },
4599 )
4600 .await
4601 .expect("new_volume failed");
4602
4603 yield_to_executor().await;
4605
4606 fs.close().await.expect("close failed");
4607 }
4608
4609 #[test_case(false; "non_casefold")]
4610 #[test_case(true; "casefold")]
4611 #[fuchsia::test]
4612 async fn test_lookup_long_filename_in_locked_directory(casefold: bool) {
4613 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4614 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4615 let object_id;
4616 let mut filenames = Vec::new();
4617 {
4618 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4619 let root_volume = root_volume(fs.clone()).await.unwrap();
4620 let store = root_volume
4621 .new_volume(
4622 "vol",
4623 NewChildStoreOptions {
4624 options: StoreOptions {
4625 crypt: Some(crypt.clone()),
4626 ..StoreOptions::default()
4627 },
4628 ..Default::default()
4629 },
4630 )
4631 .await
4632 .unwrap();
4633
4634 crypt
4635 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4636 .expect("add_wrapping_key failed");
4637
4638 object_id = {
4639 let mut transaction = fs
4640 .clone()
4641 .new_transaction(lock_keys![], Options::default())
4642 .await
4643 .expect("new_transaction failed");
4644 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4645 .await
4646 .expect("create failed");
4647
4648 transaction.commit().await.expect("commit");
4649 dir.object_id()
4650 };
4651 let dir = Directory::open(&store, object_id).await.expect("open failed");
4652 if casefold {
4653 dir.set_casefold(true).await.expect("set casefold");
4654 }
4655
4656 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4657
4658 for len in [144, 145, 255] {
4659 let filename = "a".repeat(len);
4660 let encrypted_name =
4661 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
4662 let proxy_filename = if casefold {
4663 let hash_code = key.hash_code_casefold(&filename);
4664 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name)
4665 } else {
4666 ProxyFilename::new(&encrypted_name)
4667 };
4668 let mut transaction = fs
4669 .clone()
4670 .new_transaction(
4671 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4672 Options::default(),
4673 )
4674 .await
4675 .expect("new_transaction failed");
4676 let file = dir
4677 .create_child_file(&mut transaction, &filename)
4678 .await
4679 .expect("create_child_file failed");
4680 filenames.push((proxy_filename, file.object_id()));
4681 transaction.commit().await.expect("commit failed");
4682 }
4683
4684 fs.close().await.expect("Close failed");
4685 }
4686
4687 let device = fs.take_device().await;
4688 device.reopen(false);
4689 let fs = FxFilesystem::open(device).await.expect("open failed");
4690 {
4691 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4692 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4693 let store = root_volume
4694 .volume(
4695 "vol",
4696 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4697 )
4698 .await
4699 .expect("volume failed");
4700 let dir = Directory::open(&store, object_id).await.expect("open failed");
4701
4702 let layer_set = dir.store().tree().layer_set();
4704 let mut merger = layer_set.merger();
4705 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
4706 let mut entries = Vec::new();
4707 while let Some((name, _, _)) = iter.get() {
4708 entries.push(name.to_string());
4709 iter.advance().await.expect("advance failed");
4710 }
4711 assert_eq!(entries.len(), filenames.len());
4712
4713 for (proxy_filename, object_id) in &filenames {
4714 let proxy_filename_str: String = (*proxy_filename).into();
4715 assert!(entries.contains(&proxy_filename_str));
4716 let item = dir
4717 .lookup(&proxy_filename_str)
4718 .await
4719 .expect("lookup failed")
4720 .expect("lookup is not None");
4721 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4722 }
4723
4724 fs.close().await.expect("Close failed");
4725 }
4726 }
4727
4728 #[fuchsia::test]
4729 async fn test_lookup_cached_entry_after_unlock() {
4730 const FILENAME: &str = "foo";
4731 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4732 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4733 let object_id;
4734 let proxy_filename;
4735 {
4736 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4737 let root_volume = root_volume(fs.clone()).await.unwrap();
4738 let store = root_volume
4739 .new_volume(
4740 "vol",
4741 NewChildStoreOptions {
4742 options: StoreOptions {
4743 crypt: Some(crypt.clone()),
4744 ..StoreOptions::default()
4745 },
4746 ..Default::default()
4747 },
4748 )
4749 .await
4750 .unwrap();
4751
4752 crypt
4753 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4754 .expect("add_wrapping_key failed");
4755
4756 let mut transaction = fs
4757 .clone()
4758 .new_transaction(lock_keys![], Options::default())
4759 .await
4760 .expect("new_transaction failed");
4761 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4762 .await
4763 .expect("create failed");
4764 transaction.commit().await.expect("commit");
4765 object_id = dir.object_id();
4766
4767 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4768 let encrypted_name =
4769 encrypt_filename(&*key, object_id, FILENAME).expect("encrypt_filename");
4770 proxy_filename = ProxyFilename::new(&encrypted_name);
4771
4772 let mut transaction = fs
4773 .clone()
4774 .new_transaction(
4775 lock_keys![LockKey::object(store.store_object_id(), object_id),],
4776 Options::default(),
4777 )
4778 .await
4779 .expect("new_transaction failed");
4780 dir.create_child_file(&mut transaction, FILENAME)
4781 .await
4782 .expect("create_child_file failed");
4783 transaction.commit().await.expect("commit failed");
4784
4785 fs.close().await.expect("Close failed");
4786 }
4787
4788 let device = fs.take_device().await;
4789 device.reopen(false);
4790 let fs = FxFilesystem::open(device).await.expect("open failed");
4791 {
4792 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4793 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4794 let store = root_volume
4795 .volume(
4796 "vol",
4797 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4798 )
4799 .await
4800 .expect("volume failed");
4801 let dir = Directory::open(&store, object_id).await.expect("open failed");
4802
4803 let proxy_filename_str: String = proxy_filename.into();
4804 dir.lookup(&proxy_filename_str)
4806 .await
4807 .expect("lookup failed")
4808 .expect("lookup is not None");
4809
4810 crypt
4811 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4812 .expect("add_wrapping_key failed");
4813
4814 assert!(dir.lookup(&proxy_filename_str).await.expect("lookup failed").is_none());
4817
4818 fs.close().await.expect("Close failed");
4819 }
4820 }
4821
4822 #[test_case(false, false; "no_encryption_no_casefold")]
4823 #[test_case(false, true; "no_encryption_casefold")]
4824 #[test_case(true, false; "encryption_no_casefold")]
4825 #[test_case(true, true; "encryption_casefold")]
4826 #[fuchsia::test]
4827 async fn test_traversal_position(encrypted: bool, casefold: bool) {
4828 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4829 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4830 {
4831 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4832 let crypt = Arc::new(new_insecure_crypt());
4833 crypt
4834 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4835 .expect("add_wrapping_key failed");
4836 let store = root_volume
4837 .new_volume(
4838 "test",
4839 NewChildStoreOptions {
4840 options: StoreOptions {
4841 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4842 ..StoreOptions::default()
4843 },
4844 ..Default::default()
4845 },
4846 )
4847 .await
4848 .expect("new_volume failed");
4849 let mut root_dir = Directory::open(&store, store.root_directory_object_id())
4850 .await
4851 .expect("open failed");
4852 if encrypted {
4853 let mut transaction = fs
4854 .clone()
4855 .new_transaction(
4856 lock_keys![LockKey::object(
4857 store.store_object_id(),
4858 store.root_directory_object_id()
4859 )],
4860 Options::default(),
4861 )
4862 .await
4863 .expect("new_transaction failed");
4864 root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await.unwrap();
4865 transaction.commit().await.unwrap();
4866
4867 root_dir = Directory::open(&store, store.root_directory_object_id())
4869 .await
4870 .expect("open failed");
4871 }
4872 if casefold {
4873 root_dir.set_casefold(true).await.unwrap();
4874 }
4875
4876 let mut transaction = fs
4877 .clone()
4878 .new_transaction(
4879 lock_keys![LockKey::object(
4880 store.store_object_id(),
4881 store.root_directory_object_id()
4882 )],
4883 Options::default(),
4884 )
4885 .await
4886 .expect("new_transaction failed");
4887 let _ = root_dir.create_child_file(&mut transaction, "foo").await.unwrap();
4888 transaction.commit().await.unwrap();
4889
4890 let layer_set = store.tree().layer_set();
4891 let mut merger = layer_set.merger();
4892 let iter = root_dir.iter(&mut merger).await.expect("iter failed");
4893 let pos =
4894 iter.traversal_position(|name| name.to_string(), |bytes| format!("{:?}", bytes));
4895 assert!(
4896 pos.is_some(),
4897 "traversal_position returned None for encrypted={}, casefold={}",
4898 encrypted,
4899 casefold
4900 );
4901 }
4902 fs.close().await.expect("close failed");
4903 }
4904}