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