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