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