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