1use crate::errors::FxfsError;
6use crate::lsm_tree::merge::{Merger, MergerIterator};
7use crate::lsm_tree::types::{Item, ItemRef, LayerIterator};
8use crate::lsm_tree::Query;
9use crate::object_handle::{ObjectHandle, ObjectProperties, INVALID_OBJECT_ID};
10use crate::object_store::key_manager::ToCipherSet;
11use crate::object_store::object_record::{
12 ChildValue, ObjectAttributes, ObjectDescriptor, ObjectItem, ObjectKey, ObjectKeyData,
13 ObjectKind, ObjectValue, Timestamp,
14};
15use crate::object_store::transaction::{
16 lock_keys, LockKey, LockKeys, Mutation, Options, Transaction,
17};
18use crate::object_store::{
19 DataObjectHandle, EncryptionKeys, HandleOptions, HandleOwner, ObjectStore,
20 SetExtendedAttributeMode, StoreObjectHandle,
21};
22use anyhow::{anyhow, bail, ensure, Context, Error};
23use fidl_fuchsia_io as fio;
24use fscrypt::proxy_filename::ProxyFilename;
25use fuchsia_sync::Mutex;
26use fxfs_crypto::{Cipher, CipherSet, Key, WrappedKeys};
27use std::fmt;
28use std::hash::{Hash, Hasher};
29use std::sync::atomic::{AtomicBool, Ordering};
30use std::sync::Arc;
31use zerocopy::IntoBytes;
32
33use super::FSCRYPT_KEY_ID;
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 casefold: AtomicBool,
50 wrapping_key_id: Mutex<Option<u128>>,
51}
52
53#[derive(Clone, Default)]
54pub struct MutableAttributesInternal {
55 sub_dirs: i64,
56 change_time: Option<Timestamp>,
57 modification_time: Option<u64>,
58 creation_time: Option<u64>,
59}
60
61impl MutableAttributesInternal {
62 pub fn new(
63 sub_dirs: i64,
64 change_time: Option<Timestamp>,
65 modification_time: Option<u64>,
66 creation_time: Option<u64>,
67 ) -> Self {
68 Self { sub_dirs, change_time, modification_time, creation_time }
69 }
70}
71
72fn get_casefold_hash(key: Option<&Key>, name: &str, casefold: bool) -> u32 {
85 if name == "" {
87 return 0;
88 }
89 let mut hasher = rustc_hash::FxHasher::default();
90 if casefold {
91 for ch in fxfs_unicode::casefold(name.chars()) {
92 ch.hash(&mut hasher);
93 }
94 } else {
95 name.hash(&mut hasher);
96 }
97 let mut hash = hasher.finish() as u32;
98 if let Some(key) = key {
99 key.encrypt(0, hash.as_mut_bytes()).unwrap();
100 }
101 hash
102}
103
104fn encrypt_filename(key: &Key, object_id: u64, name: &str) -> Result<Vec<u8>, Error> {
106 let mut name_bytes = name.to_string().into_bytes();
107 key.encrypt_filename(object_id, &mut name_bytes)?;
108 Ok(name_bytes)
109}
110
111fn decrypt_filename(key: &Key, object_id: u64, data: &Vec<u8>) -> Result<String, Error> {
113 let mut raw = data.clone();
114 key.decrypt_filename(object_id, &mut raw)?;
115 Ok(String::from_utf8(raw)?)
116}
117
118fn proxy_filename_to_query_key(proxy: &ProxyFilename, object_id: u64) -> ObjectKey {
124 let mut filename = proxy.filename.to_vec();
125 while let Some(0) = filename.last() {
126 filename.pop();
127 }
128 ObjectKey::encrypted_child(object_id, filename, proxy.hash_code as u32)
129}
130
131#[fxfs_trace::trace]
132impl<S: HandleOwner> Directory<S> {
133 fn new(owner: Arc<S>, object_id: u64, wrapping_key_id: Option<u128>, casefold: bool) -> Self {
134 Directory {
135 handle: StoreObjectHandle::new(
136 owner,
137 object_id,
138 false,
139 HandleOptions::default(),
140 false,
141 ),
142 is_deleted: AtomicBool::new(false),
143 casefold: AtomicBool::new(casefold),
144 wrapping_key_id: Mutex::new(wrapping_key_id),
145 }
146 }
147
148 pub fn object_id(&self) -> u64 {
149 self.handle.object_id()
150 }
151
152 pub fn wrapping_key_id(&self) -> Option<u128> {
153 self.wrapping_key_id.lock().clone()
154 }
155
156 pub async fn get_fscrypt_key(&self) -> Result<Option<Key>, Error> {
160 let object_id = self.object_id();
161 let store = self.store();
162 store
163 .key_manager()
164 .get_fscrypt_key(object_id, store.crypt().unwrap().as_ref(), async || {
165 store.get_keys(object_id).await
166 })
167 .await
168 }
169
170 pub fn owner(&self) -> &Arc<S> {
171 self.handle.owner()
172 }
173
174 pub fn store(&self) -> &ObjectStore {
175 self.handle.store()
176 }
177
178 pub fn handle(&self) -> &StoreObjectHandle<S> {
179 &self.handle
180 }
181
182 pub fn is_deleted(&self) -> bool {
183 self.is_deleted.load(Ordering::Relaxed)
184 }
185
186 pub fn set_deleted(&self) {
187 self.is_deleted.store(true, Ordering::Relaxed);
188 }
189
190 pub fn casefold(&self) -> bool {
192 self.casefold.load(Ordering::Relaxed)
193 }
194
195 pub async fn set_casefold(&self, val: bool) -> Result<(), Error> {
197 let fs = self.store().filesystem();
198 let mut transaction = fs
200 .new_transaction(
201 lock_keys![LockKey::object(self.store().store_object_id(), self.object_id())],
202 Options::default(),
203 )
204 .await?;
205 ensure!(!self.has_children().await?, FxfsError::InvalidArgs);
206 let mut mutation =
207 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
208 if let ObjectValue::Object { kind: ObjectKind::Directory { casefold, .. }, .. } =
209 &mut mutation.item.value
210 {
211 *casefold = val;
212 } else {
213 return Err(
214 anyhow!(FxfsError::Inconsistent).context("casefold only applies to directories")
215 );
216 }
217 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
218 transaction.commit_with_callback(|_| self.casefold.store(val, Ordering::Relaxed)).await?;
219 Ok(())
220 }
221
222 pub async fn create(
223 transaction: &mut Transaction<'_>,
224 owner: &Arc<S>,
225 wrapping_key_id: Option<u128>,
226 ) -> Result<Directory<S>, Error> {
227 Self::create_with_options(transaction, owner, wrapping_key_id, false).await
228 }
229
230 pub async fn create_with_options(
231 transaction: &mut Transaction<'_>,
232 owner: &Arc<S>,
233 wrapping_key_id: Option<u128>,
234 casefold: bool,
235 ) -> Result<Directory<S>, Error> {
236 let store = owner.as_ref().as_ref();
237 let object_id = store.get_next_object_id(transaction.txn_guard()).await?;
238 let now = Timestamp::now();
239 transaction.add(
240 store.store_object_id(),
241 Mutation::insert_object(
242 ObjectKey::object(object_id),
243 ObjectValue::Object {
244 kind: ObjectKind::Directory { sub_dirs: 0, casefold, wrapping_key_id },
245 attributes: ObjectAttributes {
246 creation_time: now.clone(),
247 modification_time: now.clone(),
248 project_id: 0,
249 posix_attributes: None,
250 allocated_size: 0,
251 access_time: now.clone(),
252 change_time: now,
253 },
254 },
255 ),
256 );
257 if let Some(wrapping_key_id) = &wrapping_key_id {
258 if let Some(crypt) = store.crypt() {
259 let (key, unwrapped_key) =
260 crypt.create_key_with_id(object_id, *wrapping_key_id).await?;
261 transaction.add(
262 store.store_object_id(),
263 Mutation::insert_object(
264 ObjectKey::keys(object_id),
265 ObjectValue::keys(EncryptionKeys::AES256XTS(WrappedKeys::from(vec![(
266 FSCRYPT_KEY_ID,
267 key,
268 )]))),
269 ),
270 );
271 store.key_manager.insert(
276 object_id,
277 &vec![(FSCRYPT_KEY_ID, Some(unwrapped_key))],
278 false,
279 );
280 } else {
281 return Err(anyhow!("No crypt"));
282 }
283 }
284 Ok(Directory::new(owner.clone(), object_id, wrapping_key_id, casefold))
285 }
286
287 pub async fn set_wrapping_key(
288 &self,
289 transaction: &mut Transaction<'_>,
290 id: u128,
291 ) -> Result<Cipher, Error> {
292 let object_id = self.object_id();
293 let store = self.store();
294 if let Some(crypt) = store.crypt() {
295 let (key, unwrapped_key) = crypt.create_key_with_id(object_id, id).await?;
296 match store
297 .tree
298 .find(&ObjectKey::object(object_id))
299 .await?
300 .ok_or(FxfsError::NotFound)?
301 {
302 ObjectItem {
303 value:
304 ObjectValue::Object {
305 kind: ObjectKind::Directory { sub_dirs, wrapping_key_id, casefold },
306 attributes,
307 },
308 ..
309 } => {
310 if wrapping_key_id.is_some() {
311 return Err(anyhow!("wrapping key id is already set"));
312 }
313 if self.has_children().await? {
314 return Err(FxfsError::NotEmpty.into());
315 }
316 transaction.add(
317 store.store_object_id(),
318 Mutation::replace_or_insert_object(
319 ObjectKey::object(self.object_id()),
320 ObjectValue::Object {
321 kind: ObjectKind::Directory {
322 sub_dirs,
323 wrapping_key_id: Some(id),
324 casefold,
325 },
326 attributes,
327 },
328 ),
329 );
330 }
331 ObjectItem { value: ObjectValue::None, .. } => bail!(FxfsError::NotFound),
332 _ => bail!(FxfsError::NotDir),
333 }
334
335 match store.tree.find(&ObjectKey::keys(object_id)).await? {
336 None => {
337 transaction.add(
338 store.store_object_id(),
339 Mutation::insert_object(
340 ObjectKey::keys(object_id),
341 ObjectValue::keys(EncryptionKeys::AES256XTS(WrappedKeys::from(vec![
342 (FSCRYPT_KEY_ID, key),
343 ]))),
344 ),
345 );
346 }
347 Some(Item {
348 value: ObjectValue::Keys(EncryptionKeys::AES256XTS(mut keys)),
349 ..
350 }) => {
351 keys.push((FSCRYPT_KEY_ID, key));
352 transaction.add(
353 store.store_object_id(),
354 Mutation::replace_or_insert_object(
355 ObjectKey::keys(object_id),
356 ObjectValue::keys(EncryptionKeys::AES256XTS(keys)),
357 ),
358 );
359 }
360 Some(item) => bail!("Unexpected item in lookup: {item:?}"),
361 }
362 Ok(Cipher::new(FSCRYPT_KEY_ID, &unwrapped_key))
363 } else {
364 Err(anyhow!("No crypt"))
365 }
366 }
367
368 #[trace]
369 pub async fn open(owner: &Arc<S>, object_id: u64) -> Result<Directory<S>, Error> {
370 let store = owner.as_ref().as_ref();
371 match store.tree.find(&ObjectKey::object(object_id)).await?.ok_or(FxfsError::NotFound)? {
372 ObjectItem {
373 value:
374 ObjectValue::Object {
375 kind: ObjectKind::Directory { wrapping_key_id, casefold, .. },
376 ..
377 },
378 ..
379 } => Ok(Directory::new(owner.clone(), object_id, wrapping_key_id, casefold)),
380 _ => bail!(FxfsError::NotDir),
381 }
382 }
383
384 pub fn open_unchecked(
387 owner: Arc<S>,
388 object_id: u64,
389 wrapping_key_id: Option<u128>,
390 casefold: bool,
391 ) -> Self {
392 Self::new(owner, object_id, wrapping_key_id, casefold)
393 }
394
395 pub async fn acquire_context_for_replace(
408 &self,
409 src: Option<(&Directory<S>, &str)>,
410 dst: &str,
411 borrow_metadata_space: bool,
412 ) -> Result<ReplaceContext<'_>, Error> {
413 let store = self.store();
424 let mut child_object_id = INVALID_OBJECT_ID;
425 let mut src_object_id = src.map(|_| INVALID_OBJECT_ID);
426 let mut lock_keys = LockKeys::with_capacity(4);
427 lock_keys.push(LockKey::object(store.store_object_id(), self.object_id()));
428 loop {
429 lock_keys.truncate(1);
430 if let Some(src) = src {
431 lock_keys.push(LockKey::object(store.store_object_id(), src.0.object_id()));
432 if let Some(src_object_id) = src_object_id {
433 if src_object_id != INVALID_OBJECT_ID {
434 lock_keys.push(LockKey::object(store.store_object_id(), src_object_id));
435 }
436 }
437 }
438 if child_object_id != INVALID_OBJECT_ID {
439 lock_keys.push(LockKey::object(store.store_object_id(), child_object_id));
440 };
441 let fs = store.filesystem().clone();
442 let transaction = fs
443 .new_transaction(
444 lock_keys.clone(),
445 Options { borrow_metadata_space, ..Default::default() },
446 )
447 .await?;
448
449 let mut have_required_locks = true;
450 let mut src_id_and_descriptor = None;
451 if let Some((src_dir, src_name)) = src {
452 match src_dir.lookup(src_name).await? {
453 Some((object_id, object_descriptor, _)) => match object_descriptor {
454 ObjectDescriptor::File
455 | ObjectDescriptor::Directory
456 | ObjectDescriptor::Symlink => {
457 if src_object_id != Some(object_id) {
458 have_required_locks = false;
459 src_object_id = Some(object_id);
460 }
461 src_id_and_descriptor = Some((object_id, object_descriptor));
462 }
463 _ => bail!(FxfsError::Inconsistent),
464 },
465 None => {
466 bail!(FxfsError::NotFound)
468 }
469 }
470 };
471 let dst_id_and_descriptor = match self.lookup(dst).await? {
472 Some((object_id, object_descriptor, _)) => match object_descriptor {
473 ObjectDescriptor::File
474 | ObjectDescriptor::Directory
475 | ObjectDescriptor::Symlink => {
476 if child_object_id != object_id {
477 have_required_locks = false;
478 child_object_id = object_id
479 }
480 Some((object_id, object_descriptor))
481 }
482 _ => bail!(FxfsError::Inconsistent),
483 },
484 None => {
485 if child_object_id != INVALID_OBJECT_ID {
486 have_required_locks = false;
487 child_object_id = INVALID_OBJECT_ID;
488 }
489 None
490 }
491 };
492 if have_required_locks {
493 return Ok(ReplaceContext {
494 transaction,
495 src_id_and_descriptor,
496 dst_id_and_descriptor,
497 });
498 }
499 }
500 }
501
502 async fn has_children(&self) -> Result<bool, Error> {
503 if self.is_deleted() {
504 return Ok(false);
505 }
506 let layer_set = self.store().tree().layer_set();
507 let mut merger = layer_set.merger();
508 Ok(self.iter(&mut merger).await?.get().is_some())
509 }
510
511 #[trace]
515 pub async fn lookup(&self, name: &str) -> Result<Option<(u64, ObjectDescriptor, bool)>, Error> {
516 if self.is_deleted() {
517 return Ok(None);
518 }
519 let res = if self.wrapping_key_id.lock().is_some() {
520 if let Some(fscrypt_key) = self.get_fscrypt_key().await? {
521 let target_casefold_hash =
522 get_casefold_hash(Some(&fscrypt_key), name, self.casefold());
523 if !self.casefold() {
524 let encrypted_name = encrypt_filename(&fscrypt_key, self.object_id(), name)?;
525 self.store()
526 .tree()
527 .find(&ObjectKey::encrypted_child(
528 self.object_id(),
529 encrypted_name,
530 target_casefold_hash,
531 ))
532 .await?
533 .map(|x| (x, false))
534 } else {
535 let key =
536 ObjectKey::encrypted_child(self.object_id(), vec![], target_casefold_hash);
537 let layer_set = self.store().tree().layer_set();
538 let mut merger = layer_set.merger();
539 let mut iter = merger.query(Query::FullRange(&key)).await?;
540 loop {
541 match iter.get() {
542 Some(ItemRef { value: ObjectValue::None, .. }) => {}
544 Some(ItemRef {
545 key:
546 key @ ObjectKey {
547 object_id,
548 data:
549 ObjectKeyData::EncryptedChild {
550 casefold_hash,
551 name: encrypted_name,
552 },
553 },
554 value,
555 sequence,
556 }) if *object_id == self.object_id()
557 && *casefold_hash == target_casefold_hash =>
558 {
559 let decrypted_name = decrypt_filename(
560 &fscrypt_key,
561 self.object_id(),
562 encrypted_name,
563 )?;
564 if fxfs_unicode::casefold_cmp(name, &decrypted_name)
565 == std::cmp::Ordering::Equal
566 {
567 break Some((
568 Item { key: key.clone(), value: value.clone(), sequence },
569 false,
570 ));
571 }
572 }
573 _ => break None,
574 }
575 iter.advance().await?;
576 }
577 }
578 } else {
579 let target_filename: ProxyFilename =
580 name.try_into().unwrap_or_else(|_| ProxyFilename::new(0, &[]));
581 let query_key = proxy_filename_to_query_key(&target_filename, self.object_id());
582 let layer_set = self.store().tree().layer_set();
583 let mut merger = layer_set.merger();
584 let mut iter = merger.query(Query::FullRange(&query_key)).await?;
585 loop {
586 match iter.get() {
587 Some(ItemRef { value: ObjectValue::None, .. }) => {}
589 Some(ItemRef {
590 key:
591 key @ ObjectKey {
592 object_id,
593 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
594 },
595 value,
596 sequence,
597 }) if *object_id == self.object_id()
598 && *casefold_hash == target_filename.hash_code as u32 =>
599 {
600 let filename = ProxyFilename::new(*casefold_hash as u64, name);
601 if filename == target_filename {
602 break Some((
603 Item { key: key.clone(), value: value.clone(), sequence },
604 true,
605 ));
606 }
607 }
608 _ => break None,
609 }
610 iter.advance().await?;
611 }
612 }
613 } else {
614 self.store()
615 .tree()
616 .find(&ObjectKey::child(self.object_id(), name, self.casefold()))
617 .await?
618 .map(|x| (x, false))
619 };
620 match res {
621 None | Some((ObjectItem { value: ObjectValue::None, .. }, _)) => Ok(None),
622 Some((
623 ObjectItem {
624 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
625 ..
626 },
627 locked,
628 )) => Ok(Some((object_id, object_descriptor, locked))),
629 Some(item) => Err(anyhow!(FxfsError::Inconsistent)
630 .context(format!("Unexpected item in lookup: {:?}", item))),
631 }
632 }
633
634 pub async fn create_child_dir(
635 &self,
636 transaction: &mut Transaction<'_>,
637 name: &str,
638 ) -> Result<Directory<S>, Error> {
639 ensure!(!self.is_deleted(), FxfsError::Deleted);
640
641 let handle = Directory::create_with_options(
642 transaction,
643 self.owner(),
644 self.wrapping_key_id(),
645 self.casefold(),
646 )
647 .await?;
648 if self.wrapping_key_id.lock().is_some() {
649 let key = if let Some(key) = self.get_fscrypt_key().await? {
650 key
651 } else {
652 bail!(FxfsError::NoKey);
653 };
654 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
655 let encrypted_name =
656 encrypt_filename(&key, self.object_id(), name).expect("encrypt_filename");
657 transaction.add(
658 self.store().store_object_id(),
659 Mutation::replace_or_insert_object(
660 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
661 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
662 ),
663 );
664 } else {
665 transaction.add(
666 self.store().store_object_id(),
667 Mutation::replace_or_insert_object(
668 ObjectKey::child(self.object_id(), &name, self.casefold()),
669 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
670 ),
671 );
672 }
673 let now = Timestamp::now();
674 self.update_dir_attributes_internal(
675 transaction,
676 self.object_id(),
677 MutableAttributesInternal {
678 sub_dirs: 1,
679 modification_time: Some(now.as_nanos()),
680 change_time: Some(now),
681 ..Default::default()
682 },
683 )
684 .await?;
685 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
686 Ok(handle)
687 }
688
689 pub async fn add_child_file<'a>(
690 &self,
691 transaction: &mut Transaction<'a>,
692 name: &str,
693 handle: &DataObjectHandle<S>,
694 ) -> Result<(), Error> {
695 ensure!(!self.is_deleted(), FxfsError::Deleted);
696 if self.wrapping_key_id.lock().is_some() {
697 let key = if let Some(key) = self.get_fscrypt_key().await? {
698 key
699 } else {
700 bail!(FxfsError::NoKey);
701 };
702 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
703 let encrypted_name =
704 encrypt_filename(&key, self.object_id(), name).expect("encrypt_filename");
705 transaction.add(
706 self.store().store_object_id(),
707 Mutation::replace_or_insert_object(
708 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
709 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
710 ),
711 );
712 } else {
713 transaction.add(
714 self.store().store_object_id(),
715 Mutation::replace_or_insert_object(
716 ObjectKey::child(self.object_id(), &name, self.casefold()),
717 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
718 ),
719 );
720 }
721 let now = Timestamp::now();
722 self.update_dir_attributes_internal(
723 transaction,
724 self.object_id(),
725 MutableAttributesInternal {
726 modification_time: Some(now.as_nanos()),
727 change_time: Some(now),
728 ..Default::default()
729 },
730 )
731 .await
732 }
733
734 fn copy_project_id_to_object_in_txn<'a>(
739 &self,
740 transaction: &mut Transaction<'a>,
741 object_id: u64,
742 ) -> Result<(), Error> {
743 let store_id = self.store().store_object_id();
744 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
746 transaction
747 .get_object_mutation(store_id, ObjectKey::object(self.object_id()))
748 .unwrap()
749 .item
750 .value
751 else {
752 return Err(anyhow!(FxfsError::Inconsistent));
753 };
754 if project_id > 0 {
755 let mut mutation = transaction
758 .get_object_mutation(store_id, ObjectKey::object(object_id))
759 .unwrap()
760 .clone();
761 if let ObjectValue::Object {
762 attributes: ObjectAttributes { project_id: child_project_id, .. },
763 ..
764 } = &mut mutation.item.value
765 {
766 *child_project_id = project_id;
767 } else {
768 return Err(anyhow!(FxfsError::Inconsistent));
769 }
770 transaction.add(store_id, Mutation::ObjectStore(mutation));
771 transaction.add(
772 store_id,
773 Mutation::merge_object(
774 ObjectKey::project_usage(self.store().root_directory_object_id(), project_id),
775 ObjectValue::BytesAndNodes { bytes: 0, nodes: 1 },
776 ),
777 );
778 }
779 Ok(())
780 }
781
782 pub async fn create_child_file<'a>(
783 &self,
784 transaction: &mut Transaction<'a>,
785 name: &str,
786 ) -> Result<DataObjectHandle<S>, Error> {
787 self.create_child_file_with_options(transaction, name, HandleOptions::default()).await
788 }
789
790 pub async fn create_child_file_with_options<'a>(
791 &self,
792 transaction: &mut Transaction<'a>,
793 name: &str,
794 options: HandleOptions,
795 ) -> Result<DataObjectHandle<S>, Error> {
796 ensure!(!self.is_deleted(), FxfsError::Deleted);
797 let wrapping_key_id = self.wrapping_key_id.lock().clone();
798 let handle =
799 ObjectStore::create_object(self.owner(), transaction, options, wrapping_key_id).await?;
800 self.add_child_file(transaction, name, &handle).await?;
801 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
802 Ok(handle)
803 }
804
805 pub async fn create_child_unnamed_temporary_file<'a>(
806 &self,
807 transaction: &mut Transaction<'a>,
808 ) -> Result<DataObjectHandle<S>, Error> {
809 ensure!(!self.is_deleted(), FxfsError::Deleted);
810 let wrapping_key_id = self.wrapping_key_id.lock().clone();
811 let handle = ObjectStore::create_object(
812 self.owner(),
813 transaction,
814 HandleOptions::default(),
815 wrapping_key_id,
816 )
817 .await?;
818
819 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } = self
821 .store()
822 .txn_get_object_mutation(&transaction, self.object_id())
823 .await
824 .unwrap()
825 .item
826 .value
827 else {
828 bail!(anyhow!(FxfsError::Inconsistent)
829 .context("Directory.create_child_file_with_options: expected mutation object"));
830 };
831
832 let mut child_mutation = transaction
834 .get_object_mutation(
835 self.store().store_object_id(),
836 ObjectKey::object(handle.object_id()),
837 )
838 .unwrap()
839 .clone();
840 if let ObjectValue::Object {
841 attributes: ObjectAttributes { project_id: child_project_id, .. },
842 ..
843 } = &mut child_mutation.item.value
844 {
845 *child_project_id = project_id;
846 } else {
847 bail!(anyhow!(FxfsError::Inconsistent)
848 .context("Directory.create_child_file_with_options: expected file object"));
849 }
850 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(child_mutation));
851
852 self.store().add_to_graveyard(transaction, handle.object_id());
854
855 Ok(handle)
856 }
857
858 pub async fn create_symlink(
859 &self,
860 transaction: &mut Transaction<'_>,
861 link: &[u8],
862 name: &str,
863 ) -> Result<u64, Error> {
864 ensure!(!self.is_deleted(), FxfsError::Deleted);
865 ensure!(link.len() <= 256, FxfsError::BadPath);
869 let symlink_id = self.store().get_next_object_id(transaction.txn_guard()).await?;
870 let wrapping_key_id = self.wrapping_key_id.lock().clone();
871 let mut link = link.to_vec();
872
873 if let Some(wrapping_key_id) = wrapping_key_id {
874 if let Some(crypt) = self.store().crypt() {
875 let (wrapped_key, unwrapped_key) =
876 crypt.create_key_with_id(symlink_id, wrapping_key_id).await?;
877
878 let unwrapped_keys = vec![(FSCRYPT_KEY_ID, Some(unwrapped_key))];
883 self.store().key_manager.insert(symlink_id, &unwrapped_keys, false);
884 let symlink_key = Key::new(unwrapped_keys.to_cipher_set(), 0);
885
886 let dir_key = if let Some(key) = self.get_fscrypt_key().await? {
887 key
888 } else {
889 bail!(FxfsError::NoKey);
890 };
891 let casefold_hash = get_casefold_hash(Some(&dir_key), name, self.casefold());
892 let encrypted_name = encrypt_filename(&dir_key, self.object_id(), name)?;
893 symlink_key.encrypt_filename(symlink_id, &mut link)?;
894
895 transaction.add(
896 self.store().store_object_id(),
897 Mutation::insert_object(
898 ObjectKey::object(symlink_id),
899 ObjectValue::encrypted_symlink(link, Timestamp::now(), Timestamp::now(), 0),
900 ),
901 );
902 transaction.add(
903 self.store().store_object_id(),
904 Mutation::insert_object(
905 ObjectKey::keys(symlink_id),
906 ObjectValue::keys(EncryptionKeys::AES256XTS(WrappedKeys::from(vec![(
907 FSCRYPT_KEY_ID,
908 wrapped_key,
909 )]))),
910 ),
911 );
912 transaction.add(
913 self.store().store_object_id(),
914 Mutation::replace_or_insert_object(
915 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
916 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
917 ),
918 );
919 } else {
920 return Err(anyhow!("No crypt"));
921 }
922 } else {
923 transaction.add(
924 self.store().store_object_id(),
925 Mutation::insert_object(
926 ObjectKey::object(symlink_id),
927 ObjectValue::symlink(link, Timestamp::now(), Timestamp::now(), 0),
928 ),
929 );
930 transaction.add(
931 self.store().store_object_id(),
932 Mutation::replace_or_insert_object(
933 ObjectKey::child(self.object_id(), &name, self.casefold()),
934 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
935 ),
936 );
937 };
938
939 let now = Timestamp::now();
940 self.update_dir_attributes_internal(
941 transaction,
942 self.object_id(),
943 MutableAttributesInternal {
944 modification_time: Some(now.as_nanos()),
945 change_time: Some(now),
946 ..Default::default()
947 },
948 )
949 .await?;
950 Ok(symlink_id)
951 }
952
953 pub async fn add_child_volume(
954 &self,
955 transaction: &mut Transaction<'_>,
956 volume_name: &str,
957 store_object_id: u64,
958 ) -> Result<(), Error> {
959 ensure!(!self.is_deleted(), FxfsError::Deleted);
960 transaction.add(
961 self.store().store_object_id(),
962 Mutation::replace_or_insert_object(
963 ObjectKey::child(self.object_id(), volume_name, self.casefold()),
964 ObjectValue::child(store_object_id, ObjectDescriptor::Volume),
965 ),
966 );
967 let now = Timestamp::now();
968 self.update_dir_attributes_internal(
969 transaction,
970 self.object_id(),
971 MutableAttributesInternal {
972 modification_time: Some(now.as_nanos()),
973 change_time: Some(now),
974 ..Default::default()
975 },
976 )
977 .await
978 }
979
980 pub async fn delete_child_volume<'a>(
981 &self,
982 transaction: &mut Transaction<'a>,
983 volume_name: &str,
984 store_object_id: u64,
985 ) -> Result<(), Error> {
986 ensure!(!self.is_deleted(), FxfsError::Deleted);
987 transaction.add(
988 self.store().store_object_id(),
989 Mutation::replace_or_insert_object(
990 ObjectKey::child(self.object_id(), volume_name, self.casefold()),
991 ObjectValue::None,
992 ),
993 );
994 transaction.add(store_object_id, Mutation::DeleteVolume);
999 Ok(())
1000 }
1001
1002 pub async fn insert_child<'a>(
1006 &self,
1007 transaction: &mut Transaction<'a>,
1008 name: &str,
1009 object_id: u64,
1010 descriptor: ObjectDescriptor,
1011 ) -> Result<(), Error> {
1012 ensure!(!self.is_deleted(), FxfsError::Deleted);
1013 let sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1014 if self.wrapping_key_id.lock().is_some() {
1015 let key = self.get_fscrypt_key().await?.ok_or(FxfsError::NoKey)?;
1016 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
1017 let encrypted_name = encrypt_filename(&key, self.object_id(), name)?;
1018 transaction.add(
1019 self.store().store_object_id(),
1020 Mutation::replace_or_insert_object(
1021 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
1022 ObjectValue::child(object_id, descriptor),
1023 ),
1024 );
1025 } else {
1026 transaction.add(
1027 self.store().store_object_id(),
1028 Mutation::replace_or_insert_object(
1029 ObjectKey::child(self.object_id(), &name, self.casefold()),
1030 ObjectValue::child(object_id, descriptor),
1031 ),
1032 );
1033 }
1034 let now = Timestamp::now();
1035 self.update_dir_attributes_internal(
1036 transaction,
1037 self.object_id(),
1038 MutableAttributesInternal {
1039 sub_dirs: sub_dirs_delta,
1040 modification_time: Some(now.as_nanos()),
1041 change_time: Some(now),
1042 ..Default::default()
1043 },
1044 )
1045 .await
1046 }
1047
1048 pub async fn update_attributes<'a>(
1051 &self,
1052 mut transaction: Transaction<'a>,
1053 node_attributes: Option<&fio::MutableNodeAttributes>,
1054 sub_dirs_delta: i64,
1055 change_time: Option<Timestamp>,
1056 ) -> Result<(), Error> {
1057 ensure!(!self.is_deleted(), FxfsError::Deleted);
1058
1059 if sub_dirs_delta != 0 {
1060 let mut mutation =
1061 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
1062 if let ObjectValue::Object { kind: ObjectKind::Directory { sub_dirs, .. }, .. } =
1063 &mut mutation.item.value
1064 {
1065 *sub_dirs = sub_dirs.saturating_add_signed(sub_dirs_delta);
1066 } else {
1067 bail!(anyhow!(FxfsError::Inconsistent)
1068 .context("Directory.update_attributes: expected directory object"));
1069 };
1070
1071 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1072 }
1073
1074 let wrapping_key =
1075 if let Some(fio::MutableNodeAttributes { wrapping_key_id: Some(id), .. }) =
1076 node_attributes
1077 {
1078 Some((
1079 u128::from_le_bytes(*id),
1080 self.set_wrapping_key(&mut transaction, u128::from_le_bytes(*id)).await?,
1081 ))
1082 } else {
1083 None
1084 };
1085
1086 if node_attributes.is_some() || change_time.is_some() {
1088 self.handle.update_attributes(&mut transaction, node_attributes, change_time).await?;
1089 }
1090 transaction
1091 .commit_with_callback(|_| {
1092 if let Some((key_id, unwrapped_key)) = wrapping_key {
1093 *self.wrapping_key_id.lock() = Some(key_id);
1094 self.store().key_manager.merge(self.object_id(), |existing| {
1095 let mut new = existing.map_or(Vec::new(), |e| e.ciphers().to_vec());
1096 new.push(unwrapped_key);
1097 Arc::new(CipherSet::from(new))
1098 });
1099 }
1100 })
1101 .await?;
1102 Ok(())
1103 }
1104
1105 pub async fn update_dir_attributes_internal<'a>(
1109 &self,
1110 transaction: &mut Transaction<'a>,
1111 object_id: u64,
1112 mutable_node_attributes: MutableAttributesInternal,
1113 ) -> Result<(), Error> {
1114 ensure!(!self.is_deleted(), FxfsError::Deleted);
1115
1116 let mut mutation = self.store().txn_get_object_mutation(transaction, object_id).await?;
1117 if let ObjectValue::Object {
1118 kind: ObjectKind::Directory { sub_dirs, .. },
1119 ref mut attributes,
1120 ..
1121 } = &mut mutation.item.value
1122 {
1123 if let Some(time) = mutable_node_attributes.modification_time {
1124 attributes.modification_time = Timestamp::from_nanos(time);
1125 }
1126 if let Some(time) = mutable_node_attributes.change_time {
1127 attributes.change_time = time;
1128 }
1129 if mutable_node_attributes.sub_dirs != 0 {
1130 *sub_dirs = sub_dirs.saturating_add_signed(mutable_node_attributes.sub_dirs);
1131 }
1132 if let Some(time) = mutable_node_attributes.creation_time {
1133 attributes.creation_time = Timestamp::from_nanos(time);
1134 }
1135 } else {
1136 bail!(anyhow!(FxfsError::Inconsistent)
1137 .context("Directory.update_attributes: expected directory object"));
1138 };
1139 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1140 Ok(())
1141 }
1142
1143 pub async fn get_properties(&self) -> Result<ObjectProperties, Error> {
1144 if self.is_deleted() {
1145 return Ok(ObjectProperties {
1146 refs: 0,
1147 allocated_size: 0,
1148 data_attribute_size: 0,
1149 creation_time: Timestamp::zero(),
1150 modification_time: Timestamp::zero(),
1151 access_time: Timestamp::zero(),
1152 change_time: Timestamp::zero(),
1153 sub_dirs: 0,
1154 posix_attributes: None,
1155 casefold: false,
1156 wrapping_key_id: None,
1157 });
1158 }
1159
1160 let item = self
1161 .store()
1162 .tree()
1163 .find(&ObjectKey::object(self.object_id()))
1164 .await?
1165 .ok_or(FxfsError::NotFound)?;
1166 match item.value {
1167 ObjectValue::Object {
1168 kind: ObjectKind::Directory { sub_dirs, casefold, wrapping_key_id },
1169 attributes:
1170 ObjectAttributes {
1171 creation_time,
1172 modification_time,
1173 posix_attributes,
1174 access_time,
1175 change_time,
1176 ..
1177 },
1178 } => Ok(ObjectProperties {
1179 refs: 1,
1180 allocated_size: 0,
1181 data_attribute_size: 0,
1182 creation_time,
1183 modification_time,
1184 access_time,
1185 change_time,
1186 sub_dirs,
1187 posix_attributes,
1188 casefold,
1189 wrapping_key_id,
1190 }),
1191 _ => {
1192 bail!(anyhow!(FxfsError::Inconsistent)
1193 .context("get_properties: Expected object value"))
1194 }
1195 }
1196 }
1197
1198 pub async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, Error> {
1199 ensure!(!self.is_deleted(), FxfsError::Deleted);
1200 self.handle.list_extended_attributes().await
1201 }
1202
1203 pub async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, Error> {
1204 ensure!(!self.is_deleted(), FxfsError::Deleted);
1205 self.handle.get_extended_attribute(name).await
1206 }
1207
1208 pub async fn set_extended_attribute(
1209 &self,
1210 name: Vec<u8>,
1211 value: Vec<u8>,
1212 mode: SetExtendedAttributeMode,
1213 ) -> Result<(), Error> {
1214 ensure!(!self.is_deleted(), FxfsError::Deleted);
1215 self.handle.set_extended_attribute(name, value, mode).await
1216 }
1217
1218 pub async fn remove_extended_attribute(&self, name: Vec<u8>) -> Result<(), Error> {
1219 ensure!(!self.is_deleted(), FxfsError::Deleted);
1220 self.handle.remove_extended_attribute(name).await
1221 }
1222
1223 pub async fn iter<'a, 'b>(
1231 &self,
1232 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1233 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1234 self.iter_from(merger, "").await
1235 }
1236
1237 pub async fn iter_from<'a, 'b>(
1244 &self,
1245 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1246 from: &str,
1247 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1248 ensure!(!self.is_deleted(), FxfsError::Deleted);
1249
1250 let (query_key, requested_filename) = if self.wrapping_key_id.lock().is_some() {
1254 if let Some(key) = self.get_fscrypt_key().await? {
1255 let casefold_hash = get_casefold_hash(Some(&key), from, self.casefold());
1257 let encrypted_name = encrypt_filename(&key, self.object_id(), from)?;
1258 (ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash), None)
1259 } else {
1260 let filename: ProxyFilename =
1262 from.try_into().unwrap_or_else(|_| ProxyFilename::new(0, &[]));
1263 let key = proxy_filename_to_query_key(&filename, self.object_id());
1264 if from == "" {
1265 (key, None)
1267 } else {
1268 (key, Some(filename))
1270 }
1271 }
1272 } else {
1273 (ObjectKey::child(self.object_id(), from, self.casefold()), None)
1275 };
1276 let mut iter = merger.query(Query::FullRange(&query_key)).await?;
1277 loop {
1278 match iter.get() {
1279 Some(ItemRef {
1281 key: ObjectKey { object_id, .. },
1282 value: ObjectValue::None,
1283 ..
1284 }) if *object_id == self.object_id() => {}
1285 Some(ItemRef {
1287 key:
1288 ObjectKey {
1289 object_id,
1290 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
1291 ..
1292 },
1293 ..
1294 }) if *object_id == self.object_id() => {
1295 if let Some(requested_filename) = &requested_filename {
1297 let filename = ProxyFilename::new(*casefold_hash as u64, name);
1298 if &filename == requested_filename {
1299 break;
1300 }
1301 } else {
1302 break;
1305 }
1306 }
1307 _ => break,
1308 }
1309 iter.advance().await?;
1310 }
1311 let key = if self.wrapping_key_id.lock().is_some() {
1312 self.get_fscrypt_key().await?
1313 } else {
1314 None
1315 };
1316 let mut dir_iter =
1317 DirectoryIterator { object_id: self.object_id(), iter, key, filename: None };
1318 if let Some(ItemRef {
1326 key:
1327 ObjectKey {
1328 object_id, data: ObjectKeyData::EncryptedChild { casefold_hash, name }, ..
1329 },
1330 ..
1331 }) = dir_iter.iter.get()
1332 {
1333 let object_id = *object_id;
1334 let casefold_hash = *casefold_hash;
1335 let name = name.clone();
1336 dir_iter.update_encrypted_filename(object_id, casefold_hash, name)?;
1337 }
1338 Ok(dir_iter)
1339 }
1340}
1341
1342impl<S: HandleOwner> fmt::Debug for Directory<S> {
1343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1344 f.debug_struct("Directory")
1345 .field("store_id", &self.store().store_object_id())
1346 .field("object_id", &self.object_id())
1347 .finish()
1348 }
1349}
1350
1351pub struct DirectoryIterator<'a, 'b> {
1352 object_id: u64,
1353 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1354 key: Option<Key>,
1355 filename: Option<String>,
1357}
1358
1359impl DirectoryIterator<'_, '_> {
1360 pub fn get(&self) -> Option<(&str, u64, &ObjectDescriptor)> {
1361 match self.iter.get() {
1362 Some(ItemRef {
1363 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1364 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1365 ..
1366 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1367 Some(ItemRef {
1368 key: ObjectKey { object_id: oid, data: ObjectKeyData::CasefoldChild { name } },
1369 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1370 ..
1371 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1372 Some(ItemRef {
1373 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedChild { .. } },
1374 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1375 ..
1376 }) if *oid == self.object_id => {
1377 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1378 }
1379 _ => None,
1380 }
1381 }
1382
1383 pub(super) fn update_encrypted_filename(
1386 &mut self,
1387 object_id: u64,
1388 casefold_hash: u32,
1389 mut name: Vec<u8>,
1390 ) -> Result<(), Error> {
1391 if let Some(key) = &self.key {
1392 key.decrypt_filename(object_id, &mut name)?;
1393 self.filename = Some(String::from_utf8(name).map_err(|_| {
1394 anyhow!(FxfsError::Internal).context("Bad UTF-8 encrypted filename")
1395 })?);
1396 } else {
1397 self.filename = Some(ProxyFilename::new(casefold_hash as u64, &name).into());
1398 }
1399 Ok(())
1400 }
1401
1402 pub async fn advance(&mut self) -> Result<(), Error> {
1403 loop {
1404 self.iter.advance().await?;
1405 match self.iter.get() {
1407 Some(ItemRef {
1408 key: ObjectKey { object_id, .. },
1409 value: ObjectValue::None,
1410 ..
1411 }) if *object_id == self.object_id => {}
1412 Some(ItemRef {
1413 key:
1414 ObjectKey {
1415 object_id,
1416 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
1417 },
1418 value: ObjectValue::Child(_),
1419 ..
1420 }) if *object_id == self.object_id => {
1421 self.update_encrypted_filename(*object_id, *casefold_hash, name.clone())?;
1424 return Ok(());
1425 }
1426 _ => return Ok(()),
1427 }
1428 }
1429 }
1430}
1431
1432#[derive(Debug)]
1435pub enum ReplacedChild {
1436 None,
1437 Object(u64),
1439 ObjectWithRemainingLinks(u64),
1440 Directory(u64),
1441}
1442
1443pub async fn replace_child<'a, S: HandleOwner>(
1451 transaction: &mut Transaction<'a>,
1452 src: Option<(&'a Directory<S>, &str)>,
1453 dst: (&'a Directory<S>, &str),
1454) -> Result<ReplacedChild, Error> {
1455 let mut sub_dirs_delta: i64 = 0;
1456 let now = Timestamp::now();
1457
1458 let src = if let Some((src_dir, src_name)) = src {
1459 let store_id = dst.0.store().store_object_id();
1460 assert_eq!(store_id, src_dir.store().store_object_id());
1461 match (src_dir.wrapping_key_id(), dst.0.wrapping_key_id()) {
1462 (Some(src_id), Some(dst_id)) => {
1463 ensure!(src_id == dst_id, FxfsError::NotSupported);
1464 let key = if let Some(key) = src_dir.get_fscrypt_key().await? {
1467 key
1468 } else {
1469 bail!(FxfsError::NoKey);
1470 };
1471
1472 let src_casefold_hash = get_casefold_hash(Some(&key), src_name, src_dir.casefold());
1473 let encrypted_src_name = encrypt_filename(&key, src_dir.object_id(), src_name)?;
1474 transaction.add(
1475 store_id,
1476 Mutation::replace_or_insert_object(
1477 ObjectKey::encrypted_child(
1478 src_dir.object_id(),
1479 encrypted_src_name,
1480 src_casefold_hash,
1481 ),
1482 ObjectValue::None,
1483 ),
1484 );
1485 }
1486 (None, None) => {
1487 transaction.add(
1488 store_id,
1489 Mutation::replace_or_insert_object(
1490 ObjectKey::child(src_dir.object_id(), src_name, src_dir.casefold()),
1491 ObjectValue::None,
1492 ),
1493 );
1494 }
1495 _ => bail!(FxfsError::NotSupported),
1497 }
1498 let (id, descriptor, _) = src_dir.lookup(src_name).await?.ok_or(FxfsError::NotFound)?;
1499 src_dir.store().update_attributes(transaction, id, None, Some(now)).await?;
1500 if src_dir.object_id() != dst.0.object_id() {
1501 sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1502 src_dir
1503 .update_dir_attributes_internal(
1504 transaction,
1505 src_dir.object_id(),
1506 MutableAttributesInternal {
1507 sub_dirs: -sub_dirs_delta,
1508 modification_time: Some(now.as_nanos()),
1509 change_time: Some(now),
1510 ..Default::default()
1511 },
1512 )
1513 .await?;
1514 }
1515 Some((id, descriptor))
1516 } else {
1517 None
1518 };
1519 replace_child_with_object(transaction, src, dst, sub_dirs_delta, now).await
1520}
1521
1522pub async fn replace_child_with_object<'a, S: HandleOwner>(
1532 transaction: &mut Transaction<'a>,
1533 src: Option<(u64, ObjectDescriptor)>,
1534 dst: (&'a Directory<S>, &str),
1535 mut sub_dirs_delta: i64,
1536 timestamp: Timestamp,
1537) -> Result<ReplacedChild, Error> {
1538 let deleted_id_and_descriptor = dst.0.lookup(dst.1).await?;
1539 let store_id = dst.0.store().store_object_id();
1540 let result = match deleted_id_and_descriptor {
1543 Some((old_id, ObjectDescriptor::File | ObjectDescriptor::Symlink, _)) => {
1544 let was_last_ref = dst.0.store().adjust_refs(transaction, old_id, -1).await?;
1545 dst.0.store().update_attributes(transaction, old_id, None, Some(timestamp)).await?;
1546 if was_last_ref {
1547 ReplacedChild::Object(old_id)
1548 } else {
1549 ReplacedChild::ObjectWithRemainingLinks(old_id)
1550 }
1551 }
1552 Some((old_id, ObjectDescriptor::Directory, _)) => {
1553 let dir = Directory::open(&dst.0.owner(), old_id).await?;
1554 if dir.has_children().await? {
1555 bail!(FxfsError::NotEmpty);
1556 }
1557 dst.0.store().add_to_graveyard(transaction, old_id);
1560 sub_dirs_delta -= 1;
1561 ReplacedChild::Directory(old_id)
1562 }
1563 Some((_, ObjectDescriptor::Volume, _)) => {
1564 bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected volume child"))
1565 }
1566 None => {
1567 if src.is_none() {
1568 bail!(FxfsError::NotFound);
1570 }
1571 ReplacedChild::None
1572 }
1573 };
1574 let new_value = match src {
1575 Some((id, descriptor)) => ObjectValue::child(id, descriptor),
1576 None => ObjectValue::None,
1577 };
1578 if dst.0.wrapping_key_id().is_some() {
1579 if let Some(key) = dst.0.get_fscrypt_key().await? {
1580 let dst_casefold_hash = get_casefold_hash(Some(&key), dst.1, dst.0.casefold());
1581 let encrypted_dst_name = encrypt_filename(&key, dst.0.object_id(), dst.1)?;
1582 transaction.add(
1583 store_id,
1584 Mutation::replace_or_insert_object(
1585 ObjectKey::encrypted_child(
1586 dst.0.object_id(),
1587 encrypted_dst_name,
1588 dst_casefold_hash,
1589 ),
1590 new_value,
1591 ),
1592 );
1593 } else {
1594 if !matches!(new_value, ObjectValue::None) {
1595 bail!(FxfsError::NoKey);
1597 }
1598 let proxy_filename: ProxyFilename =
1602 dst.1.try_into().unwrap_or_else(|_| ProxyFilename::new(0, &[]));
1603
1604 let layer_set = dst.0.store().tree().layer_set();
1605 let mut merger = layer_set.merger();
1606 let iter = dst.0.iter_from(&mut merger, dst.1).await.context("iter_from")?;
1607 if let Some(ItemRef {
1608 key:
1609 key @ ObjectKey {
1610 data: ObjectKeyData::EncryptedChild { casefold_hash, name }, ..
1611 },
1612 ..
1613 }) = iter.iter.get()
1614 {
1615 let filename = ProxyFilename::new(*casefold_hash as u64, name);
1616 if filename == proxy_filename {
1617 transaction
1618 .add(store_id, Mutation::replace_or_insert_object(key.clone(), new_value));
1619 } else {
1620 bail!(FxfsError::NotFound);
1621 }
1622 } else {
1623 bail!(FxfsError::NotFound);
1624 }
1625 }
1626 } else {
1627 transaction.add(
1628 store_id,
1629 Mutation::replace_or_insert_object(
1630 ObjectKey::child(dst.0.object_id(), dst.1, dst.0.casefold()),
1631 new_value,
1632 ),
1633 );
1634 }
1635 dst.0
1636 .update_dir_attributes_internal(
1637 transaction,
1638 dst.0.object_id(),
1639 MutableAttributesInternal {
1640 sub_dirs: sub_dirs_delta,
1641 modification_time: Some(timestamp.as_nanos()),
1642 change_time: Some(timestamp),
1643 ..Default::default()
1644 },
1645 )
1646 .await?;
1647 Ok(result)
1648}
1649
1650#[cfg(test)]
1651mod tests {
1652 use super::{encrypt_filename, get_casefold_hash, replace_child_with_object, ProxyFilename};
1653 use crate::errors::FxfsError;
1654 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
1655 use crate::object_handle::{ObjectHandle, ReadObjectHandle, WriteObjectHandle};
1656 use crate::object_store::directory::{
1657 replace_child, Directory, MutableAttributesInternal, ReplacedChild,
1658 };
1659 use crate::object_store::object_record::Timestamp;
1660 use crate::object_store::transaction::{lock_keys, Options};
1661 use crate::object_store::volume::root_volume;
1662 use crate::object_store::{
1663 HandleOptions, LockKey, ObjectDescriptor, ObjectStore, SetExtendedAttributeMode,
1664 StoreObjectHandle, NO_OWNER,
1665 };
1666 use assert_matches::assert_matches;
1667 use fidl_fuchsia_io as fio;
1668 use fxfs_crypto::Crypt;
1669 use fxfs_insecure_crypto::InsecureCrypt;
1670 use std::collections::HashSet;
1671 use std::future::poll_fn;
1672 use std::sync::Arc;
1673 use std::task::Poll;
1674 use storage_device::fake_device::FakeDevice;
1675 use storage_device::DeviceHolder;
1676
1677 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
1678
1679 async fn yield_to_executor() {
1680 let mut done = false;
1681 poll_fn(|cx| {
1682 if done {
1683 Poll::Ready(())
1684 } else {
1685 done = true;
1686 cx.waker().wake_by_ref();
1687 Poll::Pending
1688 }
1689 })
1690 .await;
1691 }
1692
1693 #[fuchsia::test]
1694 async fn test_create_directory() {
1695 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
1696 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1697 let object_id = {
1698 let mut transaction = fs
1699 .clone()
1700 .new_transaction(lock_keys![], Options::default())
1701 .await
1702 .expect("new_transaction failed");
1703 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
1704 .await
1705 .expect("create failed");
1706
1707 let child_dir = dir
1708 .create_child_dir(&mut transaction, "foo")
1709 .await
1710 .expect("create_child_dir failed");
1711 let _child_dir_file = child_dir
1712 .create_child_file(&mut transaction, "bar")
1713 .await
1714 .expect("create_child_file failed");
1715 let _child_file = dir
1716 .create_child_file(&mut transaction, "baz")
1717 .await
1718 .expect("create_child_file failed");
1719 dir.add_child_volume(&mut transaction, "corge", 100)
1720 .await
1721 .expect("add_child_volume failed");
1722 transaction.commit().await.expect("commit failed");
1723 fs.sync(SyncOptions::default()).await.expect("sync failed");
1724 dir.object_id()
1725 };
1726 fs.close().await.expect("Close failed");
1727 let device = fs.take_device().await;
1728 device.reopen(false);
1729 let fs = FxFilesystem::open(device).await.expect("open failed");
1730 {
1731 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
1732 let (object_id, object_descriptor, _) =
1733 dir.lookup("foo").await.expect("lookup failed").expect("not found");
1734 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
1735 let child_dir =
1736 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
1737 let (object_id, object_descriptor, _) =
1738 child_dir.lookup("bar").await.expect("lookup failed").expect("not found");
1739 assert_eq!(object_descriptor, ObjectDescriptor::File);
1740 let _child_dir_file = ObjectStore::open_object(
1741 &fs.root_store(),
1742 object_id,
1743 HandleOptions::default(),
1744 None,
1745 )
1746 .await
1747 .expect("open object failed");
1748 let (object_id, object_descriptor, _) =
1749 dir.lookup("baz").await.expect("lookup failed").expect("not found");
1750 assert_eq!(object_descriptor, ObjectDescriptor::File);
1751 let _child_file = ObjectStore::open_object(
1752 &fs.root_store(),
1753 object_id,
1754 HandleOptions::default(),
1755 None,
1756 )
1757 .await
1758 .expect("open object failed");
1759 let (object_id, object_descriptor, _) =
1760 dir.lookup("corge").await.expect("lookup failed").expect("not found");
1761 assert_eq!(object_id, 100);
1762 if let ObjectDescriptor::Volume = object_descriptor {
1763 } else {
1764 panic!("wrong ObjectDescriptor");
1765 }
1766
1767 assert_eq!(dir.lookup("qux").await.expect("lookup failed"), None);
1768 }
1769 fs.close().await.expect("Close failed");
1770 }
1771
1772 #[fuchsia::test]
1773 async fn test_set_wrapping_key_does_not_exist() {
1774 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1775 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1776 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1777 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1778 let store = root_volume
1779 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1780 .await
1781 .expect("new_volume failed");
1782
1783 let mut transaction = fs
1784 .clone()
1785 .new_transaction(
1786 lock_keys![LockKey::object(
1787 store.store_object_id(),
1788 store.root_directory_object_id()
1789 )],
1790 Options::default(),
1791 )
1792 .await
1793 .expect("new transaction failed");
1794 let root_directory =
1795 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1796 let directory = root_directory
1797 .create_child_dir(&mut transaction, "foo")
1798 .await
1799 .expect("create_child_dir failed");
1800 transaction.commit().await.expect("commit failed");
1801 let mut transaction = fs
1802 .clone()
1803 .new_transaction(
1804 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1805 Options::default(),
1806 )
1807 .await
1808 .expect("new transaction failed");
1809 directory
1810 .set_wrapping_key(&mut transaction, 2)
1811 .await
1812 .expect_err("wrapping key id 2 has not been added");
1813 transaction.commit().await.expect("commit failed");
1814 crypt.add_wrapping_key(2, [1; 32]);
1815 let mut transaction = fs
1816 .clone()
1817 .new_transaction(
1818 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1819 Options::default(),
1820 )
1821 .await
1822 .expect("new transaction failed");
1823 directory
1824 .set_wrapping_key(&mut transaction, 2)
1825 .await
1826 .expect("wrapping key id 2 has been added");
1827 fs.close().await.expect("Close failed");
1828 }
1829
1830 #[fuchsia::test]
1831 async fn test_set_encryption_policy_on_unencrypted_nonempty_dir() {
1832 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1833 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1834 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1835 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1836 let store = root_volume
1837 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1838 .await
1839 .expect("new_volume failed");
1840
1841 let mut transaction = fs
1842 .clone()
1843 .new_transaction(
1844 lock_keys![LockKey::object(
1845 store.store_object_id(),
1846 store.root_directory_object_id()
1847 )],
1848 Options::default(),
1849 )
1850 .await
1851 .expect("new transaction failed");
1852 let root_directory =
1853 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1854 let directory = root_directory
1855 .create_child_dir(&mut transaction, "foo")
1856 .await
1857 .expect("create_child_dir failed");
1858 let _file = directory
1859 .create_child_file(&mut transaction, "bar")
1860 .await
1861 .expect("create_child_file failed");
1862 transaction.commit().await.expect("commit failed");
1863 let mut transaction = fs
1864 .clone()
1865 .new_transaction(
1866 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1867 Options::default(),
1868 )
1869 .await
1870 .expect("new transaction failed");
1871 directory.set_wrapping_key(&mut transaction, 2).await.expect_err("directory is not empty");
1872 transaction.commit().await.expect("commit failed");
1873 fs.close().await.expect("Close failed");
1874 }
1875
1876 #[fuchsia::test]
1877 async fn test_create_file_or_subdir_in_locked_directory() {
1878 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1879 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1880 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1881 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1882 let store = root_volume
1883 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1884 .await
1885 .expect("new_volume failed");
1886
1887 let mut transaction = fs
1888 .clone()
1889 .new_transaction(
1890 lock_keys![LockKey::object(
1891 store.store_object_id(),
1892 store.root_directory_object_id()
1893 )],
1894 Options::default(),
1895 )
1896 .await
1897 .expect("new transaction failed");
1898 let root_directory =
1899 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1900 let directory = root_directory
1901 .create_child_dir(&mut transaction, "foo")
1902 .await
1903 .expect("create_child_dir failed");
1904 transaction.commit().await.expect("commit failed");
1905 crypt.add_wrapping_key(2, [1; 32]);
1906 let transaction = fs
1907 .clone()
1908 .new_transaction(
1909 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1910 Options::default(),
1911 )
1912 .await
1913 .expect("new transaction failed");
1914 directory
1915 .update_attributes(
1916 transaction,
1917 Some(&fio::MutableNodeAttributes {
1918 wrapping_key_id: Some(u128::to_le_bytes(2)),
1919 ..Default::default()
1920 }),
1921 0,
1922 None,
1923 )
1924 .await
1925 .expect("update attributes failed");
1926 crypt.remove_wrapping_key(2);
1927 let mut transaction = fs
1928 .clone()
1929 .new_transaction(
1930 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1931 Options::default(),
1932 )
1933 .await
1934 .expect("new transaction failed");
1935 directory
1936 .create_child_dir(&mut transaction, "bar")
1937 .await
1938 .expect_err("cannot create a dir inside of a locked encrypted directory");
1939 directory
1940 .create_child_file(&mut transaction, "baz")
1941 .await
1942 .map(|_| ())
1943 .expect_err("cannot create a file inside of a locked encrypted directory");
1944 fs.close().await.expect("Close failed");
1945 }
1946
1947 #[fuchsia::test]
1948 async fn test_replace_child_with_object_in_locked_directory() {
1949 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1950 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1951 let crypt = Arc::new(InsecureCrypt::new());
1952
1953 let (parent_oid, src_oid, dst_oid) = {
1954 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1955 let store = root_volume
1956 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1957 .await
1958 .expect("new_volume failed");
1959
1960 let mut transaction = fs
1961 .clone()
1962 .new_transaction(
1963 lock_keys![LockKey::object(
1964 store.store_object_id(),
1965 store.root_directory_object_id()
1966 )],
1967 Options::default(),
1968 )
1969 .await
1970 .expect("new transaction failed");
1971 let root_directory = Directory::open(&store, store.root_directory_object_id())
1972 .await
1973 .expect("open failed");
1974 let directory = root_directory
1975 .create_child_dir(&mut transaction, "foo")
1976 .await
1977 .expect("create_child_dir failed");
1978 transaction.commit().await.expect("commit failed");
1979 crypt.add_wrapping_key(2, [1; 32]);
1980 let transaction = fs
1981 .clone()
1982 .new_transaction(
1983 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1984 Options::default(),
1985 )
1986 .await
1987 .expect("new transaction failed");
1988 directory
1989 .update_attributes(
1990 transaction,
1991 Some(&fio::MutableNodeAttributes {
1992 wrapping_key_id: Some(u128::to_le_bytes(2)),
1993 ..Default::default()
1994 }),
1995 0,
1996 None,
1997 )
1998 .await
1999 .expect("update attributes failed");
2000 let mut transaction = fs
2001 .clone()
2002 .new_transaction(
2003 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2004 Options::default(),
2005 )
2006 .await
2007 .expect("new transaction failed");
2008 let src_child = directory
2009 .create_child_dir(&mut transaction, "fee")
2010 .await
2011 .expect("create_child_dir failed");
2012 let dst_child = directory
2013 .create_child_dir(&mut transaction, "faa")
2014 .await
2015 .expect("create_child_dir failed");
2016 transaction.commit().await.expect("commit failed");
2017 crypt.remove_wrapping_key(2);
2018 (directory.object_id(), src_child.object_id(), dst_child.object_id())
2019 };
2020 fs.close().await.expect("Close failed");
2021 let device = fs.take_device().await;
2022 device.reopen(false);
2023 let fs = FxFilesystem::open(device).await.expect("open failed");
2024 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2025 let store = root_volume
2026 .volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
2027 .await
2028 .expect("volume failed");
2029
2030 {
2031 let parent_directory = Directory::open(&store, parent_oid).await.expect("open failed");
2032 let layer_set = store.tree().layer_set();
2033 let mut merger = layer_set.merger();
2034 let mut encrypted_src_name = None;
2035 let mut encrypted_dst_name = None;
2036 let mut iter =
2037 parent_directory.iter_from(&mut merger, "").await.expect("iter_from failed");
2038 while let Some((name, object_id, object_descriptor)) = iter.get() {
2039 assert!(matches!(object_descriptor, ObjectDescriptor::Directory));
2040 if object_id == dst_oid {
2041 encrypted_dst_name = Some(name.to_string());
2042 } else if object_id == src_oid {
2043 encrypted_src_name = Some(name.to_string());
2044 }
2045 iter.advance().await.expect("iter advance failed");
2046 }
2047
2048 let src_child = parent_directory
2049 .lookup(&encrypted_src_name.expect("src child not found"))
2050 .await
2051 .expect("lookup failed")
2052 .expect("not found");
2053 let mut transaction = fs
2054 .clone()
2055 .new_transaction(
2056 lock_keys![LockKey::object(
2057 store.store_object_id(),
2058 parent_directory.object_id(),
2059 )],
2060 Options::default(),
2061 )
2062 .await
2063 .expect("new transaction failed");
2064 replace_child_with_object(
2065 &mut transaction,
2066 Some((src_child.0, src_child.1)),
2067 (&parent_directory, &encrypted_dst_name.expect("dst child not found")),
2068 0,
2069 Timestamp::now(),
2070 )
2071 .await
2072 .expect_err("renames should fail within a locked directory");
2073 }
2074 fs.close().await.expect("Close failed");
2075 }
2076
2077 #[fuchsia::test]
2078 async fn test_set_encryption_policy_on_unencrypted_file() {
2079 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2080 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2081 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2082 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
2083 let store = root_volume
2084 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
2085 .await
2086 .expect("new_volume failed");
2087
2088 let mut transaction = fs
2089 .clone()
2090 .new_transaction(
2091 lock_keys![LockKey::object(
2092 store.store_object_id(),
2093 store.root_directory_object_id()
2094 )],
2095 Options::default(),
2096 )
2097 .await
2098 .expect("new transaction failed");
2099 let root_directory =
2100 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2101 let file_handle = root_directory
2102 .create_child_file(&mut transaction, "foo")
2103 .await
2104 .expect("create_child_dir failed");
2105 transaction.commit().await.expect("commit failed");
2106 let mut transaction = fs
2107 .clone()
2108 .new_transaction(
2109 lock_keys![LockKey::object(store.store_object_id(), file_handle.object_id())],
2110 Options::default(),
2111 )
2112 .await
2113 .expect("new transaction failed");
2114 let mut wrapping_key_id = [0; 16];
2115 wrapping_key_id[0] = 2;
2116 file_handle
2117 .update_attributes(
2118 &mut transaction,
2119 Some(&fio::MutableNodeAttributes {
2120 wrapping_key_id: Some(wrapping_key_id),
2121 ..Default::default()
2122 }),
2123 None,
2124 )
2125 .await
2126 .expect_err("Cannot update the wrapping key id of a file");
2127 fs.close().await.expect("Close failed");
2128 }
2129
2130 #[fuchsia::test]
2131 async fn test_delete_child() {
2132 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2133 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2134 let dir;
2135 let child;
2136 let mut transaction = fs
2137 .clone()
2138 .new_transaction(lock_keys![], Options::default())
2139 .await
2140 .expect("new_transaction failed");
2141 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2142 .await
2143 .expect("create failed");
2144
2145 child =
2146 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2147 transaction.commit().await.expect("commit failed");
2148
2149 transaction = fs
2150 .clone()
2151 .new_transaction(
2152 lock_keys![
2153 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2154 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2155 ],
2156 Options::default(),
2157 )
2158 .await
2159 .expect("new_transaction failed");
2160 assert_matches!(
2161 replace_child(&mut transaction, None, (&dir, "foo"))
2162 .await
2163 .expect("replace_child failed"),
2164 ReplacedChild::Object(..)
2165 );
2166 transaction.commit().await.expect("commit failed");
2167
2168 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2169 fs.close().await.expect("Close failed");
2170 }
2171
2172 #[fuchsia::test]
2173 async fn test_delete_child_with_children_fails() {
2174 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2175 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2176 let dir;
2177 let child;
2178 let bar;
2179 let mut transaction = fs
2180 .clone()
2181 .new_transaction(lock_keys![], Options::default())
2182 .await
2183 .expect("new_transaction failed");
2184 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2185 .await
2186 .expect("create failed");
2187
2188 child =
2189 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2190 bar = child
2191 .create_child_file(&mut transaction, "bar")
2192 .await
2193 .expect("create_child_file failed");
2194 transaction.commit().await.expect("commit failed");
2195
2196 transaction = fs
2197 .clone()
2198 .new_transaction(
2199 lock_keys![
2200 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2201 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2202 ],
2203 Options::default(),
2204 )
2205 .await
2206 .expect("new_transaction failed");
2207 assert_eq!(
2208 replace_child(&mut transaction, None, (&dir, "foo"))
2209 .await
2210 .expect_err("replace_child succeeded")
2211 .downcast::<FxfsError>()
2212 .expect("wrong error"),
2213 FxfsError::NotEmpty
2214 );
2215 transaction.commit().await.expect("commit failed");
2216
2217 transaction = fs
2218 .clone()
2219 .new_transaction(
2220 lock_keys![
2221 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2222 LockKey::object(fs.root_store().store_object_id(), bar.object_id()),
2223 ],
2224 Options::default(),
2225 )
2226 .await
2227 .expect("new_transaction failed");
2228 assert_matches!(
2229 replace_child(&mut transaction, None, (&child, "bar"))
2230 .await
2231 .expect("replace_child failed"),
2232 ReplacedChild::Object(..)
2233 );
2234 transaction.commit().await.expect("commit failed");
2235
2236 transaction = fs
2237 .clone()
2238 .new_transaction(
2239 lock_keys![
2240 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2241 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2242 ],
2243 Options::default(),
2244 )
2245 .await
2246 .expect("new_transaction failed");
2247 assert_matches!(
2248 replace_child(&mut transaction, None, (&dir, "foo"))
2249 .await
2250 .expect("replace_child failed"),
2251 ReplacedChild::Directory(..)
2252 );
2253 transaction.commit().await.expect("commit failed");
2254
2255 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2256 fs.close().await.expect("Close failed");
2257 }
2258
2259 #[fuchsia::test]
2260 async fn test_delete_and_reinsert_child() {
2261 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2262 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2263 let dir;
2264 let child;
2265 let mut transaction = fs
2266 .clone()
2267 .new_transaction(lock_keys![], Options::default())
2268 .await
2269 .expect("new_transaction failed");
2270 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2271 .await
2272 .expect("create failed");
2273
2274 child =
2275 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2276 transaction.commit().await.expect("commit failed");
2277
2278 transaction = fs
2279 .clone()
2280 .new_transaction(
2281 lock_keys![
2282 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2283 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2284 ],
2285 Options::default(),
2286 )
2287 .await
2288 .expect("new_transaction failed");
2289 assert_matches!(
2290 replace_child(&mut transaction, None, (&dir, "foo"))
2291 .await
2292 .expect("replace_child failed"),
2293 ReplacedChild::Object(..)
2294 );
2295 transaction.commit().await.expect("commit failed");
2296
2297 transaction = fs
2298 .clone()
2299 .new_transaction(
2300 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2301 Options::default(),
2302 )
2303 .await
2304 .expect("new_transaction failed");
2305 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2306 transaction.commit().await.expect("commit failed");
2307
2308 dir.lookup("foo").await.expect("lookup failed");
2309 fs.close().await.expect("Close failed");
2310 }
2311
2312 #[fuchsia::test]
2313 async fn test_delete_child_persists() {
2314 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2315 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2316 let object_id = {
2317 let dir;
2318 let child;
2319 let mut transaction = fs
2320 .clone()
2321 .new_transaction(lock_keys![], Options::default())
2322 .await
2323 .expect("new_transaction failed");
2324 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2325 .await
2326 .expect("create failed");
2327
2328 child = dir
2329 .create_child_file(&mut transaction, "foo")
2330 .await
2331 .expect("create_child_file failed");
2332 transaction.commit().await.expect("commit failed");
2333 dir.lookup("foo").await.expect("lookup failed");
2334
2335 transaction = fs
2336 .clone()
2337 .new_transaction(
2338 lock_keys![
2339 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2340 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2341 ],
2342 Options::default(),
2343 )
2344 .await
2345 .expect("new_transaction failed");
2346 assert_matches!(
2347 replace_child(&mut transaction, None, (&dir, "foo"))
2348 .await
2349 .expect("replace_child failed"),
2350 ReplacedChild::Object(..)
2351 );
2352 transaction.commit().await.expect("commit failed");
2353
2354 fs.sync(SyncOptions::default()).await.expect("sync failed");
2355 dir.object_id()
2356 };
2357
2358 fs.close().await.expect("Close failed");
2359 let device = fs.take_device().await;
2360 device.reopen(false);
2361 let fs = FxFilesystem::open(device).await.expect("open failed");
2362 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2363 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2364 fs.close().await.expect("Close failed");
2365 }
2366
2367 #[fuchsia::test]
2368 async fn test_replace_child() {
2369 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2370 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2371 let dir;
2372 let child_dir1;
2373 let child_dir2;
2374 let mut transaction = fs
2375 .clone()
2376 .new_transaction(lock_keys![], Options::default())
2377 .await
2378 .expect("new_transaction failed");
2379 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2380 .await
2381 .expect("create failed");
2382
2383 child_dir1 =
2384 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2385 child_dir2 =
2386 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2387 let file = child_dir1
2388 .create_child_file(&mut transaction, "foo")
2389 .await
2390 .expect("create_child_file failed");
2391 transaction.commit().await.expect("commit failed");
2392
2393 transaction = fs
2394 .clone()
2395 .new_transaction(
2396 lock_keys![
2397 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2398 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2399 LockKey::object(fs.root_store().store_object_id(), file.object_id()),
2400 ],
2401 Options::default(),
2402 )
2403 .await
2404 .expect("new_transaction failed");
2405 assert_matches!(
2406 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2407 .await
2408 .expect("replace_child failed"),
2409 ReplacedChild::None
2410 );
2411 transaction.commit().await.expect("commit failed");
2412
2413 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2414 child_dir2.lookup("bar").await.expect("lookup failed");
2415 fs.close().await.expect("Close failed");
2416 }
2417
2418 #[fuchsia::test]
2419 async fn test_replace_child_overwrites_dst() {
2420 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2421 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2422 let dir;
2423 let child_dir1;
2424 let child_dir2;
2425 let mut transaction = fs
2426 .clone()
2427 .new_transaction(lock_keys![], Options::default())
2428 .await
2429 .expect("new_transaction failed");
2430 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2431 .await
2432 .expect("create failed");
2433
2434 child_dir1 =
2435 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2436 child_dir2 =
2437 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2438 let foo = child_dir1
2439 .create_child_file(&mut transaction, "foo")
2440 .await
2441 .expect("create_child_file failed");
2442 let bar = child_dir2
2443 .create_child_file(&mut transaction, "bar")
2444 .await
2445 .expect("create_child_file failed");
2446 let foo_oid = foo.object_id();
2447 let bar_oid = bar.object_id();
2448 transaction.commit().await.expect("commit failed");
2449
2450 {
2451 let mut buf = foo.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2452 buf.as_mut_slice().fill(0xaa);
2453 foo.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2454 buf.as_mut_slice().fill(0xbb);
2455 bar.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2456 }
2457 std::mem::drop(bar);
2458 std::mem::drop(foo);
2459
2460 transaction = fs
2461 .clone()
2462 .new_transaction(
2463 lock_keys![
2464 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2465 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2466 LockKey::object(fs.root_store().store_object_id(), foo_oid),
2467 LockKey::object(fs.root_store().store_object_id(), bar_oid),
2468 ],
2469 Options::default(),
2470 )
2471 .await
2472 .expect("new_transaction failed");
2473 assert_matches!(
2474 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2475 .await
2476 .expect("replace_child failed"),
2477 ReplacedChild::Object(..)
2478 );
2479 transaction.commit().await.expect("commit failed");
2480
2481 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2482
2483 let (oid, object_descriptor, _) =
2485 child_dir2.lookup("bar").await.expect("lookup failed").expect("not found");
2486 assert_eq!(object_descriptor, ObjectDescriptor::File);
2487 let bar =
2488 ObjectStore::open_object(&child_dir2.owner(), oid, HandleOptions::default(), None)
2489 .await
2490 .expect("Open failed");
2491 let mut buf = bar.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2492 bar.read(0, buf.as_mut()).await.expect("read failed");
2493 assert_eq!(buf.as_slice(), vec![0xaa; TEST_DEVICE_BLOCK_SIZE as usize]);
2494 fs.close().await.expect("Close failed");
2495 }
2496
2497 #[fuchsia::test]
2498 async fn test_replace_child_fails_if_would_overwrite_nonempty_dir() {
2499 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2500 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2501 let dir;
2502 let child_dir1;
2503 let child_dir2;
2504 let mut transaction = fs
2505 .clone()
2506 .new_transaction(lock_keys![], Options::default())
2507 .await
2508 .expect("new_transaction failed");
2509 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2510 .await
2511 .expect("create failed");
2512
2513 child_dir1 =
2514 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2515 child_dir2 =
2516 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2517 let foo = child_dir1
2518 .create_child_file(&mut transaction, "foo")
2519 .await
2520 .expect("create_child_file failed");
2521 let nested_child = child_dir2
2522 .create_child_dir(&mut transaction, "bar")
2523 .await
2524 .expect("create_child_file failed");
2525 nested_child
2526 .create_child_file(&mut transaction, "baz")
2527 .await
2528 .expect("create_child_file failed");
2529 transaction.commit().await.expect("commit failed");
2530
2531 transaction = fs
2532 .clone()
2533 .new_transaction(
2534 lock_keys![
2535 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2536 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2537 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2538 LockKey::object(fs.root_store().store_object_id(), nested_child.object_id()),
2539 ],
2540 Options::default(),
2541 )
2542 .await
2543 .expect("new_transaction failed");
2544 assert_eq!(
2545 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2546 .await
2547 .expect_err("replace_child succeeded")
2548 .downcast::<FxfsError>()
2549 .expect("wrong error"),
2550 FxfsError::NotEmpty
2551 );
2552 fs.close().await.expect("Close failed");
2553 }
2554
2555 #[fuchsia::test]
2556 async fn test_replace_child_within_dir() {
2557 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2558 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2559 let dir;
2560 let mut transaction = fs
2561 .clone()
2562 .new_transaction(lock_keys![], Options::default())
2563 .await
2564 .expect("new_transaction failed");
2565 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2566 .await
2567 .expect("create failed");
2568 let foo =
2569 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2570 transaction.commit().await.expect("commit failed");
2571
2572 transaction = fs
2573 .clone()
2574 .new_transaction(
2575 lock_keys![
2576 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2577 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2578 ],
2579 Options::default(),
2580 )
2581 .await
2582 .expect("new_transaction failed");
2583 assert_matches!(
2584 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
2585 .await
2586 .expect("replace_child failed"),
2587 ReplacedChild::None
2588 );
2589 transaction.commit().await.expect("commit failed");
2590
2591 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2592 dir.lookup("bar").await.expect("lookup new name failed");
2593 fs.close().await.expect("Close failed");
2594 }
2595
2596 #[fuchsia::test]
2597 async fn test_iterate() {
2598 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2599 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2600 let dir;
2601 let mut transaction = fs
2602 .clone()
2603 .new_transaction(lock_keys![], Options::default())
2604 .await
2605 .expect("new_transaction failed");
2606 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2607 .await
2608 .expect("create failed");
2609 let _cat =
2610 dir.create_child_file(&mut transaction, "cat").await.expect("create_child_file failed");
2611 let _ball = dir
2612 .create_child_file(&mut transaction, "ball")
2613 .await
2614 .expect("create_child_file failed");
2615 let apple = dir
2616 .create_child_file(&mut transaction, "apple")
2617 .await
2618 .expect("create_child_file failed");
2619 let _dog =
2620 dir.create_child_file(&mut transaction, "dog").await.expect("create_child_file failed");
2621 transaction.commit().await.expect("commit failed");
2622 transaction = fs
2623 .clone()
2624 .new_transaction(
2625 lock_keys![
2626 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2627 LockKey::object(fs.root_store().store_object_id(), apple.object_id()),
2628 ],
2629 Options::default(),
2630 )
2631 .await
2632 .expect("new_transaction failed");
2633 replace_child(&mut transaction, None, (&dir, "apple")).await.expect("replace_child failed");
2634 transaction.commit().await.expect("commit failed");
2635 let layer_set = dir.store().tree().layer_set();
2636 let mut merger = layer_set.merger();
2637 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
2638 let mut entries = Vec::new();
2639 while let Some((name, _, _)) = iter.get() {
2640 entries.push(name.to_string());
2641 iter.advance().await.expect("advance failed");
2642 }
2643 assert_eq!(&entries, &["ball", "cat", "dog"]);
2644 fs.close().await.expect("Close failed");
2645 }
2646
2647 #[fuchsia::test]
2648 async fn test_sub_dir_count() {
2649 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2650 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2651 let dir;
2652 let child_dir;
2653 let mut transaction = fs
2654 .clone()
2655 .new_transaction(lock_keys![], Options::default())
2656 .await
2657 .expect("new_transaction failed");
2658 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2659 .await
2660 .expect("create failed");
2661 child_dir =
2662 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2663 transaction.commit().await.expect("commit failed");
2664 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2665
2666 transaction = fs
2668 .clone()
2669 .new_transaction(
2670 lock_keys![
2671 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2672 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2673 ],
2674 Options::default(),
2675 )
2676 .await
2677 .expect("new_transaction failed");
2678 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
2679 .await
2680 .expect("replace_child failed");
2681 transaction.commit().await.expect("commit failed");
2682
2683 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2684 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2685
2686 transaction = fs
2688 .clone()
2689 .new_transaction(
2690 lock_keys![LockKey::object(
2691 fs.root_store().store_object_id(),
2692 child_dir.object_id()
2693 )],
2694 Options::default(),
2695 )
2696 .await
2697 .expect("new_transaction failed");
2698 let second_child = child_dir
2699 .create_child_dir(&mut transaction, "baz")
2700 .await
2701 .expect("create_child_dir failed");
2702 transaction.commit().await.expect("commit failed");
2703
2704 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2705
2706 transaction = fs
2707 .clone()
2708 .new_transaction(
2709 lock_keys![
2710 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2711 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2712 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
2713 ],
2714 Options::default(),
2715 )
2716 .await
2717 .expect("new_transaction failed");
2718 replace_child(&mut transaction, Some((&child_dir, "baz")), (&dir, "foo"))
2719 .await
2720 .expect("replace_child failed");
2721 transaction.commit().await.expect("commit failed");
2722
2723 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 2);
2724 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2725
2726 transaction = fs
2728 .clone()
2729 .new_transaction(
2730 lock_keys![
2731 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2732 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
2733 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2734 ],
2735 Options::default(),
2736 )
2737 .await
2738 .expect("new_transaction failed");
2739 replace_child(&mut transaction, Some((&dir, "bar")), (&dir, "foo"))
2740 .await
2741 .expect("replace_child failed");
2742 transaction.commit().await.expect("commit failed");
2743
2744 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2745
2746 transaction = fs
2748 .clone()
2749 .new_transaction(
2750 lock_keys![
2751 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2752 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2753 ],
2754 Options::default(),
2755 )
2756 .await
2757 .expect("new_transaction failed");
2758 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
2759 transaction.commit().await.expect("commit failed");
2760
2761 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2762 fs.close().await.expect("Close failed");
2763 }
2764
2765 #[fuchsia::test]
2766 async fn test_deleted_dir() {
2767 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2768 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2769 let dir;
2770 let mut transaction = fs
2771 .clone()
2772 .new_transaction(lock_keys![], Options::default())
2773 .await
2774 .expect("new_transaction failed");
2775 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2776 .await
2777 .expect("create failed");
2778 let child =
2779 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2780 dir.create_child_dir(&mut transaction, "bar").await.expect("create_child_dir failed");
2781 transaction.commit().await.expect("commit failed");
2782
2783 dir.store().flush().await.expect("flush failed");
2785
2786 transaction = fs
2788 .clone()
2789 .new_transaction(
2790 lock_keys![
2791 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2792 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2793 ],
2794 Options::default(),
2795 )
2796 .await
2797 .expect("new_transaction failed");
2798 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
2799 transaction.commit().await.expect("commit failed");
2800
2801 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2803
2804 assert!(dir.lookup("bar").await.expect("lookup failed").is_some());
2806
2807 dir.set_deleted();
2809
2810 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2811 assert_eq!(dir.lookup("bar").await.expect("lookup failed"), None);
2812 assert!(!dir.has_children().await.expect("has_children failed"));
2813
2814 transaction = fs
2815 .clone()
2816 .new_transaction(lock_keys![], Options::default())
2817 .await
2818 .expect("new_transaction failed");
2819
2820 let assert_access_denied = |result| {
2821 if let Err(e) = result {
2822 assert!(FxfsError::Deleted.matches(&e));
2823 } else {
2824 panic!();
2825 }
2826 };
2827 assert_access_denied(dir.create_child_dir(&mut transaction, "baz").await.map(|_| {}));
2828 assert_access_denied(dir.create_child_file(&mut transaction, "baz").await.map(|_| {}));
2829 assert_access_denied(dir.add_child_volume(&mut transaction, "baz", 1).await);
2830 assert_access_denied(
2831 dir.insert_child(&mut transaction, "baz", 1, ObjectDescriptor::File).await,
2832 );
2833 assert_access_denied(
2834 dir.update_dir_attributes_internal(
2835 &mut transaction,
2836 dir.object_id(),
2837 MutableAttributesInternal {
2838 creation_time: Some(Timestamp::zero().as_nanos()),
2839 ..Default::default()
2840 },
2841 )
2842 .await,
2843 );
2844 let layer_set = dir.store().tree().layer_set();
2845 let mut merger = layer_set.merger();
2846 assert_access_denied(dir.iter(&mut merger).await.map(|_| {}));
2847 }
2848
2849 #[fuchsia::test]
2850 async fn test_create_symlink() {
2851 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2852 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2853 let (dir_id, symlink_id) = {
2854 let mut transaction = fs
2855 .clone()
2856 .new_transaction(lock_keys![], Options::default())
2857 .await
2858 .expect("new_transaction failed");
2859 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
2860 .await
2861 .expect("create failed");
2862
2863 let symlink_id = dir
2864 .create_symlink(&mut transaction, b"link", "foo")
2865 .await
2866 .expect("create_symlink failed");
2867 transaction.commit().await.expect("commit failed");
2868
2869 fs.sync(SyncOptions::default()).await.expect("sync failed");
2870 (dir.object_id(), symlink_id)
2871 };
2872 fs.close().await.expect("Close failed");
2873 let device = fs.take_device().await;
2874 device.reopen(false);
2875 let fs = FxFilesystem::open(device).await.expect("open failed");
2876 {
2877 let dir = Directory::open(&fs.root_store(), dir_id).await.expect("open failed");
2878 assert_eq!(
2879 dir.lookup("foo").await.expect("lookup failed").expect("not found"),
2880 (symlink_id, ObjectDescriptor::Symlink, false)
2881 );
2882 }
2883 fs.close().await.expect("Close failed");
2884 }
2885
2886 #[fuchsia::test]
2887 async fn test_read_symlink() {
2888 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2889 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2890 let mut transaction = fs
2891 .clone()
2892 .new_transaction(lock_keys![], Options::default())
2893 .await
2894 .expect("new_transaction failed");
2895 let store = fs.root_store();
2896 let dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
2897
2898 let symlink_id = dir
2899 .create_symlink(&mut transaction, b"link", "foo")
2900 .await
2901 .expect("create_symlink failed");
2902 transaction.commit().await.expect("commit failed");
2903
2904 let link = store.read_symlink(symlink_id).await.expect("read_symlink failed");
2905 assert_eq!(&link, b"link");
2906 fs.close().await.expect("Close failed");
2907 }
2908
2909 #[fuchsia::test]
2910 async fn test_unlink_symlink() {
2911 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2912 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2913 let dir;
2914 let mut transaction = fs
2915 .clone()
2916 .new_transaction(lock_keys![], Options::default())
2917 .await
2918 .expect("new_transaction failed");
2919 let store = fs.root_store();
2920 dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
2921
2922 let symlink_id = dir
2923 .create_symlink(&mut transaction, b"link", "foo")
2924 .await
2925 .expect("create_symlink failed");
2926 transaction.commit().await.expect("commit failed");
2927 transaction = fs
2928 .clone()
2929 .new_transaction(
2930 lock_keys![
2931 LockKey::object(store.store_object_id(), dir.object_id()),
2932 LockKey::object(store.store_object_id(), symlink_id),
2933 ],
2934 Options::default(),
2935 )
2936 .await
2937 .expect("new_transaction failed");
2938 assert_matches!(
2939 replace_child(&mut transaction, None, (&dir, "foo"))
2940 .await
2941 .expect("replace_child failed"),
2942 ReplacedChild::Object(_)
2943 );
2944 transaction.commit().await.expect("commit failed");
2945
2946 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2947 fs.close().await.expect("Close failed");
2948 }
2949
2950 #[fuchsia::test]
2951 async fn test_get_properties() {
2952 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2953 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2954 let dir;
2955 let mut transaction = fs
2956 .clone()
2957 .new_transaction(lock_keys![], Options::default())
2958 .await
2959 .expect("new_transaction failed");
2960
2961 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2962 .await
2963 .expect("create failed");
2964 transaction.commit().await.expect("commit failed");
2965
2966 let mut properties = dir.get_properties().await.expect("get_properties failed");
2968 let dir_creation_time = properties.creation_time;
2969 assert_eq!(dir_creation_time, properties.modification_time);
2970 assert_eq!(properties.sub_dirs, 0);
2971 assert!(properties.posix_attributes.is_none());
2972
2973 transaction = fs
2975 .clone()
2976 .new_transaction(
2977 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2978 Options::default(),
2979 )
2980 .await
2981 .expect("new_transaction failed");
2982 let child_dir =
2983 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2984 transaction.commit().await.expect("commit failed");
2985
2986 properties = dir.get_properties().await.expect("get_properties failed");
2988 assert_eq!(dir_creation_time, properties.creation_time);
2990 assert!(dir_creation_time < properties.modification_time);
2991 assert_eq!(properties.sub_dirs, 1);
2992 assert!(properties.posix_attributes.is_none());
2993
2994 properties = child_dir.get_properties().await.expect("get_properties failed");
2996 assert_eq!(properties.creation_time, properties.modification_time);
2997 assert_eq!(properties.sub_dirs, 0);
2998 assert!(properties.posix_attributes.is_none());
2999
3000 transaction = fs
3002 .clone()
3003 .new_transaction(
3004 lock_keys![LockKey::object(
3005 fs.root_store().store_object_id(),
3006 child_dir.object_id()
3007 )],
3008 Options::default(),
3009 )
3010 .await
3011 .expect("new_transaction failed");
3012 let child_dir_file = child_dir
3013 .create_child_file(&mut transaction, "bar")
3014 .await
3015 .expect("create_child_file failed");
3016 child_dir_file
3017 .update_attributes(
3018 &mut transaction,
3019 Some(&fio::MutableNodeAttributes { gid: Some(1), ..Default::default() }),
3020 None,
3021 )
3022 .await
3023 .expect("Updating attributes");
3024 transaction.commit().await.expect("commit failed");
3025
3026 properties = child_dir.get_properties().await.expect("get_properties failed");
3028 assert!(properties.creation_time < properties.modification_time);
3029 assert!(properties.posix_attributes.is_none());
3030
3031 properties = child_dir_file.get_properties().await.expect("get_properties failed");
3033 assert_eq!(properties.creation_time, properties.modification_time);
3034 assert_eq!(properties.sub_dirs, 0);
3035 assert!(properties.posix_attributes.is_some());
3036 assert_eq!(properties.posix_attributes.unwrap().gid, 1);
3037 assert_eq!(properties.posix_attributes.unwrap().uid, 0);
3039 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3040 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3041 }
3042
3043 #[fuchsia::test]
3044 async fn test_update_create_attributes() {
3045 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3046 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3047 let dir;
3048 let mut transaction = fs
3049 .clone()
3050 .new_transaction(lock_keys![], Options::default())
3051 .await
3052 .expect("new_transaction failed");
3053
3054 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3055 .await
3056 .expect("create failed");
3057 transaction.commit().await.expect("commit failed");
3058 let mut properties = dir.get_properties().await.expect("get_properties failed");
3059 assert_eq!(properties.sub_dirs, 0);
3060 assert!(properties.posix_attributes.is_none());
3061 let creation_time = properties.creation_time;
3062 let modification_time = properties.modification_time;
3063 assert_eq!(creation_time, modification_time);
3064
3065 transaction = fs
3071 .clone()
3072 .new_transaction(
3073 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3074 Options::default(),
3075 )
3076 .await
3077 .expect("new_transaction failed");
3078 let now = Timestamp::now();
3079 dir.update_attributes(
3080 transaction,
3081 Some(&fio::MutableNodeAttributes {
3082 modification_time: Some(now.as_nanos()),
3083 uid: Some(1),
3084 gid: Some(2),
3085 ..Default::default()
3086 }),
3087 0,
3088 None,
3089 )
3090 .await
3091 .expect("update_attributes failed");
3092 properties = dir.get_properties().await.expect("get_properties failed");
3093 assert_eq!(properties.modification_time, now);
3095 assert!(properties.posix_attributes.is_some());
3096 assert_eq!(properties.posix_attributes.unwrap().uid, 1);
3097 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3098 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3100 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3101 assert_eq!(properties.sub_dirs, 0);
3103 assert_eq!(properties.creation_time, creation_time);
3104
3105 let transaction = fs
3108 .clone()
3109 .new_transaction(
3110 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3111 Options::default(),
3112 )
3113 .await
3114 .expect("new_transaction failed");
3115 dir.update_attributes(
3116 transaction,
3117 Some(&fio::MutableNodeAttributes {
3118 creation_time: Some(now.as_nanos()),
3119 uid: Some(3),
3120 rdev: Some(10),
3121 ..Default::default()
3122 }),
3123 0,
3124 None,
3125 )
3126 .await
3127 .expect("update_attributes failed");
3128 properties = dir.get_properties().await.expect("get_properties failed");
3129 assert_eq!(properties.creation_time, now);
3130 assert!(properties.posix_attributes.is_some());
3131 assert_eq!(properties.posix_attributes.unwrap().uid, 3);
3132 assert_eq!(properties.posix_attributes.unwrap().rdev, 10);
3133 assert_eq!(properties.sub_dirs, 0);
3135 assert_eq!(properties.modification_time, now);
3136 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3137 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3138 }
3139
3140 #[fuchsia::test]
3141 async fn write_to_directory_attribute_creates_keys() {
3142 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3143 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3144 let crypt = Arc::new(InsecureCrypt::new());
3145
3146 {
3147 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3148 let store = root_volume
3149 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3150 .await
3151 .expect("new_volume failed");
3152 let mut transaction = filesystem
3153 .clone()
3154 .new_transaction(
3155 lock_keys![LockKey::object(
3156 store.store_object_id(),
3157 store.root_directory_object_id()
3158 )],
3159 Options::default(),
3160 )
3161 .await
3162 .expect("new transaction failed");
3163 let root_directory = Directory::open(&store, store.root_directory_object_id())
3164 .await
3165 .expect("open failed");
3166 let directory = root_directory
3167 .create_child_dir(&mut transaction, "foo")
3168 .await
3169 .expect("create_child_dir failed");
3170 transaction.commit().await.expect("commit failed");
3171
3172 let mut transaction = filesystem
3173 .clone()
3174 .new_transaction(
3175 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
3176 Options::default(),
3177 )
3178 .await
3179 .expect("new transaction failed");
3180 let _ = directory
3181 .handle
3182 .write_attr(&mut transaction, 1, b"bar")
3183 .await
3184 .expect("write_attr failed");
3185 transaction.commit().await.expect("commit failed");
3186 }
3187
3188 filesystem.close().await.expect("Close failed");
3189 let device = filesystem.take_device().await;
3190 device.reopen(false);
3191 let filesystem = FxFilesystem::open(device).await.expect("open failed");
3192
3193 {
3194 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3195 let volume =
3196 root_volume.volume("vol", NO_OWNER, Some(crypt)).await.expect("volume failed");
3197 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
3198 .await
3199 .expect("open failed");
3200 let directory = Directory::open(
3201 &volume,
3202 root_directory.lookup("foo").await.expect("lookup failed").expect("not found").0,
3203 )
3204 .await
3205 .expect("open failed");
3206 let mut buffer = directory.handle.allocate_buffer(10).await;
3207 assert_eq!(directory.handle.read(1, 0, buffer.as_mut()).await.expect("read failed"), 3);
3208 assert_eq!(&buffer.as_slice()[..3], b"bar");
3209 }
3210
3211 filesystem.close().await.expect("Close failed");
3212 }
3213
3214 #[fuchsia::test]
3215 async fn directory_with_extended_attributes() {
3216 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3217 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3218 let crypt = Arc::new(InsecureCrypt::new());
3219
3220 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3221 let store = root_volume
3222 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3223 .await
3224 .expect("new_volume failed");
3225 let directory =
3226 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3227
3228 let test_small_name = b"security.selinux".to_vec();
3229 let test_small_value = b"foo".to_vec();
3230 let test_large_name = b"large.attribute".to_vec();
3231 let test_large_value = vec![1u8; 500];
3232
3233 directory
3234 .set_extended_attribute(
3235 test_small_name.clone(),
3236 test_small_value.clone(),
3237 SetExtendedAttributeMode::Set,
3238 )
3239 .await
3240 .unwrap();
3241 assert_eq!(
3242 directory.get_extended_attribute(test_small_name.clone()).await.unwrap(),
3243 test_small_value
3244 );
3245
3246 directory
3247 .set_extended_attribute(
3248 test_large_name.clone(),
3249 test_large_value.clone(),
3250 SetExtendedAttributeMode::Set,
3251 )
3252 .await
3253 .unwrap();
3254 assert_eq!(
3255 directory.get_extended_attribute(test_large_name.clone()).await.unwrap(),
3256 test_large_value
3257 );
3258
3259 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3260 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3261 .await
3262 .unwrap();
3263
3264 directory.remove_extended_attribute(test_small_name.clone()).await.unwrap();
3265 directory.remove_extended_attribute(test_large_name.clone()).await.unwrap();
3266
3267 filesystem.close().await.expect("close failed");
3268 }
3269
3270 #[fuchsia::test]
3271 async fn remove_directory_with_extended_attributes() {
3272 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3273 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3274 let crypt = Arc::new(InsecureCrypt::new());
3275
3276 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3277 let store = root_volume
3278 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3279 .await
3280 .expect("new_volume failed");
3281 let mut transaction = filesystem
3282 .clone()
3283 .new_transaction(
3284 lock_keys![LockKey::object(
3285 store.store_object_id(),
3286 store.root_directory_object_id()
3287 )],
3288 Options::default(),
3289 )
3290 .await
3291 .expect("new transaction failed");
3292 let root_directory =
3293 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3294 let directory = root_directory
3295 .create_child_dir(&mut transaction, "foo")
3296 .await
3297 .expect("create_child_dir failed");
3298 transaction.commit().await.expect("commit failed");
3299
3300 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3301 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3302 .await
3303 .unwrap();
3304
3305 let test_small_name = b"security.selinux".to_vec();
3306 let test_small_value = b"foo".to_vec();
3307 let test_large_name = b"large.attribute".to_vec();
3308 let test_large_value = vec![1u8; 500];
3309
3310 directory
3311 .set_extended_attribute(
3312 test_small_name.clone(),
3313 test_small_value.clone(),
3314 SetExtendedAttributeMode::Set,
3315 )
3316 .await
3317 .unwrap();
3318 directory
3319 .set_extended_attribute(
3320 test_large_name.clone(),
3321 test_large_value.clone(),
3322 SetExtendedAttributeMode::Set,
3323 )
3324 .await
3325 .unwrap();
3326
3327 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3328 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3329 .await
3330 .unwrap();
3331
3332 let mut transaction = filesystem
3333 .clone()
3334 .new_transaction(
3335 lock_keys![
3336 LockKey::object(store.store_object_id(), root_directory.object_id()),
3337 LockKey::object(store.store_object_id(), directory.object_id()),
3338 ],
3339 Options::default(),
3340 )
3341 .await
3342 .expect("new_transaction failed");
3343 replace_child(&mut transaction, None, (&root_directory, "foo"))
3344 .await
3345 .expect("replace_child failed");
3346 transaction.commit().await.unwrap();
3347
3348 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3349 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3350 .await
3351 .unwrap();
3352
3353 filesystem.close().await.expect("close failed");
3354 }
3355
3356 #[fuchsia::test]
3357 async fn remove_symlink_with_extended_attributes() {
3358 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3359 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3360 let crypt = Arc::new(InsecureCrypt::new());
3361
3362 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3363 let store = root_volume
3364 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3365 .await
3366 .expect("new_volume failed");
3367 let mut transaction = filesystem
3368 .clone()
3369 .new_transaction(
3370 lock_keys![LockKey::object(
3371 store.store_object_id(),
3372 store.root_directory_object_id()
3373 )],
3374 Options::default(),
3375 )
3376 .await
3377 .expect("new transaction failed");
3378 let root_directory =
3379 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3380 let symlink_id = root_directory
3381 .create_symlink(&mut transaction, b"somewhere/else", "foo")
3382 .await
3383 .expect("create_symlink failed");
3384 transaction.commit().await.expect("commit failed");
3385
3386 let symlink = StoreObjectHandle::new(
3387 store.clone(),
3388 symlink_id,
3389 false,
3390 HandleOptions::default(),
3391 false,
3392 );
3393
3394 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3395 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3396 .await
3397 .unwrap();
3398
3399 let test_small_name = b"security.selinux".to_vec();
3400 let test_small_value = b"foo".to_vec();
3401 let test_large_name = b"large.attribute".to_vec();
3402 let test_large_value = vec![1u8; 500];
3403
3404 symlink
3405 .set_extended_attribute(
3406 test_small_name.clone(),
3407 test_small_value.clone(),
3408 SetExtendedAttributeMode::Set,
3409 )
3410 .await
3411 .unwrap();
3412 symlink
3413 .set_extended_attribute(
3414 test_large_name.clone(),
3415 test_large_value.clone(),
3416 SetExtendedAttributeMode::Set,
3417 )
3418 .await
3419 .unwrap();
3420
3421 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3422 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3423 .await
3424 .unwrap();
3425
3426 let mut transaction = filesystem
3427 .clone()
3428 .new_transaction(
3429 lock_keys![
3430 LockKey::object(store.store_object_id(), root_directory.object_id()),
3431 LockKey::object(store.store_object_id(), symlink.object_id()),
3432 ],
3433 Options::default(),
3434 )
3435 .await
3436 .expect("new_transaction failed");
3437 replace_child(&mut transaction, None, (&root_directory, "foo"))
3438 .await
3439 .expect("replace_child failed");
3440 transaction.commit().await.unwrap();
3441
3442 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3443 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3444 .await
3445 .unwrap();
3446
3447 filesystem.close().await.expect("close failed");
3448 }
3449
3450 #[fuchsia::test]
3451 async fn test_update_timestamps() {
3452 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3453 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3454 let dir;
3455 let mut transaction = fs
3456 .clone()
3457 .new_transaction(lock_keys![], Options::default())
3458 .await
3459 .expect("new_transaction failed");
3460
3461 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3464 .await
3465 .expect("create failed");
3466 transaction.commit().await.expect("commit failed");
3467 let mut properties = dir.get_properties().await.expect("get_properties failed");
3468 let starting_time = properties.creation_time;
3469 assert_eq!(properties.creation_time, starting_time);
3470 assert_eq!(properties.modification_time, starting_time);
3471 assert_eq!(properties.change_time, starting_time);
3472 assert_eq!(properties.access_time, starting_time);
3473
3474 transaction = fs
3476 .clone()
3477 .new_transaction(
3478 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3479 Options::default(),
3480 )
3481 .await
3482 .expect("new_transaction failed");
3483 let update1_time = Timestamp::now();
3484 dir.update_attributes(
3485 transaction,
3486 Some(&fio::MutableNodeAttributes {
3487 modification_time: Some(update1_time.as_nanos()),
3488 ..Default::default()
3489 }),
3490 0,
3491 Some(update1_time),
3492 )
3493 .await
3494 .expect("update_attributes failed");
3495 properties = dir.get_properties().await.expect("get_properties failed");
3496 assert_eq!(properties.modification_time, update1_time);
3497 assert_eq!(properties.access_time, starting_time);
3498 assert_eq!(properties.creation_time, starting_time);
3499 assert_eq!(properties.change_time, update1_time);
3500 }
3501
3502 #[fuchsia::test]
3503 async fn test_move_dir_timestamps() {
3504 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3505 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3506 let dir;
3507 let child1;
3508 let child2;
3509 let mut transaction = fs
3510 .clone()
3511 .new_transaction(lock_keys![], Options::default())
3512 .await
3513 .expect("new_transaction failed");
3514 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3515 .await
3516 .expect("create failed");
3517 child1 = dir
3518 .create_child_dir(&mut transaction, "child1")
3519 .await
3520 .expect("create_child_dir failed");
3521 child2 = dir
3522 .create_child_dir(&mut transaction, "child2")
3523 .await
3524 .expect("create_child_dir failed");
3525 transaction.commit().await.expect("commit failed");
3526 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3527 let child2_properties = child2.get_properties().await.expect("get_properties failed");
3528
3529 transaction = fs
3531 .clone()
3532 .new_transaction(
3533 lock_keys![
3534 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3535 LockKey::object(fs.root_store().store_object_id(), child1.object_id()),
3536 LockKey::object(fs.root_store().store_object_id(), child2.object_id()),
3537 ],
3538 Options::default(),
3539 )
3540 .await
3541 .expect("new_transaction failed");
3542 assert_matches!(
3543 replace_child(&mut transaction, Some((&dir, "child2")), (&child1, "child2"))
3544 .await
3545 .expect("replace_child failed"),
3546 ReplacedChild::None
3547 );
3548 transaction.commit().await.expect("commit failed");
3549 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
3551 let time_of_replacement = new_dir_properties.change_time;
3552 assert!(new_dir_properties.change_time > dir_properties.change_time);
3553 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
3554 let new_child1_properties = child1.get_properties().await.expect("get_properties failed");
3556 assert_eq!(new_child1_properties.modification_time, time_of_replacement);
3557 assert_eq!(new_child1_properties.change_time, time_of_replacement);
3558 let moved_child2_properties = child2.get_properties().await.expect("get_properties failed");
3560 assert_eq!(moved_child2_properties.change_time, time_of_replacement);
3561 assert_eq!(moved_child2_properties.creation_time, child2_properties.creation_time);
3562 assert_eq!(moved_child2_properties.access_time, child2_properties.access_time);
3563 assert_eq!(moved_child2_properties.modification_time, child2_properties.modification_time);
3564 fs.close().await.expect("Close failed");
3565 }
3566
3567 #[fuchsia::test]
3568 async fn test_unlink_timestamps() {
3569 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3570 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3571 let dir;
3572 let foo;
3573 let mut transaction = fs
3574 .clone()
3575 .new_transaction(lock_keys![], Options::default())
3576 .await
3577 .expect("new_transaction failed");
3578 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3579 .await
3580 .expect("create failed");
3581 foo =
3582 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_dir failed");
3583
3584 transaction.commit().await.expect("commit failed");
3585 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3586 let foo_properties = foo.get_properties().await.expect("get_properties failed");
3587
3588 transaction = fs
3589 .clone()
3590 .new_transaction(
3591 lock_keys![
3592 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3593 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3594 ],
3595 Options::default(),
3596 )
3597 .await
3598 .expect("new_transaction failed");
3599 assert_matches!(
3600 replace_child(&mut transaction, None, (&dir, "foo"))
3601 .await
3602 .expect("replace_child failed"),
3603 ReplacedChild::Object(_)
3604 );
3605 transaction.commit().await.expect("commit failed");
3606 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
3608 let time_of_replacement = new_dir_properties.change_time;
3609 assert!(new_dir_properties.change_time > dir_properties.change_time);
3610 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
3611 let moved_foo_properties = foo.get_properties().await.expect("get_properties failed");
3613 assert_eq!(moved_foo_properties.change_time, time_of_replacement);
3614 assert_eq!(moved_foo_properties.creation_time, foo_properties.creation_time);
3615 assert_eq!(moved_foo_properties.access_time, foo_properties.access_time);
3616 assert_eq!(moved_foo_properties.modification_time, foo_properties.modification_time);
3617 fs.close().await.expect("Close failed");
3618 }
3619
3620 #[fuchsia::test]
3621 async fn test_replace_dir_timestamps() {
3622 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3623 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3624 let dir;
3625 let child_dir1;
3626 let child_dir2;
3627 let foo;
3628 let mut transaction = fs
3629 .clone()
3630 .new_transaction(lock_keys![], Options::default())
3631 .await
3632 .expect("new_transaction failed");
3633 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3634 .await
3635 .expect("create failed");
3636 child_dir1 =
3637 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
3638 child_dir2 =
3639 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
3640 foo = child_dir1
3641 .create_child_dir(&mut transaction, "foo")
3642 .await
3643 .expect("create_child_dir failed");
3644 transaction.commit().await.expect("commit failed");
3645 let dir_props = dir.get_properties().await.expect("get_properties failed");
3646 let foo_props = foo.get_properties().await.expect("get_properties failed");
3647
3648 transaction = fs
3649 .clone()
3650 .new_transaction(
3651 lock_keys![
3652 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3653 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
3654 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
3655 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3656 ],
3657 Options::default(),
3658 )
3659 .await
3660 .expect("new_transaction failed");
3661 assert_matches!(
3662 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&dir, "dir2"))
3663 .await
3664 .expect("replace_child failed"),
3665 ReplacedChild::Directory(_)
3666 );
3667 transaction.commit().await.expect("commit failed");
3668 let new_dir_props = dir.get_properties().await.expect("get_properties failed");
3670 let time_of_replacement = new_dir_props.change_time;
3671 assert!(new_dir_props.change_time > dir_props.change_time);
3672 assert_eq!(new_dir_props.modification_time, time_of_replacement);
3673 let new_dir1_props = child_dir1.get_properties().await.expect("get_properties failed");
3675 let time_of_replacement = new_dir1_props.change_time;
3676 assert_eq!(new_dir1_props.change_time, time_of_replacement);
3677 assert_eq!(new_dir1_props.modification_time, time_of_replacement);
3678 let moved_foo_props = foo.get_properties().await.expect("get_properties failed");
3680 assert_eq!(moved_foo_props.change_time, time_of_replacement);
3681 assert_eq!(moved_foo_props.creation_time, foo_props.creation_time);
3682 assert_eq!(moved_foo_props.access_time, foo_props.access_time);
3683 assert_eq!(moved_foo_props.modification_time, foo_props.modification_time);
3684 fs.close().await.expect("Close failed");
3685 }
3686
3687 #[fuchsia::test]
3688 async fn test_create_casefold_directory() {
3689 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3690 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3691 let object_id = {
3692 let mut transaction = fs
3693 .clone()
3694 .new_transaction(lock_keys![], Options::default())
3695 .await
3696 .expect("new_transaction failed");
3697 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
3698 .await
3699 .expect("create failed");
3700
3701 let child_dir = dir
3702 .create_child_dir(&mut transaction, "foo")
3703 .await
3704 .expect("create_child_dir failed");
3705 let _child_dir_file = child_dir
3706 .create_child_file(&mut transaction, "bAr")
3707 .await
3708 .expect("create_child_file failed");
3709 transaction.commit().await.expect("commit failed");
3710 dir.object_id()
3711 };
3712 fs.close().await.expect("Close failed");
3713 let device = fs.take_device().await;
3714
3715 device.reopen(false);
3718 let fs = FxFilesystem::open(device).await.expect("open failed");
3719 {
3720 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
3721 let (object_id, object_descriptor, _) =
3722 dir.lookup("foo").await.expect("lookup failed").expect("not found");
3723 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
3724 let child_dir =
3725 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
3726 assert!(!child_dir.casefold());
3727 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_none());
3728 let (object_id, descriptor, _) =
3729 child_dir.lookup("bAr").await.expect("lookup failed").unwrap();
3730 assert_eq!(descriptor, ObjectDescriptor::File);
3731
3732 child_dir.set_casefold(true).await.expect_err("not empty");
3734
3735 let mut transaction = fs
3737 .clone()
3738 .new_transaction(
3739 lock_keys![
3740 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3741 LockKey::object(fs.root_store().store_object_id(), object_id),
3742 ],
3743 Options::default(),
3744 )
3745 .await
3746 .expect("new_transaction failed");
3747 assert_matches!(
3748 replace_child(&mut transaction, None, (&child_dir, "bAr"))
3749 .await
3750 .expect("replace_child failed"),
3751 ReplacedChild::Object(..)
3752 );
3753 transaction.commit().await.expect("commit failed");
3754
3755 child_dir.set_casefold(true).await.expect("set casefold");
3757
3758 assert!(child_dir.casefold());
3759
3760 let mut transaction = fs
3762 .clone()
3763 .new_transaction(
3764 lock_keys![LockKey::object(
3765 fs.root_store().store_object_id(),
3766 child_dir.object_id()
3767 ),],
3768 Options::default(),
3769 )
3770 .await
3771 .expect("new_transaction failed");
3772 let _child_dir_file = child_dir
3773 .create_child_file(&mut transaction, "bAr")
3774 .await
3775 .expect("create_child_file failed");
3776 transaction.commit().await.expect("commit failed");
3777
3778 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_some());
3780 assert!(child_dir.lookup("bAr").await.expect("lookup failed").is_some());
3781
3782 child_dir.set_casefold(true).await.expect_err("set casefold");
3784 assert!(child_dir.casefold());
3785
3786 let mut transaction = fs
3788 .clone()
3789 .new_transaction(
3790 lock_keys![LockKey::object(
3791 fs.root_store().store_object_id(),
3792 child_dir.object_id()
3793 ),],
3794 Options::default(),
3795 )
3796 .await
3797 .expect("new_transaction failed");
3798 let sub_dir = child_dir
3799 .create_child_dir(&mut transaction, "sub")
3800 .await
3801 .expect("create_sub_dir failed");
3802 transaction.commit().await.expect("commit failed");
3803 assert!(sub_dir.casefold());
3804 };
3805 fs.close().await.expect("Close failed");
3806 }
3807
3808 #[fuchsia::test]
3809 async fn test_create_casefold_encrypted_directory() {
3810 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3811 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3812 let proxy_filename: ProxyFilename;
3813 let object_id;
3814 {
3815 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3816 let root_volume = root_volume(fs.clone()).await.unwrap();
3817 let store = root_volume.new_volume("vol", NO_OWNER, Some(crypt.clone())).await.unwrap();
3818
3819 let wrapping_key_id = 2;
3821 crypt.add_wrapping_key(wrapping_key_id, [1; 32]);
3822
3823 object_id = {
3824 let mut transaction = fs
3825 .clone()
3826 .new_transaction(
3827 lock_keys![LockKey::object(
3828 fs.root_store().store_object_id(),
3829 store.store_object_id()
3830 ),],
3831 Options::default(),
3832 )
3833 .await
3834 .expect("new_transaction failed");
3835 let dir = Directory::create(&mut transaction, &store, Some(wrapping_key_id))
3836 .await
3837 .expect("create failed");
3838
3839 transaction.commit().await.expect("commit");
3840 dir.object_id()
3841 };
3842 let dir = Directory::open(&store, object_id).await.expect("open failed");
3843
3844 dir.set_casefold(true).await.expect("set casefold");
3845 assert!(dir.casefold());
3846
3847 let mut transaction = fs
3848 .clone()
3849 .new_transaction(
3850 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
3851 Options::default(),
3852 )
3853 .await
3854 .expect("new_transaction failed");
3855 let _file = dir
3856 .create_child_file(&mut transaction, "bAr")
3857 .await
3858 .expect("create_child_file failed");
3859 transaction.commit().await.expect("commit failed");
3860
3861 assert!(dir.lookup("bAr").await.expect("original lookup failed").is_some());
3863
3864 let key = dir.get_fscrypt_key().await.expect("key").unwrap();
3867 let casefold_hash = get_casefold_hash(Some(&key), "bAr", true);
3868 let encrypted_name =
3869 encrypt_filename(&key, dir.object_id(), "bAr").expect("encrypt_filename");
3870 proxy_filename = ProxyFilename::new(casefold_hash as u64, &encrypted_name);
3871
3872 assert!(dir.lookup("BAR").await.expect("casefold lookup failed").is_some());
3874
3875 assert_eq!(
3877 get_casefold_hash(Some(&key), "bar", true),
3878 get_casefold_hash(Some(&key), "BaR", true)
3879 );
3880
3881 let mut count = 0;
3884 let layer_set = dir.store().tree().layer_set();
3885 let mut merger = layer_set.merger();
3886 let mut iter = dir.iter_from(&mut merger, "").await.expect("iter");
3887 while let Some(_entry) = iter.get() {
3888 count += 1;
3889 iter.advance().await.expect("advance");
3890 }
3891 assert_eq!(1, count, "unexpected number of entries.");
3892
3893 fs.close().await.expect("Close failed");
3894 }
3895
3896 let device = fs.take_device().await;
3897
3898 device.reopen(false);
3901 let fs = FxFilesystem::open(device).await.expect("open failed");
3902 {
3903 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3904 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3905 let store = root_volume
3906 .volume("vol", NO_OWNER, Some(crypt.clone()))
3907 .await
3908 .expect("volume failed");
3909 let dir = Directory::open(&store, object_id).await.expect("open failed");
3910 assert!(dir.casefold());
3911
3912 assert!(dir.lookup("bAr").await.expect("lookup failed").is_none());
3914 let filename: String = proxy_filename.into();
3916 assert!(dir.lookup(&filename).await.expect("lookup failed").is_some());
3917
3918 let layer_set = dir.store().tree().layer_set();
3919 let mut merger = layer_set.merger();
3920 let mut iter = dir.iter_from(&mut merger, "").await.expect("iter");
3921 let item = iter.get().expect("expect item");
3922 let filename: String = proxy_filename.into();
3923 assert_eq!(item.0, &filename);
3924 iter.advance().await.expect("advance");
3925 assert_eq!(None, iter.get());
3926
3927 crate::fsck::fsck(fs.clone()).await.unwrap();
3928 crate::fsck::fsck_volume(fs.as_ref(), store.store_object_id(), Some(crypt.clone()))
3929 .await
3930 .unwrap();
3931
3932 fs.close().await.expect("Close failed");
3933 }
3934 }
3935
3936 #[allow(dead_code)]
3947 fn find_out_of_order_sha256_long_prefix_pair(
3948 object_id: u64,
3949 key: &fxfs_crypto::Key,
3950 ) -> Option<[String; 2]> {
3951 let mut collision_map: std::collections::HashMap<u32, (usize, ProxyFilename, Vec<u8>)> =
3952 std::collections::HashMap::new();
3953 for i in 0..(1usize << 32) {
3954 let filename = format!("{:0>160}_{i}", 0);
3955 let casefold_hash = get_casefold_hash(Some(&key), &filename, true);
3956 let encrypted_name =
3957 encrypt_filename(&key, object_id, &filename).expect("encrypt_filename");
3958 let a = ProxyFilename::new(casefold_hash as u64, &encrypted_name);
3959 let casefold_hash = a.hash_code as u32;
3960 if let Some((j, b, b_encrypted_name)) = collision_map.get(&casefold_hash) {
3961 assert_eq!(a.filename, b.filename);
3962 if encrypted_name.cmp(b_encrypted_name) != a.sha256.cmp(&b.sha256) {
3963 return Some([format!("{:0>160}_{i}", 0), format!("{:0>160}_{j}", 0)]);
3964 }
3965 } else {
3966 collision_map.insert(casefold_hash, (i, a, encrypted_name));
3967 }
3968 }
3969 None
3970 }
3971
3972 #[fuchsia::test]
3973 async fn test_proxy_filename() {
3974 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3975 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3976 let mut filenames = Vec::new();
3977 let object_id;
3978 {
3979 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3980 let root_volume = root_volume(fs.clone()).await.unwrap();
3981 let store = root_volume.new_volume("vol", NO_OWNER, Some(crypt.clone())).await.unwrap();
3982
3983 let wrapping_key_id = 2;
3985 crypt.add_wrapping_key(wrapping_key_id, [1; 32]);
3986
3987 object_id = {
3988 let mut transaction = fs
3989 .clone()
3990 .new_transaction(
3991 lock_keys![LockKey::object(
3992 fs.root_store().store_object_id(),
3993 store.store_object_id()
3994 ),],
3995 Options::default(),
3996 )
3997 .await
3998 .expect("new_transaction failed");
3999 let dir = Directory::create(&mut transaction, &store, Some(wrapping_key_id))
4000 .await
4001 .expect("create failed");
4002
4003 transaction.commit().await.expect("commit");
4004 dir.object_id()
4005 };
4006 let dir = Directory::open(&store, object_id).await.expect("open failed");
4007
4008 dir.set_casefold(true).await.expect("set casefold");
4009 assert!(dir.casefold());
4010
4011 let mut transaction = fs
4012 .clone()
4013 .new_transaction(
4014 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4015 Options::default(),
4016 )
4017 .await
4018 .expect("new_transaction failed");
4019 let key = dir.get_fscrypt_key().await.expect("key").unwrap();
4020
4021 let collision_pair =
4031 [format!("{:0>160}_{}", 0, 3047256), format!("{:0>160}_{}", 0, 918)];
4032 for filename in (0..64)
4035 .into_iter()
4036 .map(|i| format!("{:0>160}_{i}", 0))
4037 .chain(collision_pair.into_iter())
4038 {
4039 let casefold_hash = get_casefold_hash(Some(&key), &filename, true);
4040 let encrypted_name =
4041 encrypt_filename(&key, dir.object_id(), &filename).expect("encrypt_filename");
4042 let proxy_filename = ProxyFilename::new(casefold_hash as u64, &encrypted_name);
4043 let file = dir
4044 .create_child_file(&mut transaction, &filename)
4045 .await
4046 .expect("create_child_file failed");
4047 filenames.push((proxy_filename, file.object_id()));
4048 }
4049 transaction.commit().await.expect("commit failed");
4050
4051 fs.close().await.expect("Close failed");
4052 }
4053
4054 let device = fs.take_device().await;
4055
4056 device.reopen(false);
4058 let fs = FxFilesystem::open(device).await.expect("open failed");
4059 {
4060 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
4061 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4062 let store = root_volume
4063 .volume("vol", NO_OWNER, Some(crypt.clone()))
4064 .await
4065 .expect("volume failed");
4066 let dir = Directory::open(&store, object_id).await.expect("open failed");
4067 assert!(dir.casefold());
4068
4069 assert_eq!(
4071 filenames.iter().map(|(name, _)| (*name).into()).collect::<HashSet<String>>().len(),
4072 filenames.len()
4073 );
4074
4075 let filename = filenames[0].0.filename.clone();
4076 for (proxy_filename, object_id) in &filenames {
4077 assert_eq!(filename, proxy_filename.filename);
4079
4080 let proxy_filename_str: String = (*proxy_filename).into();
4081 let item = dir
4082 .lookup(&proxy_filename_str)
4083 .await
4084 .expect("lookup failed")
4085 .expect("lookup is not None");
4086 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4087
4088 let layer_set = dir.store().tree().layer_set();
4090 let mut merger = layer_set.merger();
4091 let iter = dir.iter_from(&mut merger, &proxy_filename_str).await.expect("iter");
4092 let item = iter.get().expect("expect item");
4093 assert_eq!(item.0, &proxy_filename_str);
4094 assert_eq!(item.1, *object_id);
4095 }
4096
4097 fs.close().await.expect("Close failed");
4098 }
4099 }
4100
4101 #[fuchsia::test]
4102 async fn test_replace_directory_and_tombstone_on_remount() {
4103 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
4104 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4105 let crypt = Arc::new(InsecureCrypt::new());
4106 {
4107 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4108 let store = root_volume
4109 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
4110 .await
4111 .expect("new_volume failed");
4112
4113 let mut transaction = fs
4114 .clone()
4115 .new_transaction(
4116 lock_keys![LockKey::object(
4117 store.store_object_id(),
4118 store.root_directory_object_id()
4119 )],
4120 Options::default(),
4121 )
4122 .await
4123 .expect("new transaction failed");
4124
4125 let root_directory = Directory::open(&store, store.root_directory_object_id())
4126 .await
4127 .expect("open failed");
4128 let _directory = root_directory
4129 .create_child_dir(&mut transaction, "foo")
4130 .await
4131 .expect("create_child_dir failed");
4132 let directory = root_directory
4133 .create_child_dir(&mut transaction, "bar")
4134 .await
4135 .expect("create_child_dir failed");
4136 let oid = directory.object_id();
4137
4138 transaction.commit().await.expect("commit failed");
4139
4140 let mut transaction = fs
4141 .clone()
4142 .new_transaction(
4143 lock_keys![LockKey::object(
4144 store.store_object_id(),
4145 store.root_directory_object_id()
4146 )],
4147 Options::default(),
4148 )
4149 .await
4150 .expect("new transaction failed");
4151
4152 replace_child_with_object(
4153 &mut transaction,
4154 Some((oid, ObjectDescriptor::Directory)),
4155 (&root_directory, "foo"),
4156 0,
4157 Timestamp::now(),
4158 )
4159 .await
4160 .expect("replace_child_with_object failed");
4161
4162 yield_to_executor().await;
4166
4167 transaction.commit().await.expect("commit failed");
4168
4169 fs.close().await.expect("close failed");
4170 }
4171
4172 let device = fs.take_device().await;
4173 device.reopen(false);
4174 let fs = FxFilesystem::open(device).await.expect("open failed");
4175 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4176 let _store = root_volume
4177 .volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
4178 .await
4179 .expect("new_volume failed");
4180
4181 yield_to_executor().await;
4183
4184 fs.close().await.expect("close failed");
4185 }
4186}