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