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::NotSupported);
1755 let _ = src_dir.get_fscrypt_key().await?.into_cipher().ok_or(FxfsError::NoKey)?;
1758 }
1759 (DirType::Normal | DirType::Casefold | DirType::LegacyCasefold, _) => {}
1760 _ => bail!(FxfsError::NotSupported),
1762 }
1763
1764 transaction.add(store_id, Mutation::replace_or_insert_object(src_key, ObjectValue::None));
1765
1766 src_dir.store().update_attributes(transaction, id, None, Some(now)).await?;
1767 if src_dir.object_id() != dst.0.object_id() {
1768 sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1769 src_dir
1770 .update_dir_attributes_internal(
1771 transaction,
1772 src_dir.object_id(),
1773 MutableAttributesInternal {
1774 sub_dirs: -sub_dirs_delta,
1775 modification_time: Some(now.as_nanos()),
1776 change_time: Some(now),
1777 ..Default::default()
1778 },
1779 )
1780 .await?;
1781 }
1782 Some((id, descriptor))
1783 } else {
1784 None
1785 };
1786 replace_child_with_object(
1787 transaction,
1788 src,
1789 dst,
1790 sub_dirs_delta,
1791 is_same_dir_casefold_rename,
1792 now,
1793 )
1794 .await
1795}
1796
1797pub async fn replace_child_with_object<'a, S: HandleOwner>(
1807 transaction: &mut Transaction<'a>,
1808 src: Option<(u64, ObjectDescriptor)>,
1809 dst: (&'a Directory<S>, &str),
1810 mut sub_dirs_delta: i64,
1811 is_same_dir_casefold_rename: bool,
1812 timestamp: Timestamp,
1813) -> Result<ReplacedChild, Error> {
1814 let deleted_info =
1815 if is_same_dir_casefold_rename { None } else { dst.0.lookup_ext(dst.1).await? };
1816
1817 let (deleted_id_and_descriptor, dst_key) = match deleted_info {
1818 Some(entry) => (Some((entry.object_id, entry.descriptor.clone())), Some(entry.key)),
1819 None => (None, None),
1820 };
1821 let store_id = dst.0.store().store_object_id();
1822 let result = match deleted_id_and_descriptor {
1825 Some((old_id, ObjectDescriptor::File | ObjectDescriptor::Symlink)) => {
1826 let was_last_ref = dst.0.store().adjust_refs(transaction, old_id, -1).await?;
1827 dst.0.store().update_attributes(transaction, old_id, None, Some(timestamp)).await?;
1828 if was_last_ref {
1829 ReplacedChild::Object(old_id)
1830 } else {
1831 ReplacedChild::ObjectWithRemainingLinks(old_id)
1832 }
1833 }
1834 Some((old_id, ObjectDescriptor::Directory)) => {
1835 let dir = Directory::open(&dst.0.owner(), old_id).await?;
1836 if dir.has_children().await? {
1837 bail!(FxfsError::NotEmpty);
1838 }
1839 dst.0.store().add_to_graveyard(transaction, old_id);
1842 sub_dirs_delta -= 1;
1843 ReplacedChild::Directory(old_id)
1844 }
1845 Some((_, ObjectDescriptor::Volume)) => {
1846 bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected volume child"))
1847 }
1848 None => {
1849 if src.is_none() {
1850 bail!(FxfsError::NotFound);
1852 }
1853 ReplacedChild::None
1854 }
1855 };
1856 let new_value = match src {
1857 Some((id, descriptor)) => ObjectValue::child(id, descriptor),
1858 None => ObjectValue::None,
1859 };
1860 let new_key = if matches!(new_value, ObjectValue::None) {
1861 None
1862 } else {
1863 if dst.0.dir_type().is_encrypted() {
1864 match dst.0.get_fscrypt_key().await? {
1865 CipherHolder::Cipher(cipher) => {
1866 let encrypted_dst_name = encrypt_filename(&*cipher, dst.0.object_id(), dst.1)?;
1867 let dst_hash_code = if dst.0.dir_type().is_casefold() {
1868 Some(cipher.hash_code_casefold(dst.1))
1869 } else {
1870 cipher.hash_code(encrypted_dst_name.as_bytes(), dst.1)
1871 };
1872 Some(ObjectKey::encrypted_child(
1873 dst.0.object_id(),
1874 encrypted_dst_name,
1875 dst_hash_code,
1876 ))
1877 }
1878 CipherHolder::Unavailable => {
1879 bail!(FxfsError::NoKey);
1880 }
1881 }
1882 } else {
1883 Some(ObjectKey::child(dst.0.object_id(), dst.1, dst.0.dir_type()))
1884 }
1885 };
1886
1887 if let Some(dst_key) = dst_key
1888 && new_key.as_ref() != Some(&dst_key)
1889 {
1890 transaction.add(store_id, Mutation::replace_or_insert_object(dst_key, ObjectValue::None));
1891 }
1892
1893 if let Some(new_key) = new_key {
1894 transaction.add(store_id, Mutation::replace_or_insert_object(new_key, new_value));
1895 }
1896 dst.0
1897 .update_dir_attributes_internal(
1898 transaction,
1899 dst.0.object_id(),
1900 MutableAttributesInternal {
1901 sub_dirs: sub_dirs_delta,
1902 modification_time: Some(timestamp.as_nanos()),
1903 change_time: Some(timestamp),
1904 ..Default::default()
1905 },
1906 )
1907 .await?;
1908 Ok(result)
1909}
1910
1911#[cfg(test)]
1912mod tests {
1913 use super::{ProxyFilename, encrypt_filename, replace_child_with_object};
1914 use crate::errors::FxfsError;
1915 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
1916 use crate::object_handle::{ObjectHandle, ReadObjectHandle, WriteObjectHandle};
1917 use crate::object_store::directory::{
1918 Directory, MutableAttributesInternal, ReplacedChild, replace_child,
1919 };
1920 use crate::object_store::object_record::{ObjectKey, ObjectValue, Timestamp};
1921 use crate::object_store::transaction::{Options, lock_keys};
1922 use crate::object_store::volume::root_volume;
1923 use crate::object_store::{
1924 AttributeId, HandleOptions, LockKey, NewChildStoreOptions, ObjectDescriptor, ObjectKind,
1925 ObjectStore, SetExtendedAttributeMode, StoreObjectHandle, StoreOptions,
1926 };
1927 use anyhow::Error;
1928 use assert_matches::assert_matches;
1929 use fidl_fuchsia_io as fio;
1930 use fxfs_crypt_common::CryptBase;
1931 use fxfs_crypto::{Cipher, Crypt, WrappingKeyId};
1932 use fxfs_insecure_crypto::new_insecure_crypt;
1933 use std::collections::HashSet;
1934 use std::future::poll_fn;
1935 use std::sync::Arc;
1936 use std::task::Poll;
1937 use storage_device::DeviceHolder;
1938 use storage_device::fake_device::FakeDevice;
1939 use test_case::test_case;
1940
1941 #[fuchsia::test]
1942 fn test_casefold_equality_implies_hash_equality() {
1943 use fxfs_unicode::CasefoldString;
1944
1945 let test_cases = vec![
1946 ("Hello", "hello"),
1947 ("straße", "STRASSE"),
1948 ("e\u{0301}", "\u{00c9}"), ("hello\u{00ad}", "hello"), ("foo\u{200b}bar", "FOOBAR"), ];
1952
1953 for (a, b) in test_cases {
1954 let cf_a = CasefoldString::new(a.to_string());
1955 let cf_b = CasefoldString::new(b.to_string());
1956 assert_eq!(cf_a, cf_b, "Strings {:?} and {:?} should be equal under casefolding", a, b);
1957
1958 let bytes_a: Vec<u8> =
1959 cf_a.casefold_normalized_chars().collect::<String>().into_bytes();
1960 let bytes_b: Vec<u8> =
1961 cf_b.casefold_normalized_chars().collect::<String>().into_bytes();
1962 assert_eq!(
1963 bytes_a, bytes_b,
1964 "Normalized bytes for {:?} and {:?} should be identical",
1965 a, b
1966 );
1967
1968 let hash_a = fscrypt::direntry::tea_hash_filename(bytes_a);
1969 let hash_b = fscrypt::direntry::tea_hash_filename(bytes_b);
1970 assert_eq!(hash_a, hash_b, "Hashes for {:?} and {:?} should be identical", a, b);
1971 }
1972 }
1973
1974 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
1975 const WRAPPING_KEY_ID: WrappingKeyId = u128::to_le_bytes(2);
1976
1977 #[fuchsia::test]
1981 async fn test_reopen_with_different_crypt_shows_proxy_name() -> Result<(), Error> {
1982 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
1983 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1984 let symlink_object_id;
1985 {
1986 let crypt = Arc::new(new_insecure_crypt());
1987 crypt
1988 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
1989 .expect("add_wrapping_key failed");
1990 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1991 let store = root_volume
1992 .new_volume(
1993 "test",
1994 NewChildStoreOptions {
1995 options: StoreOptions {
1996 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
1997 ..StoreOptions::default()
1998 },
1999 ..Default::default()
2000 },
2001 )
2002 .await
2003 .expect("new_volume failed");
2004 let mut transaction = fs
2005 .root_store()
2006 .new_transaction(
2007 lock_keys![LockKey::object(
2008 store.store_object_id(),
2009 store.root_directory_object_id()
2010 )],
2011 Options::default(),
2012 )
2013 .await
2014 .expect("new_transaction failed");
2015 let root_dir = Directory::open(&store, store.root_directory_object_id())
2016 .await
2017 .expect("open failed");
2018 let _ = root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await?;
2019 transaction.commit().await.unwrap();
2020
2021 let mut transaction = fs
2022 .root_store()
2023 .new_transaction(
2024 lock_keys![LockKey::object(
2025 store.store_object_id(),
2026 store.root_directory_object_id()
2027 )],
2028 Options::default(),
2029 )
2030 .await
2031 .expect("new_transaction failed");
2032 let root_dir = Directory::open(&store, store.root_directory_object_id())
2033 .await
2034 .expect("open failed");
2035 symlink_object_id = root_dir
2036 .create_symlink(&mut transaction, b"some_link_text", "a")
2037 .await
2038 .expect("create_symlink failed");
2039 transaction.commit().await.expect("commit failed");
2040 };
2041 fs.close().await.expect("close failed");
2042 let device = fs.take_device().await;
2043 device.reopen(false);
2044
2045 let fs = FxFilesystem::open(device).await.expect("open failed");
2046 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2047 let store = root_volume
2049 .volume(
2050 "test",
2051 StoreOptions {
2052 crypt: Some(Arc::new(new_insecure_crypt())),
2053 ..StoreOptions::default()
2054 },
2055 )
2056 .await
2057 .expect("volume failed");
2058
2059 let item = store
2060 .tree()
2061 .find(&ObjectKey::object(symlink_object_id))
2062 .await
2063 .expect("find failed")
2064 .expect("found record");
2065 let raw_link = match item.value {
2066 ObjectValue::Object { kind: ObjectKind::EncryptedSymlink { link, .. }, .. } => link,
2067 _ => panic!("Unexpected item {item:?}"),
2068 };
2069 let symlink_target = store.read_symlink(symlink_object_id).await?;
2070 let expected_symlink_target: String =
2072 ProxyFilename::new_with_hash_code(0, &raw_link).into();
2073 assert_eq!(symlink_target, expected_symlink_target.as_bytes());
2074
2075 fs.close().await.expect("Close failed");
2076 Ok(())
2077 }
2078
2079 async fn yield_to_executor() {
2080 let mut done = false;
2081 poll_fn(|cx| {
2082 if done {
2083 Poll::Ready(())
2084 } else {
2085 done = true;
2086 cx.waker().wake_by_ref();
2087 Poll::Pending
2088 }
2089 })
2090 .await;
2091 }
2092
2093 #[fuchsia::test]
2094 async fn test_create_directory() {
2095 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2096 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2097 let object_id = {
2098 let mut transaction = fs
2099 .root_store()
2100 .new_transaction(lock_keys![], Options::default())
2101 .await
2102 .expect("new_transaction failed");
2103 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
2104 .await
2105 .expect("create failed");
2106
2107 let child_dir = dir
2108 .create_child_dir(&mut transaction, "foo")
2109 .await
2110 .expect("create_child_dir failed");
2111 let _child_dir_file = child_dir
2112 .create_child_file(&mut transaction, "bar")
2113 .await
2114 .expect("create_child_file failed");
2115 let _child_file = dir
2116 .create_child_file(&mut transaction, "baz")
2117 .await
2118 .expect("create_child_file failed");
2119 dir.add_child_volume(&mut transaction, "corge", 100)
2120 .await
2121 .expect("add_child_volume failed");
2122 transaction.commit().await.expect("commit failed");
2123 fs.sync(SyncOptions::default()).await.expect("sync failed");
2124 dir.object_id()
2125 };
2126 fs.close().await.expect("Close failed");
2127 let device = fs.take_device().await;
2128 device.reopen(false);
2129 let fs = FxFilesystem::open(device).await.expect("open failed");
2130 {
2131 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2132 let (object_id, object_descriptor, _) =
2133 dir.lookup("foo").await.expect("lookup failed").expect("not found");
2134 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
2135 let child_dir =
2136 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2137 let (object_id, object_descriptor, _) =
2138 child_dir.lookup("bar").await.expect("lookup failed").expect("not found");
2139 assert_eq!(object_descriptor, ObjectDescriptor::File);
2140 let _child_dir_file = ObjectStore::open_object(
2141 &fs.root_store(),
2142 object_id,
2143 HandleOptions::default(),
2144 None,
2145 )
2146 .await
2147 .expect("open object failed");
2148 let (object_id, object_descriptor, _) =
2149 dir.lookup("baz").await.expect("lookup failed").expect("not found");
2150 assert_eq!(object_descriptor, ObjectDescriptor::File);
2151 let _child_file = ObjectStore::open_object(
2152 &fs.root_store(),
2153 object_id,
2154 HandleOptions::default(),
2155 None,
2156 )
2157 .await
2158 .expect("open object failed");
2159 let (object_id, object_descriptor, _) =
2160 dir.lookup("corge").await.expect("lookup failed").expect("not found");
2161 assert_eq!(object_id, 100);
2162 if let ObjectDescriptor::Volume = object_descriptor {
2163 } else {
2164 panic!("wrong ObjectDescriptor");
2165 }
2166
2167 assert_eq!(dir.lookup("qux").await.expect("lookup failed"), None);
2168 }
2169 fs.close().await.expect("Close failed");
2170 }
2171
2172 #[fuchsia::test]
2173 async fn test_set_wrapping_key_does_not_exist() {
2174 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2175 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2176 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2177 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2178 let store = root_volume
2179 .new_volume(
2180 "test",
2181 NewChildStoreOptions {
2182 options: StoreOptions {
2183 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2184 ..StoreOptions::default()
2185 },
2186 ..NewChildStoreOptions::default()
2187 },
2188 )
2189 .await
2190 .expect("new_volume failed");
2191
2192 let mut transaction = fs
2193 .root_store()
2194 .new_transaction(
2195 lock_keys![LockKey::object(
2196 store.store_object_id(),
2197 store.root_directory_object_id()
2198 )],
2199 Options::default(),
2200 )
2201 .await
2202 .expect("new transaction failed");
2203 let root_directory =
2204 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2205 let directory = root_directory
2206 .create_child_dir(&mut transaction, "foo")
2207 .await
2208 .expect("create_child_dir failed");
2209 transaction.commit().await.expect("commit failed");
2210 let mut transaction = fs
2211 .root_store()
2212 .new_transaction(
2213 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2214 Options::default(),
2215 )
2216 .await
2217 .expect("new transaction failed");
2218 directory
2219 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2220 .await
2221 .expect_err("wrapping key id 2 has not been added");
2222 transaction.commit().await.expect("commit failed");
2223 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2224 let mut transaction = fs
2225 .root_store()
2226 .new_transaction(
2227 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2228 Options::default(),
2229 )
2230 .await
2231 .expect("new transaction failed");
2232 directory
2233 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2234 .await
2235 .expect("wrapping key id 2 has been added");
2236 fs.close().await.expect("Close failed");
2237 }
2238
2239 #[fuchsia::test]
2240 async fn test_set_encryption_policy_on_unencrypted_nonempty_dir() {
2241 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2242 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2243 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2244 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2245 let store = root_volume
2246 .new_volume(
2247 "test",
2248 NewChildStoreOptions {
2249 options: StoreOptions {
2250 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2251 ..StoreOptions::default()
2252 },
2253 ..NewChildStoreOptions::default()
2254 },
2255 )
2256 .await
2257 .expect("new_volume failed");
2258
2259 let mut transaction = fs
2260 .root_store()
2261 .new_transaction(
2262 lock_keys![LockKey::object(
2263 store.store_object_id(),
2264 store.root_directory_object_id()
2265 )],
2266 Options::default(),
2267 )
2268 .await
2269 .expect("new transaction failed");
2270 let root_directory =
2271 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2272 let directory = root_directory
2273 .create_child_dir(&mut transaction, "foo")
2274 .await
2275 .expect("create_child_dir failed");
2276 let _file = directory
2277 .create_child_file(&mut transaction, "bar")
2278 .await
2279 .expect("create_child_file failed");
2280 transaction.commit().await.expect("commit failed");
2281 let mut transaction = fs
2282 .root_store()
2283 .new_transaction(
2284 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2285 Options::default(),
2286 )
2287 .await
2288 .expect("new transaction failed");
2289 directory
2290 .set_wrapping_key(&mut transaction, WRAPPING_KEY_ID)
2291 .await
2292 .expect_err("directory is not empty");
2293 transaction.commit().await.expect("commit failed");
2294 fs.close().await.expect("Close failed");
2295 }
2296
2297 #[fuchsia::test]
2298 async fn test_create_file_or_subdir_in_locked_directory() {
2299 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2300 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2301 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2302 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2303 let store = root_volume
2304 .new_volume(
2305 "test",
2306 NewChildStoreOptions {
2307 options: StoreOptions {
2308 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2309 ..StoreOptions::default()
2310 },
2311 ..NewChildStoreOptions::default()
2312 },
2313 )
2314 .await
2315 .expect("new_volume failed");
2316
2317 let mut transaction = fs
2318 .root_store()
2319 .new_transaction(
2320 lock_keys![LockKey::object(
2321 store.store_object_id(),
2322 store.root_directory_object_id()
2323 )],
2324 Options::default(),
2325 )
2326 .await
2327 .expect("new transaction failed");
2328 let root_directory =
2329 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2330 let directory = root_directory
2331 .create_child_dir(&mut transaction, "foo")
2332 .await
2333 .expect("create_child_dir failed");
2334 transaction.commit().await.expect("commit failed");
2335 crypt.add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into()).expect("add_wrapping_key failed");
2336 let transaction = fs
2337 .root_store()
2338 .new_transaction(
2339 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2340 Options::default(),
2341 )
2342 .await
2343 .expect("new transaction failed");
2344 directory
2345 .update_attributes(
2346 transaction,
2347 Some(&fio::MutableNodeAttributes {
2348 wrapping_key_id: Some(WRAPPING_KEY_ID),
2349 ..Default::default()
2350 }),
2351 0,
2352 None,
2353 )
2354 .await
2355 .expect("update attributes failed");
2356 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget wrapping key failed");
2357 let mut transaction = fs
2358 .root_store()
2359 .new_transaction(
2360 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2361 Options::default(),
2362 )
2363 .await
2364 .expect("new transaction failed");
2365 directory
2366 .create_child_dir(&mut transaction, "bar")
2367 .await
2368 .expect_err("cannot create a dir inside of a locked encrypted directory");
2369 directory
2370 .create_child_file(&mut transaction, "baz")
2371 .await
2372 .map(|_| ())
2373 .expect_err("cannot create a file inside of a locked encrypted directory");
2374 fs.close().await.expect("Close failed");
2375 }
2376
2377 #[fuchsia::test]
2378 async fn test_replace_child_with_object_in_locked_directory() {
2379 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2380 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2381 let crypt = Arc::new(new_insecure_crypt());
2382
2383 let (parent_oid, src_oid, dst_oid) = {
2384 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2385 let store = root_volume
2386 .new_volume(
2387 "test",
2388 NewChildStoreOptions {
2389 options: StoreOptions {
2390 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2391 ..StoreOptions::default()
2392 },
2393 ..Default::default()
2394 },
2395 )
2396 .await
2397 .expect("new_volume failed");
2398
2399 let mut transaction = fs
2400 .root_store()
2401 .new_transaction(
2402 lock_keys![LockKey::object(
2403 store.store_object_id(),
2404 store.root_directory_object_id()
2405 )],
2406 Options::default(),
2407 )
2408 .await
2409 .expect("new transaction failed");
2410 let root_directory = Directory::open(&store, store.root_directory_object_id())
2411 .await
2412 .expect("open failed");
2413 let directory = root_directory
2414 .create_child_dir(&mut transaction, "foo")
2415 .await
2416 .expect("create_child_dir failed");
2417 transaction.commit().await.expect("commit failed");
2418 crypt
2419 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
2420 .expect("add_wrapping_key failed");
2421 let transaction = fs
2422 .root_store()
2423 .new_transaction(
2424 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2425 Options::default(),
2426 )
2427 .await
2428 .expect("new transaction failed");
2429 directory
2430 .update_attributes(
2431 transaction,
2432 Some(&fio::MutableNodeAttributes {
2433 wrapping_key_id: Some(WRAPPING_KEY_ID),
2434 ..Default::default()
2435 }),
2436 0,
2437 None,
2438 )
2439 .await
2440 .expect("update attributes failed");
2441 let mut transaction = fs
2442 .root_store()
2443 .new_transaction(
2444 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
2445 Options::default(),
2446 )
2447 .await
2448 .expect("new transaction failed");
2449 let src_child = directory
2450 .create_child_dir(&mut transaction, "fee")
2451 .await
2452 .expect("create_child_dir failed");
2453 let dst_child = directory
2454 .create_child_dir(&mut transaction, "faa")
2455 .await
2456 .expect("create_child_dir failed");
2457 transaction.commit().await.expect("commit failed");
2458 crypt.forget_wrapping_key(&WRAPPING_KEY_ID).expect("forget_wrapping_key failed");
2459 (directory.object_id(), src_child.object_id(), dst_child.object_id())
2460 };
2461 fs.close().await.expect("Close failed");
2462 let device = fs.take_device().await;
2463 device.reopen(false);
2464 let fs = FxFilesystem::open(device).await.expect("open failed");
2465 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2466 let store = root_volume
2467 .volume(
2468 "test",
2469 StoreOptions {
2470 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2471 ..StoreOptions::default()
2472 },
2473 )
2474 .await
2475 .expect("volume failed");
2476
2477 {
2478 let parent_directory = Directory::open(&store, parent_oid).await.expect("open failed");
2479 let layer_set = store.tree().layer_set();
2480 let mut merger = layer_set.merger();
2481 let mut encrypted_src_name = None;
2482 let mut encrypted_dst_name = None;
2483 let mut iter = parent_directory.iter(&mut merger).await.expect("iter_from failed");
2484 while let Some((name, object_id, object_descriptor)) = iter.get() {
2485 assert!(matches!(object_descriptor, ObjectDescriptor::Directory));
2486 if object_id == dst_oid {
2487 encrypted_dst_name = Some(name.to_string());
2488 } else if object_id == src_oid {
2489 encrypted_src_name = Some(name.to_string());
2490 }
2491 iter.advance().await.expect("iter advance failed");
2492 }
2493
2494 let src_child = parent_directory
2495 .lookup(&encrypted_src_name.expect("src child not found"))
2496 .await
2497 .expect("lookup failed")
2498 .expect("not found");
2499 let mut transaction = fs
2500 .root_store()
2501 .new_transaction(
2502 lock_keys![LockKey::object(
2503 store.store_object_id(),
2504 parent_directory.object_id(),
2505 )],
2506 Options::default(),
2507 )
2508 .await
2509 .expect("new transaction failed");
2510 replace_child_with_object(
2511 &mut transaction,
2512 Some((src_child.0, src_child.1)),
2513 (&parent_directory, &encrypted_dst_name.expect("dst child not found")),
2514 0,
2515 false,
2516 Timestamp::now(),
2517 )
2518 .await
2519 .expect_err("renames should fail within a locked directory");
2520 }
2521 fs.close().await.expect("Close failed");
2522 }
2523
2524 #[fuchsia::test]
2525 async fn test_set_encryption_policy_on_unencrypted_file() {
2526 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2527 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2528 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2529 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
2530 let store = root_volume
2531 .new_volume(
2532 "test",
2533 NewChildStoreOptions {
2534 options: StoreOptions {
2535 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
2536 ..StoreOptions::default()
2537 },
2538 ..NewChildStoreOptions::default()
2539 },
2540 )
2541 .await
2542 .expect("new_volume failed");
2543
2544 let mut transaction = fs
2545 .root_store()
2546 .new_transaction(
2547 lock_keys![LockKey::object(
2548 store.store_object_id(),
2549 store.root_directory_object_id()
2550 )],
2551 Options::default(),
2552 )
2553 .await
2554 .expect("new transaction failed");
2555 let root_directory =
2556 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2557 let file_handle = root_directory
2558 .create_child_file(&mut transaction, "foo")
2559 .await
2560 .expect("create_child_dir failed");
2561 transaction.commit().await.expect("commit failed");
2562 let mut transaction = fs
2563 .root_store()
2564 .new_transaction(
2565 lock_keys![LockKey::object(store.store_object_id(), file_handle.object_id())],
2566 Options::default(),
2567 )
2568 .await
2569 .expect("new transaction failed");
2570 file_handle
2571 .update_attributes(
2572 &mut transaction,
2573 Some(&fio::MutableNodeAttributes {
2574 wrapping_key_id: Some(WRAPPING_KEY_ID),
2575 ..Default::default()
2576 }),
2577 None,
2578 )
2579 .await
2580 .expect_err("Cannot update the wrapping key id of a file");
2581 fs.close().await.expect("Close failed");
2582 }
2583
2584 #[fuchsia::test]
2585 async fn test_delete_child() {
2586 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2587 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2588 let dir;
2589 let child;
2590 let mut transaction = fs
2591 .root_store()
2592 .new_transaction(lock_keys![], Options::default())
2593 .await
2594 .expect("new_transaction failed");
2595 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2596 .await
2597 .expect("create failed");
2598
2599 child =
2600 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2601 transaction.commit().await.expect("commit failed");
2602
2603 transaction = fs
2604 .root_store()
2605 .new_transaction(
2606 lock_keys![
2607 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2608 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2609 ],
2610 Options::default(),
2611 )
2612 .await
2613 .expect("new_transaction failed");
2614 assert_matches!(
2615 replace_child(&mut transaction, None, (&dir, "foo"))
2616 .await
2617 .expect("replace_child failed"),
2618 ReplacedChild::Object(..)
2619 );
2620 transaction.commit().await.expect("commit failed");
2621
2622 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2623 fs.close().await.expect("Close failed");
2624 }
2625
2626 #[fuchsia::test]
2627 async fn test_delete_child_with_children_fails() {
2628 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2629 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2630 let dir;
2631 let child;
2632 let bar;
2633 let mut transaction = fs
2634 .root_store()
2635 .new_transaction(lock_keys![], Options::default())
2636 .await
2637 .expect("new_transaction failed");
2638 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2639 .await
2640 .expect("create failed");
2641
2642 child =
2643 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2644 bar = child
2645 .create_child_file(&mut transaction, "bar")
2646 .await
2647 .expect("create_child_file failed");
2648 transaction.commit().await.expect("commit failed");
2649
2650 transaction = fs
2651 .root_store()
2652 .new_transaction(
2653 lock_keys![
2654 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2655 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2656 ],
2657 Options::default(),
2658 )
2659 .await
2660 .expect("new_transaction failed");
2661 assert_eq!(
2662 replace_child(&mut transaction, None, (&dir, "foo"))
2663 .await
2664 .expect_err("replace_child succeeded")
2665 .downcast::<FxfsError>()
2666 .expect("wrong error"),
2667 FxfsError::NotEmpty
2668 );
2669 transaction.commit().await.expect("commit failed");
2670
2671 transaction = fs
2672 .root_store()
2673 .new_transaction(
2674 lock_keys![
2675 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2676 LockKey::object(fs.root_store().store_object_id(), bar.object_id()),
2677 ],
2678 Options::default(),
2679 )
2680 .await
2681 .expect("new_transaction failed");
2682 assert_matches!(
2683 replace_child(&mut transaction, None, (&child, "bar"))
2684 .await
2685 .expect("replace_child failed"),
2686 ReplacedChild::Object(..)
2687 );
2688 transaction.commit().await.expect("commit failed");
2689
2690 transaction = fs
2691 .root_store()
2692 .new_transaction(
2693 lock_keys![
2694 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2695 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2696 ],
2697 Options::default(),
2698 )
2699 .await
2700 .expect("new_transaction failed");
2701 assert_matches!(
2702 replace_child(&mut transaction, None, (&dir, "foo"))
2703 .await
2704 .expect("replace_child failed"),
2705 ReplacedChild::Directory(..)
2706 );
2707 transaction.commit().await.expect("commit failed");
2708
2709 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2710 fs.close().await.expect("Close failed");
2711 }
2712
2713 #[fuchsia::test]
2714 async fn test_delete_and_reinsert_child() {
2715 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2716 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2717 let dir;
2718 let child;
2719 let mut transaction = fs
2720 .root_store()
2721 .new_transaction(lock_keys![], Options::default())
2722 .await
2723 .expect("new_transaction failed");
2724 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2725 .await
2726 .expect("create failed");
2727
2728 child =
2729 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2730 transaction.commit().await.expect("commit failed");
2731
2732 transaction = fs
2733 .root_store()
2734 .new_transaction(
2735 lock_keys![
2736 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2737 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2738 ],
2739 Options::default(),
2740 )
2741 .await
2742 .expect("new_transaction failed");
2743 assert_matches!(
2744 replace_child(&mut transaction, None, (&dir, "foo"))
2745 .await
2746 .expect("replace_child failed"),
2747 ReplacedChild::Object(..)
2748 );
2749 transaction.commit().await.expect("commit failed");
2750
2751 transaction = fs
2752 .root_store()
2753 .new_transaction(
2754 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2755 Options::default(),
2756 )
2757 .await
2758 .expect("new_transaction failed");
2759 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2760 transaction.commit().await.expect("commit failed");
2761
2762 dir.lookup("foo").await.expect("lookup failed");
2763 fs.close().await.expect("Close failed");
2764 }
2765
2766 #[fuchsia::test]
2767 async fn test_delete_child_persists() {
2768 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2769 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2770 let object_id = {
2771 let dir;
2772 let child;
2773 let mut transaction = fs
2774 .root_store()
2775 .new_transaction(lock_keys![], Options::default())
2776 .await
2777 .expect("new_transaction failed");
2778 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2779 .await
2780 .expect("create failed");
2781
2782 child = dir
2783 .create_child_file(&mut transaction, "foo")
2784 .await
2785 .expect("create_child_file failed");
2786 transaction.commit().await.expect("commit failed");
2787 dir.lookup("foo").await.expect("lookup failed");
2788
2789 transaction = fs
2790 .root_store()
2791 .new_transaction(
2792 lock_keys![
2793 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2794 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2795 ],
2796 Options::default(),
2797 )
2798 .await
2799 .expect("new_transaction failed");
2800 assert_matches!(
2801 replace_child(&mut transaction, None, (&dir, "foo"))
2802 .await
2803 .expect("replace_child failed"),
2804 ReplacedChild::Object(..)
2805 );
2806 transaction.commit().await.expect("commit failed");
2807
2808 fs.sync(SyncOptions::default()).await.expect("sync failed");
2809 dir.object_id()
2810 };
2811
2812 fs.close().await.expect("Close failed");
2813 let device = fs.take_device().await;
2814 device.reopen(false);
2815 let fs = FxFilesystem::open(device).await.expect("open failed");
2816 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2817 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2818 fs.close().await.expect("Close failed");
2819 }
2820
2821 #[fuchsia::test]
2822 async fn test_replace_child() {
2823 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2824 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2825 let dir;
2826 let child_dir1;
2827 let child_dir2;
2828 let mut transaction = fs
2829 .root_store()
2830 .new_transaction(lock_keys![], Options::default())
2831 .await
2832 .expect("new_transaction failed");
2833 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2834 .await
2835 .expect("create failed");
2836
2837 child_dir1 =
2838 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2839 child_dir2 =
2840 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2841 let file = child_dir1
2842 .create_child_file(&mut transaction, "foo")
2843 .await
2844 .expect("create_child_file failed");
2845 transaction.commit().await.expect("commit failed");
2846
2847 transaction = fs
2848 .root_store()
2849 .new_transaction(
2850 lock_keys![
2851 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2852 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2853 LockKey::object(fs.root_store().store_object_id(), file.object_id()),
2854 ],
2855 Options::default(),
2856 )
2857 .await
2858 .expect("new_transaction failed");
2859 assert_matches!(
2860 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2861 .await
2862 .expect("replace_child failed"),
2863 ReplacedChild::None
2864 );
2865 transaction.commit().await.expect("commit failed");
2866
2867 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2868 child_dir2.lookup("bar").await.expect("lookup failed");
2869 fs.close().await.expect("Close failed");
2870 }
2871
2872 #[fuchsia::test]
2873 async fn test_replace_child_overwrites_dst() {
2874 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2875 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2876 let dir;
2877 let child_dir1;
2878 let child_dir2;
2879 let mut transaction = fs
2880 .root_store()
2881 .new_transaction(lock_keys![], Options::default())
2882 .await
2883 .expect("new_transaction failed");
2884 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2885 .await
2886 .expect("create failed");
2887
2888 child_dir1 =
2889 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2890 child_dir2 =
2891 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2892 let foo = child_dir1
2893 .create_child_file(&mut transaction, "foo")
2894 .await
2895 .expect("create_child_file failed");
2896 let bar = child_dir2
2897 .create_child_file(&mut transaction, "bar")
2898 .await
2899 .expect("create_child_file failed");
2900 let foo_oid = foo.object_id();
2901 let bar_oid = bar.object_id();
2902 transaction.commit().await.expect("commit failed");
2903
2904 {
2905 let mut buf = foo.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2906 buf.as_mut_slice().fill(0xaa);
2907 foo.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2908 buf.as_mut_slice().fill(0xbb);
2909 bar.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2910 }
2911 std::mem::drop(bar);
2912 std::mem::drop(foo);
2913
2914 transaction = fs
2915 .root_store()
2916 .new_transaction(
2917 lock_keys![
2918 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2919 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2920 LockKey::object(fs.root_store().store_object_id(), foo_oid),
2921 LockKey::object(fs.root_store().store_object_id(), bar_oid),
2922 ],
2923 Options::default(),
2924 )
2925 .await
2926 .expect("new_transaction failed");
2927 assert_matches!(
2928 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2929 .await
2930 .expect("replace_child failed"),
2931 ReplacedChild::Object(..)
2932 );
2933 transaction.commit().await.expect("commit failed");
2934
2935 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2936
2937 let (oid, object_descriptor, _) =
2939 child_dir2.lookup("bar").await.expect("lookup failed").expect("not found");
2940 assert_eq!(object_descriptor, ObjectDescriptor::File);
2941 let bar =
2942 ObjectStore::open_object(&child_dir2.owner(), oid, HandleOptions::default(), None)
2943 .await
2944 .expect("Open failed");
2945 let mut buf = bar.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2946 bar.read(0, buf.as_mut()).await.expect("read failed");
2947 assert_eq!(buf.as_slice(), vec![0xaa; TEST_DEVICE_BLOCK_SIZE as usize]);
2948 fs.close().await.expect("Close failed");
2949 }
2950
2951 #[fuchsia::test]
2952 async fn test_replace_child_fails_if_would_overwrite_nonempty_dir() {
2953 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2954 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2955 let dir;
2956 let child_dir1;
2957 let child_dir2;
2958 let mut transaction = fs
2959 .root_store()
2960 .new_transaction(lock_keys![], Options::default())
2961 .await
2962 .expect("new_transaction failed");
2963 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2964 .await
2965 .expect("create failed");
2966
2967 child_dir1 =
2968 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2969 child_dir2 =
2970 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2971 let foo = child_dir1
2972 .create_child_file(&mut transaction, "foo")
2973 .await
2974 .expect("create_child_file failed");
2975 let nested_child = child_dir2
2976 .create_child_dir(&mut transaction, "bar")
2977 .await
2978 .expect("create_child_file failed");
2979 nested_child
2980 .create_child_file(&mut transaction, "baz")
2981 .await
2982 .expect("create_child_file failed");
2983 transaction.commit().await.expect("commit failed");
2984
2985 transaction = fs
2986 .root_store()
2987 .new_transaction(
2988 lock_keys![
2989 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2990 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2991 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2992 LockKey::object(fs.root_store().store_object_id(), nested_child.object_id()),
2993 ],
2994 Options::default(),
2995 )
2996 .await
2997 .expect("new_transaction failed");
2998 assert_eq!(
2999 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
3000 .await
3001 .expect_err("replace_child succeeded")
3002 .downcast::<FxfsError>()
3003 .expect("wrong error"),
3004 FxfsError::NotEmpty
3005 );
3006 fs.close().await.expect("Close failed");
3007 }
3008
3009 #[fuchsia::test]
3010 async fn test_replace_child_within_dir() {
3011 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3012 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3013 let dir;
3014 let mut transaction = fs
3015 .root_store()
3016 .new_transaction(lock_keys![], Options::default())
3017 .await
3018 .expect("new_transaction failed");
3019 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3020 .await
3021 .expect("create failed");
3022 let foo =
3023 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
3024 transaction.commit().await.expect("commit failed");
3025
3026 transaction = fs
3027 .root_store()
3028 .new_transaction(
3029 lock_keys![
3030 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3031 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3032 ],
3033 Options::default(),
3034 )
3035 .await
3036 .expect("new_transaction failed");
3037 assert_matches!(
3038 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
3039 .await
3040 .expect("replace_child failed"),
3041 ReplacedChild::None
3042 );
3043 transaction.commit().await.expect("commit failed");
3044
3045 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3046 dir.lookup("bar").await.expect("lookup new name failed");
3047 fs.close().await.expect("Close failed");
3048 }
3049
3050 #[fuchsia::test]
3051 async fn test_iterate() {
3052 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3053 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3054 let dir;
3055 let mut transaction = fs
3056 .root_store()
3057 .new_transaction(lock_keys![], Options::default())
3058 .await
3059 .expect("new_transaction failed");
3060 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3061 .await
3062 .expect("create failed");
3063 let _cat =
3064 dir.create_child_file(&mut transaction, "cat").await.expect("create_child_file failed");
3065 let _ball = dir
3066 .create_child_file(&mut transaction, "ball")
3067 .await
3068 .expect("create_child_file failed");
3069 let apple = dir
3070 .create_child_file(&mut transaction, "apple")
3071 .await
3072 .expect("create_child_file failed");
3073 let _dog =
3074 dir.create_child_file(&mut transaction, "dog").await.expect("create_child_file failed");
3075 transaction.commit().await.expect("commit failed");
3076 transaction = fs
3077 .root_store()
3078 .new_transaction(
3079 lock_keys![
3080 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3081 LockKey::object(fs.root_store().store_object_id(), apple.object_id()),
3082 ],
3083 Options::default(),
3084 )
3085 .await
3086 .expect("new_transaction failed");
3087 replace_child(&mut transaction, None, (&dir, "apple")).await.expect("replace_child failed");
3088 transaction.commit().await.expect("commit failed");
3089 let layer_set = dir.store().tree().layer_set();
3090 let mut merger = layer_set.merger();
3091 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
3092 let mut entries = Vec::new();
3093 while let Some((name, _, _)) = iter.get() {
3094 entries.push(name.to_string());
3095 iter.advance().await.expect("advance failed");
3096 }
3097 assert_eq!(&entries, &["ball", "cat", "dog"]);
3098 fs.close().await.expect("Close failed");
3099 }
3100
3101 #[fuchsia::test]
3102 async fn test_sub_dir_count() {
3103 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3104 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3105 let dir;
3106 let child_dir;
3107 let mut transaction = fs
3108 .root_store()
3109 .new_transaction(lock_keys![], Options::default())
3110 .await
3111 .expect("new_transaction failed");
3112 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3113 .await
3114 .expect("create failed");
3115 child_dir =
3116 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3117 transaction.commit().await.expect("commit failed");
3118 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3119
3120 transaction = fs
3122 .root_store()
3123 .new_transaction(
3124 lock_keys![
3125 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3126 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3127 ],
3128 Options::default(),
3129 )
3130 .await
3131 .expect("new_transaction failed");
3132 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
3133 .await
3134 .expect("replace_child failed");
3135 transaction.commit().await.expect("commit failed");
3136
3137 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3138 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3139
3140 transaction = fs
3142 .root_store()
3143 .new_transaction(
3144 lock_keys![LockKey::object(
3145 fs.root_store().store_object_id(),
3146 child_dir.object_id()
3147 )],
3148 Options::default(),
3149 )
3150 .await
3151 .expect("new_transaction failed");
3152 let second_child = child_dir
3153 .create_child_dir(&mut transaction, "baz")
3154 .await
3155 .expect("create_child_dir failed");
3156 transaction.commit().await.expect("commit failed");
3157
3158 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3159
3160 transaction = fs
3161 .root_store()
3162 .new_transaction(
3163 lock_keys![
3164 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3165 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3166 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3167 ],
3168 Options::default(),
3169 )
3170 .await
3171 .expect("new_transaction failed");
3172 replace_child(&mut transaction, Some((&child_dir, "baz")), (&dir, "foo"))
3173 .await
3174 .expect("replace_child failed");
3175 transaction.commit().await.expect("commit failed");
3176
3177 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 2);
3178 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3179
3180 transaction = fs
3182 .root_store()
3183 .new_transaction(
3184 lock_keys![
3185 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3186 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
3187 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3188 ],
3189 Options::default(),
3190 )
3191 .await
3192 .expect("new_transaction failed");
3193 replace_child(&mut transaction, Some((&dir, "bar")), (&dir, "foo"))
3194 .await
3195 .expect("replace_child failed");
3196 transaction.commit().await.expect("commit failed");
3197
3198 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
3199
3200 transaction = fs
3202 .root_store()
3203 .new_transaction(
3204 lock_keys![
3205 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3206 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3207 ],
3208 Options::default(),
3209 )
3210 .await
3211 .expect("new_transaction failed");
3212 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3213 transaction.commit().await.expect("commit failed");
3214
3215 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
3216 fs.close().await.expect("Close failed");
3217 }
3218
3219 #[fuchsia::test]
3220 async fn test_deleted_dir() {
3221 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3222 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3223 let dir;
3224 let mut transaction = fs
3225 .root_store()
3226 .new_transaction(lock_keys![], Options::default())
3227 .await
3228 .expect("new_transaction failed");
3229 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3230 .await
3231 .expect("create failed");
3232 let child =
3233 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3234 dir.create_child_dir(&mut transaction, "bar").await.expect("create_child_dir failed");
3235 transaction.commit().await.expect("commit failed");
3236
3237 dir.store().flush().await.expect("flush failed");
3239
3240 transaction = fs
3242 .root_store()
3243 .new_transaction(
3244 lock_keys![
3245 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3246 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
3247 ],
3248 Options::default(),
3249 )
3250 .await
3251 .expect("new_transaction failed");
3252 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
3253 transaction.commit().await.expect("commit failed");
3254
3255 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3257
3258 assert!(dir.lookup("bar").await.expect("lookup failed").is_some());
3260
3261 dir.set_deleted();
3263
3264 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3265 assert_eq!(dir.lookup("bar").await.expect("lookup failed"), None);
3266 assert!(!dir.has_children().await.expect("has_children failed"));
3267
3268 transaction = fs
3269 .root_store()
3270 .new_transaction(lock_keys![], Options::default())
3271 .await
3272 .expect("new_transaction failed");
3273
3274 let assert_access_denied = |result| {
3275 if let Err(e) = result {
3276 assert!(FxfsError::Deleted.matches(&e));
3277 } else {
3278 panic!();
3279 }
3280 };
3281 assert_access_denied(dir.create_child_dir(&mut transaction, "baz").await.map(|_| {}));
3282 assert_access_denied(dir.create_child_file(&mut transaction, "baz").await.map(|_| {}));
3283 assert_access_denied(dir.add_child_volume(&mut transaction, "baz", 1).await);
3284 assert_access_denied(
3285 dir.insert_child(&mut transaction, "baz", 1, ObjectDescriptor::File).await,
3286 );
3287 assert_access_denied(
3288 dir.update_dir_attributes_internal(
3289 &mut transaction,
3290 dir.object_id(),
3291 MutableAttributesInternal {
3292 creation_time: Some(Timestamp::zero().as_nanos()),
3293 ..Default::default()
3294 },
3295 )
3296 .await,
3297 );
3298 let layer_set = dir.store().tree().layer_set();
3299 let mut merger = layer_set.merger();
3300 assert_access_denied(dir.iter(&mut merger).await.map(|_| {}));
3301 }
3302
3303 #[fuchsia::test]
3304 async fn test_create_symlink() {
3305 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3306 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3307 let (dir_id, symlink_id) = {
3308 let mut transaction = fs
3309 .root_store()
3310 .new_transaction(lock_keys![], Options::default())
3311 .await
3312 .expect("new_transaction failed");
3313 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
3314 .await
3315 .expect("create failed");
3316
3317 let symlink_id = dir
3318 .create_symlink(&mut transaction, b"link", "foo")
3319 .await
3320 .expect("create_symlink failed");
3321 transaction.commit().await.expect("commit failed");
3322
3323 fs.sync(SyncOptions::default()).await.expect("sync failed");
3324 (dir.object_id(), symlink_id)
3325 };
3326 fs.close().await.expect("Close failed");
3327 let device = fs.take_device().await;
3328 device.reopen(false);
3329 let fs = FxFilesystem::open(device).await.expect("open failed");
3330 {
3331 let dir = Directory::open(&fs.root_store(), dir_id).await.expect("open failed");
3332 assert_eq!(
3333 dir.lookup("foo").await.expect("lookup failed").expect("not found"),
3334 (symlink_id, ObjectDescriptor::Symlink, false)
3335 );
3336 }
3337 fs.close().await.expect("Close failed");
3338 }
3339
3340 #[fuchsia::test]
3341 async fn test_read_symlink() {
3342 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3343 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3344 let mut transaction = fs
3345 .root_store()
3346 .new_transaction(lock_keys![], Options::default())
3347 .await
3348 .expect("new_transaction failed");
3349 let store = fs.root_store();
3350 let dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3351
3352 let symlink_id = dir
3353 .create_symlink(&mut transaction, b"link", "foo")
3354 .await
3355 .expect("create_symlink failed");
3356 transaction.commit().await.expect("commit failed");
3357
3358 let link = store.read_symlink(symlink_id).await.expect("read_symlink failed");
3359 assert_eq!(&link, b"link");
3360 fs.close().await.expect("Close failed");
3361 }
3362
3363 #[fuchsia::test]
3364 async fn test_unlink_symlink() {
3365 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3366 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3367 let dir;
3368 let mut transaction = fs
3369 .root_store()
3370 .new_transaction(lock_keys![], Options::default())
3371 .await
3372 .expect("new_transaction failed");
3373 let store = fs.root_store();
3374 dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
3375
3376 let symlink_id = dir
3377 .create_symlink(&mut transaction, b"link", "foo")
3378 .await
3379 .expect("create_symlink failed");
3380 transaction.commit().await.expect("commit failed");
3381 transaction = fs
3382 .root_store()
3383 .new_transaction(
3384 lock_keys![
3385 LockKey::object(store.store_object_id(), dir.object_id()),
3386 LockKey::object(store.store_object_id(), symlink_id),
3387 ],
3388 Options::default(),
3389 )
3390 .await
3391 .expect("new_transaction failed");
3392 assert_matches!(
3393 replace_child(&mut transaction, None, (&dir, "foo"))
3394 .await
3395 .expect("replace_child failed"),
3396 ReplacedChild::Object(_)
3397 );
3398 transaction.commit().await.expect("commit failed");
3399
3400 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
3401 fs.close().await.expect("Close failed");
3402 }
3403
3404 #[fuchsia::test]
3405 async fn test_get_properties() {
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 dir;
3409 let mut transaction = fs
3410 .root_store()
3411 .new_transaction(lock_keys![], Options::default())
3412 .await
3413 .expect("new_transaction failed");
3414
3415 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3416 .await
3417 .expect("create failed");
3418 transaction.commit().await.expect("commit failed");
3419
3420 let mut properties = dir.get_properties().await.expect("get_properties failed");
3422 let dir_creation_time = properties.creation_time;
3423 assert_eq!(dir_creation_time, properties.modification_time);
3424 assert_eq!(properties.sub_dirs, 0);
3425 assert!(properties.posix_attributes.is_none());
3426
3427 transaction = fs
3429 .root_store()
3430 .new_transaction(
3431 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3432 Options::default(),
3433 )
3434 .await
3435 .expect("new_transaction failed");
3436 let child_dir =
3437 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
3438 transaction.commit().await.expect("commit failed");
3439
3440 properties = dir.get_properties().await.expect("get_properties failed");
3442 assert_eq!(dir_creation_time, properties.creation_time);
3444 assert!(dir_creation_time < properties.modification_time);
3445 assert_eq!(properties.sub_dirs, 1);
3446 assert!(properties.posix_attributes.is_none());
3447
3448 properties = child_dir.get_properties().await.expect("get_properties failed");
3450 assert_eq!(properties.creation_time, properties.modification_time);
3451 assert_eq!(properties.sub_dirs, 0);
3452 assert!(properties.posix_attributes.is_none());
3453
3454 transaction = fs
3456 .root_store()
3457 .new_transaction(
3458 lock_keys![LockKey::object(
3459 fs.root_store().store_object_id(),
3460 child_dir.object_id()
3461 )],
3462 Options::default(),
3463 )
3464 .await
3465 .expect("new_transaction failed");
3466 let child_dir_file = child_dir
3467 .create_child_file(&mut transaction, "bar")
3468 .await
3469 .expect("create_child_file failed");
3470 child_dir_file
3471 .update_attributes(
3472 &mut transaction,
3473 Some(&fio::MutableNodeAttributes { gid: Some(1), ..Default::default() }),
3474 None,
3475 )
3476 .await
3477 .expect("Updating attributes");
3478 transaction.commit().await.expect("commit failed");
3479
3480 properties = child_dir.get_properties().await.expect("get_properties failed");
3482 assert!(properties.creation_time < properties.modification_time);
3483 assert!(properties.posix_attributes.is_none());
3484
3485 properties = child_dir_file.get_properties().await.expect("get_properties failed");
3487 assert_eq!(properties.creation_time, properties.modification_time);
3488 assert_eq!(properties.sub_dirs, 0);
3489 assert!(properties.posix_attributes.is_some());
3490 assert_eq!(properties.posix_attributes.unwrap().gid, 1);
3491 assert_eq!(properties.posix_attributes.unwrap().uid, 0);
3493 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3494 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3495 }
3496
3497 #[fuchsia::test]
3498 async fn test_update_create_attributes() {
3499 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3500 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3501 let dir;
3502 let mut transaction = fs
3503 .root_store()
3504 .new_transaction(lock_keys![], Options::default())
3505 .await
3506 .expect("new_transaction failed");
3507
3508 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3509 .await
3510 .expect("create failed");
3511 transaction.commit().await.expect("commit failed");
3512 let mut properties = dir.get_properties().await.expect("get_properties failed");
3513 assert_eq!(properties.sub_dirs, 0);
3514 assert!(properties.posix_attributes.is_none());
3515 let creation_time = properties.creation_time;
3516 let modification_time = properties.modification_time;
3517 assert_eq!(creation_time, modification_time);
3518
3519 transaction = fs
3525 .root_store()
3526 .new_transaction(
3527 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3528 Options::default(),
3529 )
3530 .await
3531 .expect("new_transaction failed");
3532 let now = Timestamp::now();
3533 dir.update_attributes(
3534 transaction,
3535 Some(&fio::MutableNodeAttributes {
3536 modification_time: Some(now.as_nanos()),
3537 uid: Some(1),
3538 gid: Some(2),
3539 ..Default::default()
3540 }),
3541 0,
3542 None,
3543 )
3544 .await
3545 .expect("update_attributes failed");
3546 properties = dir.get_properties().await.expect("get_properties failed");
3547 assert_eq!(properties.modification_time, now);
3549 assert!(properties.posix_attributes.is_some());
3550 assert_eq!(properties.posix_attributes.unwrap().uid, 1);
3551 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3552 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3554 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3555 assert_eq!(properties.sub_dirs, 0);
3557 assert_eq!(properties.creation_time, creation_time);
3558
3559 let transaction = fs
3562 .root_store()
3563 .new_transaction(
3564 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3565 Options::default(),
3566 )
3567 .await
3568 .expect("new_transaction failed");
3569 dir.update_attributes(
3570 transaction,
3571 Some(&fio::MutableNodeAttributes {
3572 creation_time: Some(now.as_nanos()),
3573 uid: Some(3),
3574 rdev: Some(10),
3575 ..Default::default()
3576 }),
3577 0,
3578 None,
3579 )
3580 .await
3581 .expect("update_attributes failed");
3582 properties = dir.get_properties().await.expect("get_properties failed");
3583 assert_eq!(properties.creation_time, now);
3584 assert!(properties.posix_attributes.is_some());
3585 assert_eq!(properties.posix_attributes.unwrap().uid, 3);
3586 assert_eq!(properties.posix_attributes.unwrap().rdev, 10);
3587 assert_eq!(properties.sub_dirs, 0);
3589 assert_eq!(properties.modification_time, now);
3590 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3591 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3592 }
3593
3594 #[fuchsia::test]
3595 async fn write_to_directory_attribute_creates_keys() {
3596 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3597 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3598 let crypt = Arc::new(new_insecure_crypt());
3599
3600 {
3601 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3602 let store = root_volume
3603 .new_volume(
3604 "vol",
3605 NewChildStoreOptions {
3606 options: StoreOptions {
3607 crypt: Some(crypt.clone()),
3608 ..StoreOptions::default()
3609 },
3610 ..Default::default()
3611 },
3612 )
3613 .await
3614 .expect("new_volume failed");
3615 let mut transaction = filesystem
3616 .root_store()
3617 .new_transaction(
3618 lock_keys![LockKey::object(
3619 store.store_object_id(),
3620 store.root_directory_object_id()
3621 )],
3622 Options::default(),
3623 )
3624 .await
3625 .expect("new transaction failed");
3626 let root_directory = Directory::open(&store, store.root_directory_object_id())
3627 .await
3628 .expect("open failed");
3629 let directory = root_directory
3630 .create_child_dir(&mut transaction, "foo")
3631 .await
3632 .expect("create_child_dir failed");
3633 transaction.commit().await.expect("commit failed");
3634
3635 let mut transaction = filesystem
3636 .root_store()
3637 .new_transaction(
3638 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
3639 Options::default(),
3640 )
3641 .await
3642 .expect("new transaction failed");
3643 let _ = directory
3644 .handle
3645 .write_attr(&mut transaction, AttributeId::TEST_ID, b"bar")
3646 .await
3647 .expect("write_attr failed");
3648 transaction.commit().await.expect("commit failed");
3649 }
3650
3651 filesystem.close().await.expect("Close failed");
3652 let device = filesystem.take_device().await;
3653 device.reopen(false);
3654 let filesystem = FxFilesystem::open(device).await.expect("open failed");
3655
3656 {
3657 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3658 let volume = root_volume
3659 .volume("vol", StoreOptions { crypt: Some(crypt), ..StoreOptions::default() })
3660 .await
3661 .expect("volume failed");
3662 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
3663 .await
3664 .expect("open failed");
3665 let directory = Directory::open(
3666 &volume,
3667 root_directory.lookup("foo").await.expect("lookup failed").expect("not found").0,
3668 )
3669 .await
3670 .expect("open failed");
3671 let mut buffer = directory.handle.allocate_buffer(10).await;
3672 assert_eq!(
3673 directory
3674 .handle
3675 .read(AttributeId::TEST_ID, 0, buffer.as_mut())
3676 .await
3677 .expect("read failed"),
3678 3
3679 );
3680 assert_eq!(&buffer.as_slice()[..3], b"bar");
3681 }
3682
3683 filesystem.close().await.expect("Close failed");
3684 }
3685
3686 #[fuchsia::test]
3687 async fn directory_with_extended_attributes() {
3688 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3689 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3690 let crypt = Arc::new(new_insecure_crypt());
3691
3692 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3693 let store = root_volume
3694 .new_volume(
3695 "vol",
3696 NewChildStoreOptions {
3697 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3698 ..Default::default()
3699 },
3700 )
3701 .await
3702 .expect("new_volume failed");
3703 let directory =
3704 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3705
3706 let test_small_name = b"security.selinux".to_vec();
3707 let test_small_value = b"foo".to_vec();
3708 let test_large_name = b"large.attribute".to_vec();
3709 let test_large_value = vec![1u8; 500];
3710
3711 directory
3712 .set_extended_attribute(
3713 test_small_name.clone(),
3714 test_small_value.clone(),
3715 SetExtendedAttributeMode::Set,
3716 )
3717 .await
3718 .unwrap();
3719 assert_eq!(
3720 directory.get_extended_attribute(test_small_name.clone()).await.unwrap(),
3721 test_small_value
3722 );
3723
3724 directory
3725 .set_extended_attribute(
3726 test_large_name.clone(),
3727 test_large_value.clone(),
3728 SetExtendedAttributeMode::Set,
3729 )
3730 .await
3731 .unwrap();
3732 assert_eq!(
3733 directory.get_extended_attribute(test_large_name.clone()).await.unwrap(),
3734 test_large_value
3735 );
3736
3737 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3738 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3739 .await
3740 .unwrap();
3741
3742 directory.remove_extended_attribute(test_small_name.clone()).await.unwrap();
3743 directory.remove_extended_attribute(test_large_name.clone()).await.unwrap();
3744
3745 filesystem.close().await.expect("close failed");
3746 }
3747
3748 #[fuchsia::test]
3749 async fn remove_directory_with_extended_attributes() {
3750 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3751 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3752 let crypt = Arc::new(new_insecure_crypt());
3753
3754 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3755 let store = root_volume
3756 .new_volume(
3757 "vol",
3758 NewChildStoreOptions {
3759 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3760 ..Default::default()
3761 },
3762 )
3763 .await
3764 .expect("new_volume failed");
3765 let mut transaction = filesystem
3766 .root_store()
3767 .new_transaction(
3768 lock_keys![LockKey::object(
3769 store.store_object_id(),
3770 store.root_directory_object_id()
3771 )],
3772 Options::default(),
3773 )
3774 .await
3775 .expect("new transaction failed");
3776 let root_directory =
3777 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3778 let directory = root_directory
3779 .create_child_dir(&mut transaction, "foo")
3780 .await
3781 .expect("create_child_dir failed");
3782 transaction.commit().await.expect("commit failed");
3783
3784 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3785 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3786 .await
3787 .unwrap();
3788
3789 let test_small_name = b"security.selinux".to_vec();
3790 let test_small_value = b"foo".to_vec();
3791 let test_large_name = b"large.attribute".to_vec();
3792 let test_large_value = vec![1u8; 500];
3793
3794 directory
3795 .set_extended_attribute(
3796 test_small_name.clone(),
3797 test_small_value.clone(),
3798 SetExtendedAttributeMode::Set,
3799 )
3800 .await
3801 .unwrap();
3802 directory
3803 .set_extended_attribute(
3804 test_large_name.clone(),
3805 test_large_value.clone(),
3806 SetExtendedAttributeMode::Set,
3807 )
3808 .await
3809 .unwrap();
3810
3811 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3812 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3813 .await
3814 .unwrap();
3815
3816 let mut transaction = filesystem
3817 .root_store()
3818 .new_transaction(
3819 lock_keys![
3820 LockKey::object(store.store_object_id(), root_directory.object_id()),
3821 LockKey::object(store.store_object_id(), directory.object_id()),
3822 ],
3823 Options::default(),
3824 )
3825 .await
3826 .expect("new_transaction failed");
3827 replace_child(&mut transaction, None, (&root_directory, "foo"))
3828 .await
3829 .expect("replace_child failed");
3830 transaction.commit().await.unwrap();
3831
3832 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3833 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3834 .await
3835 .unwrap();
3836
3837 filesystem.close().await.expect("close failed");
3838 }
3839
3840 #[fuchsia::test]
3841 async fn remove_symlink_with_extended_attributes() {
3842 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3843 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3844 let crypt = Arc::new(new_insecure_crypt());
3845
3846 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3847 let store = root_volume
3848 .new_volume(
3849 "vol",
3850 NewChildStoreOptions {
3851 options: StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
3852 ..Default::default()
3853 },
3854 )
3855 .await
3856 .expect("new_volume failed");
3857 let mut transaction = filesystem
3858 .root_store()
3859 .new_transaction(
3860 lock_keys![LockKey::object(
3861 store.store_object_id(),
3862 store.root_directory_object_id()
3863 )],
3864 Options::default(),
3865 )
3866 .await
3867 .expect("new transaction failed");
3868 let root_directory =
3869 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3870 let symlink_id = root_directory
3871 .create_symlink(&mut transaction, b"somewhere/else", "foo")
3872 .await
3873 .expect("create_symlink failed");
3874 transaction.commit().await.expect("commit failed");
3875
3876 let symlink = StoreObjectHandle::new(
3877 store.clone(),
3878 symlink_id,
3879 false,
3880 HandleOptions::default(),
3881 false,
3882 );
3883
3884 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3885 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3886 .await
3887 .unwrap();
3888
3889 let test_small_name = b"security.selinux".to_vec();
3890 let test_small_value = b"foo".to_vec();
3891 let test_large_name = b"large.attribute".to_vec();
3892 let test_large_value = vec![1u8; 500];
3893
3894 symlink
3895 .set_extended_attribute(
3896 test_small_name.clone(),
3897 test_small_value.clone(),
3898 SetExtendedAttributeMode::Set,
3899 )
3900 .await
3901 .unwrap();
3902 symlink
3903 .set_extended_attribute(
3904 test_large_name.clone(),
3905 test_large_value.clone(),
3906 SetExtendedAttributeMode::Set,
3907 )
3908 .await
3909 .unwrap();
3910
3911 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3912 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3913 .await
3914 .unwrap();
3915
3916 let mut transaction = filesystem
3917 .root_store()
3918 .new_transaction(
3919 lock_keys![
3920 LockKey::object(store.store_object_id(), root_directory.object_id()),
3921 LockKey::object(store.store_object_id(), symlink.object_id()),
3922 ],
3923 Options::default(),
3924 )
3925 .await
3926 .expect("new_transaction failed");
3927 replace_child(&mut transaction, None, (&root_directory, "foo"))
3928 .await
3929 .expect("replace_child failed");
3930 transaction.commit().await.unwrap();
3931
3932 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3933 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3934 .await
3935 .unwrap();
3936
3937 filesystem.close().await.expect("close failed");
3938 }
3939
3940 #[fuchsia::test]
3941 async fn test_update_timestamps() {
3942 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3943 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3944 let dir;
3945 let mut transaction = fs
3946 .root_store()
3947 .new_transaction(lock_keys![], Options::default())
3948 .await
3949 .expect("new_transaction failed");
3950
3951 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3954 .await
3955 .expect("create failed");
3956 transaction.commit().await.expect("commit failed");
3957 let mut properties = dir.get_properties().await.expect("get_properties failed");
3958 let starting_time = properties.creation_time;
3959 assert_eq!(properties.creation_time, starting_time);
3960 assert_eq!(properties.modification_time, starting_time);
3961 assert_eq!(properties.change_time, starting_time);
3962 assert_eq!(properties.access_time, starting_time);
3963
3964 transaction = fs
3966 .root_store()
3967 .new_transaction(
3968 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3969 Options::default(),
3970 )
3971 .await
3972 .expect("new_transaction failed");
3973 let update1_time = Timestamp::now();
3974 dir.update_attributes(
3975 transaction,
3976 Some(&fio::MutableNodeAttributes {
3977 modification_time: Some(update1_time.as_nanos()),
3978 ..Default::default()
3979 }),
3980 0,
3981 Some(update1_time),
3982 )
3983 .await
3984 .expect("update_attributes failed");
3985 properties = dir.get_properties().await.expect("get_properties failed");
3986 assert_eq!(properties.modification_time, update1_time);
3987 assert_eq!(properties.access_time, starting_time);
3988 assert_eq!(properties.creation_time, starting_time);
3989 assert_eq!(properties.change_time, update1_time);
3990 }
3991
3992 #[fuchsia::test]
3993 async fn test_move_dir_timestamps() {
3994 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3995 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3996 let dir;
3997 let child1;
3998 let child2;
3999 let mut transaction = fs
4000 .root_store()
4001 .new_transaction(lock_keys![], Options::default())
4002 .await
4003 .expect("new_transaction failed");
4004 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4005 .await
4006 .expect("create failed");
4007 child1 = dir
4008 .create_child_dir(&mut transaction, "child1")
4009 .await
4010 .expect("create_child_dir failed");
4011 child2 = dir
4012 .create_child_dir(&mut transaction, "child2")
4013 .await
4014 .expect("create_child_dir failed");
4015 transaction.commit().await.expect("commit failed");
4016 let dir_properties = dir.get_properties().await.expect("get_properties failed");
4017 let child2_properties = child2.get_properties().await.expect("get_properties failed");
4018
4019 transaction = fs
4021 .root_store()
4022 .new_transaction(
4023 lock_keys![
4024 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4025 LockKey::object(fs.root_store().store_object_id(), child1.object_id()),
4026 LockKey::object(fs.root_store().store_object_id(), child2.object_id()),
4027 ],
4028 Options::default(),
4029 )
4030 .await
4031 .expect("new_transaction failed");
4032 assert_matches!(
4033 replace_child(&mut transaction, Some((&dir, "child2")), (&child1, "child2"))
4034 .await
4035 .expect("replace_child failed"),
4036 ReplacedChild::None
4037 );
4038 transaction.commit().await.expect("commit failed");
4039 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
4041 let time_of_replacement = new_dir_properties.change_time;
4042 assert!(new_dir_properties.change_time > dir_properties.change_time);
4043 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
4044 let new_child1_properties = child1.get_properties().await.expect("get_properties failed");
4046 assert_eq!(new_child1_properties.modification_time, time_of_replacement);
4047 assert_eq!(new_child1_properties.change_time, time_of_replacement);
4048 let moved_child2_properties = child2.get_properties().await.expect("get_properties failed");
4050 assert_eq!(moved_child2_properties.change_time, time_of_replacement);
4051 assert_eq!(moved_child2_properties.creation_time, child2_properties.creation_time);
4052 assert_eq!(moved_child2_properties.access_time, child2_properties.access_time);
4053 assert_eq!(moved_child2_properties.modification_time, child2_properties.modification_time);
4054 fs.close().await.expect("Close failed");
4055 }
4056
4057 #[fuchsia::test]
4058 async fn test_unlink_timestamps() {
4059 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4060 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4061 let dir;
4062 let foo;
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 foo =
4072 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_dir failed");
4073
4074 transaction.commit().await.expect("commit failed");
4075 let dir_properties = dir.get_properties().await.expect("get_properties failed");
4076 let foo_properties = foo.get_properties().await.expect("get_properties failed");
4077
4078 transaction = fs
4079 .root_store()
4080 .new_transaction(
4081 lock_keys![
4082 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4083 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
4084 ],
4085 Options::default(),
4086 )
4087 .await
4088 .expect("new_transaction failed");
4089 assert_matches!(
4090 replace_child(&mut transaction, None, (&dir, "foo"))
4091 .await
4092 .expect("replace_child failed"),
4093 ReplacedChild::Object(_)
4094 );
4095 transaction.commit().await.expect("commit failed");
4096 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
4098 let time_of_replacement = new_dir_properties.change_time;
4099 assert!(new_dir_properties.change_time > dir_properties.change_time);
4100 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
4101 let moved_foo_properties = foo.get_properties().await.expect("get_properties failed");
4103 assert_eq!(moved_foo_properties.change_time, time_of_replacement);
4104 assert_eq!(moved_foo_properties.creation_time, foo_properties.creation_time);
4105 assert_eq!(moved_foo_properties.access_time, foo_properties.access_time);
4106 assert_eq!(moved_foo_properties.modification_time, foo_properties.modification_time);
4107 fs.close().await.expect("Close failed");
4108 }
4109
4110 #[fuchsia::test]
4111 async fn test_replace_dir_timestamps() {
4112 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4113 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4114 let dir;
4115 let child_dir1;
4116 let child_dir2;
4117 let foo;
4118 let mut transaction = fs
4119 .root_store()
4120 .new_transaction(lock_keys![], Options::default())
4121 .await
4122 .expect("new_transaction failed");
4123 dir = Directory::create(&mut transaction, &fs.root_store(), None)
4124 .await
4125 .expect("create failed");
4126 child_dir1 =
4127 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
4128 child_dir2 =
4129 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
4130 foo = child_dir1
4131 .create_child_dir(&mut transaction, "foo")
4132 .await
4133 .expect("create_child_dir failed");
4134 transaction.commit().await.expect("commit failed");
4135 let dir_props = dir.get_properties().await.expect("get_properties failed");
4136 let foo_props = foo.get_properties().await.expect("get_properties failed");
4137
4138 transaction = fs
4139 .root_store()
4140 .new_transaction(
4141 lock_keys![
4142 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
4143 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
4144 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
4145 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
4146 ],
4147 Options::default(),
4148 )
4149 .await
4150 .expect("new_transaction failed");
4151 assert_matches!(
4152 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&dir, "dir2"))
4153 .await
4154 .expect("replace_child failed"),
4155 ReplacedChild::Directory(_)
4156 );
4157 transaction.commit().await.expect("commit failed");
4158 let new_dir_props = dir.get_properties().await.expect("get_properties failed");
4160 let time_of_replacement = new_dir_props.change_time;
4161 assert!(new_dir_props.change_time > dir_props.change_time);
4162 assert_eq!(new_dir_props.modification_time, time_of_replacement);
4163 let new_dir1_props = child_dir1.get_properties().await.expect("get_properties failed");
4165 let time_of_replacement = new_dir1_props.change_time;
4166 assert_eq!(new_dir1_props.change_time, time_of_replacement);
4167 assert_eq!(new_dir1_props.modification_time, time_of_replacement);
4168 let moved_foo_props = foo.get_properties().await.expect("get_properties failed");
4170 assert_eq!(moved_foo_props.change_time, time_of_replacement);
4171 assert_eq!(moved_foo_props.creation_time, foo_props.creation_time);
4172 assert_eq!(moved_foo_props.access_time, foo_props.access_time);
4173 assert_eq!(moved_foo_props.modification_time, foo_props.modification_time);
4174 fs.close().await.expect("Close failed");
4175 }
4176
4177 #[fuchsia::test]
4178 async fn test_create_casefold_directory() {
4179 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4180 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4181 let object_id = {
4182 let mut transaction = fs
4183 .root_store()
4184 .new_transaction(lock_keys![], Options::default())
4185 .await
4186 .expect("new_transaction failed");
4187 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
4188 .await
4189 .expect("create failed");
4190
4191 let child_dir = dir
4192 .create_child_dir(&mut transaction, "foo")
4193 .await
4194 .expect("create_child_dir failed");
4195 let _child_dir_file = child_dir
4196 .create_child_file(&mut transaction, "bAr")
4197 .await
4198 .expect("create_child_file failed");
4199 transaction.commit().await.expect("commit failed");
4200 dir.object_id()
4201 };
4202 fs.close().await.expect("Close failed");
4203 let device = fs.take_device().await;
4204
4205 device.reopen(false);
4208 let fs = FxFilesystem::open(device).await.expect("open failed");
4209 {
4210 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4211 let (object_id, object_descriptor, _) =
4212 dir.lookup("foo").await.expect("lookup failed").expect("not found");
4213 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
4214 let child_dir =
4215 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
4216 assert!(!child_dir.dir_type().is_casefold());
4217 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_none());
4218 let (object_id, descriptor, _) =
4219 child_dir.lookup("bAr").await.expect("lookup failed").unwrap();
4220 assert_eq!(descriptor, ObjectDescriptor::File);
4221
4222 child_dir.set_casefold(true).await.expect_err("not empty");
4224
4225 let mut transaction = fs
4227 .root_store()
4228 .new_transaction(
4229 lock_keys![
4230 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
4231 LockKey::object(fs.root_store().store_object_id(), object_id),
4232 ],
4233 Options::default(),
4234 )
4235 .await
4236 .expect("new_transaction failed");
4237 assert_matches!(
4238 replace_child(&mut transaction, None, (&child_dir, "bAr"))
4239 .await
4240 .expect("replace_child failed"),
4241 ReplacedChild::Object(..)
4242 );
4243 transaction.commit().await.expect("commit failed");
4244
4245 child_dir.set_casefold(true).await.expect("set casefold");
4247
4248 assert!(child_dir.dir_type().is_casefold());
4249
4250 let mut transaction = fs
4252 .root_store()
4253 .new_transaction(
4254 lock_keys![LockKey::object(
4255 fs.root_store().store_object_id(),
4256 child_dir.object_id()
4257 ),],
4258 Options::default(),
4259 )
4260 .await
4261 .expect("new_transaction failed");
4262 let _child_dir_file = child_dir
4263 .create_child_file(&mut transaction, "bAr")
4264 .await
4265 .expect("create_child_file failed");
4266 transaction.commit().await.expect("commit failed");
4267
4268 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_some());
4270 assert!(child_dir.lookup("bAr").await.expect("lookup failed").is_some());
4271
4272 child_dir.set_casefold(true).await.expect_err("set casefold");
4274 assert!(child_dir.dir_type().is_casefold());
4275
4276 let mut transaction = fs
4278 .root_store()
4279 .new_transaction(
4280 lock_keys![LockKey::object(
4281 fs.root_store().store_object_id(),
4282 child_dir.object_id()
4283 ),],
4284 Options::default(),
4285 )
4286 .await
4287 .expect("new_transaction failed");
4288 let sub_dir = child_dir
4289 .create_child_dir(&mut transaction, "sub")
4290 .await
4291 .expect("create_sub_dir failed");
4292 transaction.commit().await.expect("commit failed");
4293 assert!(sub_dir.dir_type().is_casefold());
4294 };
4295 fs.close().await.expect("Close failed");
4296 }
4297
4298 #[fuchsia::test]
4299 async fn test_create_casefold_encrypted_directory() {
4300 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4301 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4302 let proxy_filename: ProxyFilename;
4303 let object_id;
4304 {
4305 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4306 let root_volume = root_volume(fs.clone()).await.unwrap();
4307 let store = root_volume
4308 .new_volume(
4309 "vol",
4310 NewChildStoreOptions {
4311 options: StoreOptions {
4312 crypt: Some(crypt.clone()),
4313 ..StoreOptions::default()
4314 },
4315 ..Default::default()
4316 },
4317 )
4318 .await
4319 .unwrap();
4320
4321 crypt
4323 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4324 .expect("add wrapping key failed");
4325
4326 object_id = {
4327 let mut transaction = fs
4328 .root_store()
4329 .new_transaction(lock_keys![], Options::default())
4330 .await
4331 .expect("new_transaction failed");
4332 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4333 .await
4334 .expect("create failed");
4335
4336 transaction.commit().await.expect("commit");
4337 dir.object_id()
4338 };
4339 let dir = Directory::open(&store, object_id).await.expect("open failed");
4340
4341 dir.set_casefold(true).await.expect("set casefold");
4342 assert!(dir.dir_type().is_casefold());
4343
4344 let mut transaction = fs
4345 .root_store()
4346 .new_transaction(
4347 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4348 Options::default(),
4349 )
4350 .await
4351 .expect("new_transaction failed");
4352 let _file = dir
4353 .create_child_file(&mut transaction, "bAr")
4354 .await
4355 .expect("create_child_file failed");
4356 transaction.commit().await.expect("commit failed");
4357
4358 assert!(dir.lookup("bAr").await.expect("original lookup failed").is_some());
4360
4361 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4364 let encrypted_name =
4365 encrypt_filename(&*key, dir.object_id(), "bAr").expect("encrypt_filename");
4366 let hash_code = key.hash_code_casefold("bAr");
4367 proxy_filename = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4368
4369 assert!(dir.lookup("BAR").await.expect("casefold lookup failed").is_some());
4371
4372 assert_eq!(key.hash_code_casefold("bar"), key.hash_code_casefold("BaR"));
4374
4375 let mut count = 0;
4378 let layer_set = dir.store().tree().layer_set();
4379 let mut merger = layer_set.merger();
4380 let mut iter = dir.iter(&mut merger).await.expect("iter");
4381 while let Some(_entry) = iter.get() {
4382 count += 1;
4383 iter.advance().await.expect("advance");
4384 }
4385 assert_eq!(1, count, "unexpected number of entries.");
4386
4387 fs.close().await.expect("Close failed");
4388 }
4389
4390 let device = fs.take_device().await;
4391
4392 device.reopen(false);
4395 let fs = FxFilesystem::open(device).await.expect("open failed");
4396 {
4397 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4398 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4399 let store = root_volume
4400 .volume(
4401 "vol",
4402 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4403 )
4404 .await
4405 .expect("volume failed");
4406 let dir = Directory::open(&store, object_id).await.expect("open failed");
4407 assert!(dir.dir_type().is_casefold());
4408
4409 assert!(dir.lookup("bAr").await.expect("lookup failed").is_none());
4411 let filename: String = proxy_filename.into();
4413 assert!(dir.lookup(&filename).await.expect("lookup failed").is_some());
4414
4415 let layer_set = dir.store().tree().layer_set();
4416 let mut merger = layer_set.merger();
4417 let mut iter = dir.iter(&mut merger).await.expect("iter");
4418 let item = iter.get().expect("expect item");
4419 let filename: String = proxy_filename.into();
4420 assert_eq!(item.0, &filename);
4421 iter.advance().await.expect("advance");
4422 assert_eq!(None, iter.get());
4423
4424 crate::fsck::fsck(fs.clone()).await.unwrap();
4425 crate::fsck::fsck_volume(fs.as_ref(), store.store_object_id(), Some(crypt.clone()))
4426 .await
4427 .unwrap();
4428
4429 fs.close().await.expect("Close failed");
4430 }
4431 }
4432
4433 #[allow(dead_code)]
4444 fn find_out_of_order_sha256_long_prefix_pair(
4445 object_id: u64,
4446 key: &Arc<dyn Cipher>,
4447 ) -> Option<[String; 2]> {
4448 let mut collision_map: std::collections::HashMap<u32, (usize, ProxyFilename, Vec<u8>)> =
4449 std::collections::HashMap::new();
4450 for i in 0..(1usize << 32) {
4451 let filename = format!("{:0>176}_{i}", 0);
4452 let encrypted_name =
4453 encrypt_filename(&**key, object_id, &filename).expect("encrypt_filename");
4454 let hash_code = key.hash_code_casefold(&filename);
4455 let a = ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4456 let hash_code = a.hash_code as u32;
4457 if let Some((j, b, b_encrypted_name)) = collision_map.get(&hash_code) {
4458 assert_eq!(a.filename, b.filename);
4459 if encrypted_name.cmp(b_encrypted_name) != a.sha256.cmp(&b.sha256) {
4460 return Some([format!("{:0>176}_{i}", 0), format!("{:0>176}_{j}", 0)]);
4461 }
4462 } else {
4463 collision_map.insert(hash_code, (i, a, encrypted_name));
4464 }
4465 }
4466 None
4467 }
4468
4469 #[fuchsia::test]
4470 async fn test_proxy_filename() {
4471 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4472 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4473 let mut filenames = Vec::new();
4474 let object_id;
4475 {
4476 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4477 let root_volume = root_volume(fs.clone()).await.unwrap();
4478 let store = root_volume
4479 .new_volume(
4480 "vol",
4481 NewChildStoreOptions {
4482 options: StoreOptions {
4483 crypt: Some(crypt.clone()),
4484 ..StoreOptions::default()
4485 },
4486 ..Default::default()
4487 },
4488 )
4489 .await
4490 .unwrap();
4491
4492 crypt
4494 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4495 .expect("add wrapping key failed");
4496
4497 object_id = {
4498 let mut transaction = fs
4499 .root_store()
4500 .new_transaction(lock_keys![], Options::default())
4501 .await
4502 .expect("new_transaction failed");
4503 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4504 .await
4505 .expect("create failed");
4506
4507 transaction.commit().await.expect("commit");
4508 dir.object_id()
4509 };
4510
4511 let dir = Directory::open(&store, object_id).await.expect("open failed");
4512
4513 dir.set_casefold(true).await.expect("set casefold");
4514 assert!(dir.dir_type().is_casefold());
4515
4516 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4517
4518 let collision_pair =
4528 [format!("{:0>176}_{}", 0, 93515), format!("{:0>176}_{}", 0, 15621)];
4529
4530 for filename in (0..64)
4533 .into_iter()
4534 .map(|i| format!("{:0>176}_{i}", 0))
4535 .chain(collision_pair.into_iter())
4536 {
4537 let hash_code = key.hash_code_casefold(&filename);
4538 let encrypted_name =
4539 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
4540 let proxy_filename =
4541 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name);
4542 let mut transaction = fs
4543 .root_store()
4544 .new_transaction(
4545 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4546 Options::default(),
4547 )
4548 .await
4549 .expect("new_transaction failed");
4550 let file = dir
4551 .create_child_file(&mut transaction, &filename)
4552 .await
4553 .expect("create_child_file failed");
4554 filenames.push((proxy_filename, file.object_id()));
4555 transaction.commit().await.expect("commit failed");
4556 }
4557
4558 fs.close().await.expect("Close failed");
4559 }
4560
4561 let device = fs.take_device().await;
4562
4563 device.reopen(false);
4565 let fs = FxFilesystem::open(device).await.expect("open failed");
4566 {
4567 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4568 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4569 let store = root_volume
4570 .volume(
4571 "vol",
4572 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4573 )
4574 .await
4575 .expect("volume failed");
4576 let dir = Directory::open(&store, object_id).await.expect("open failed");
4577 assert!(dir.dir_type().is_casefold());
4578
4579 assert_eq!(
4581 filenames.iter().map(|(name, _)| (*name).into()).collect::<HashSet<String>>().len(),
4582 filenames.len()
4583 );
4584
4585 let filename = filenames[0].0.filename.clone();
4586 for (proxy_filename, object_id) in &filenames {
4587 assert_eq!(filename, proxy_filename.filename);
4589
4590 let proxy_filename_str: String = (*proxy_filename).into();
4591 let item = dir
4592 .lookup(&proxy_filename_str)
4593 .await
4594 .expect("lookup failed")
4595 .expect("lookup is not None");
4596 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4597 }
4598
4599 fs.close().await.expect("Close failed");
4600 }
4601 }
4602
4603 #[fuchsia::test]
4604 async fn test_replace_directory_and_tombstone_on_remount() {
4605 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
4606 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4607 let crypt = Arc::new(new_insecure_crypt());
4608 {
4609 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4610 let store = root_volume
4611 .new_volume(
4612 "test",
4613 NewChildStoreOptions {
4614 options: StoreOptions {
4615 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4616 ..StoreOptions::default()
4617 },
4618 ..Default::default()
4619 },
4620 )
4621 .await
4622 .expect("new_volume failed");
4623
4624 let mut transaction = fs
4625 .root_store()
4626 .new_transaction(
4627 lock_keys![LockKey::object(
4628 store.store_object_id(),
4629 store.root_directory_object_id()
4630 )],
4631 Options::default(),
4632 )
4633 .await
4634 .expect("new transaction failed");
4635
4636 let root_directory = Directory::open(&store, store.root_directory_object_id())
4637 .await
4638 .expect("open failed");
4639 let _directory = root_directory
4640 .create_child_dir(&mut transaction, "foo")
4641 .await
4642 .expect("create_child_dir failed");
4643 let directory = root_directory
4644 .create_child_dir(&mut transaction, "bar")
4645 .await
4646 .expect("create_child_dir failed");
4647 let oid = directory.object_id();
4648
4649 transaction.commit().await.expect("commit failed");
4650
4651 let mut transaction = fs
4652 .root_store()
4653 .new_transaction(
4654 lock_keys![LockKey::object(
4655 store.store_object_id(),
4656 store.root_directory_object_id()
4657 )],
4658 Options::default(),
4659 )
4660 .await
4661 .expect("new transaction failed");
4662
4663 replace_child_with_object(
4664 &mut transaction,
4665 Some((oid, ObjectDescriptor::Directory)),
4666 (&root_directory, "foo"),
4667 0,
4668 false,
4669 Timestamp::now(),
4670 )
4671 .await
4672 .expect("replace_child_with_object failed");
4673
4674 yield_to_executor().await;
4678
4679 transaction.commit().await.expect("commit failed");
4680
4681 fs.close().await.expect("close failed");
4682 }
4683
4684 let device = fs.take_device().await;
4685 device.reopen(false);
4686 let fs = FxFilesystem::open(device).await.expect("open failed");
4687 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4688 let _store = root_volume
4689 .volume(
4690 "test",
4691 StoreOptions {
4692 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4693 ..StoreOptions::default()
4694 },
4695 )
4696 .await
4697 .expect("new_volume failed");
4698
4699 yield_to_executor().await;
4701
4702 fs.close().await.expect("close failed");
4703 }
4704
4705 #[test_case(false; "non_casefold")]
4706 #[test_case(true; "casefold")]
4707 #[fuchsia::test]
4708 async fn test_lookup_long_filename_in_locked_directory(casefold: bool) {
4709 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4710 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4711 let object_id;
4712 let mut filenames = Vec::new();
4713 {
4714 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4715 let root_volume = root_volume(fs.clone()).await.unwrap();
4716 let store = root_volume
4717 .new_volume(
4718 "vol",
4719 NewChildStoreOptions {
4720 options: StoreOptions {
4721 crypt: Some(crypt.clone()),
4722 ..StoreOptions::default()
4723 },
4724 ..Default::default()
4725 },
4726 )
4727 .await
4728 .unwrap();
4729
4730 crypt
4731 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4732 .expect("add_wrapping_key failed");
4733
4734 object_id = {
4735 let mut transaction = fs
4736 .root_store()
4737 .new_transaction(lock_keys![], Options::default())
4738 .await
4739 .expect("new_transaction failed");
4740 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4741 .await
4742 .expect("create failed");
4743
4744 transaction.commit().await.expect("commit");
4745 dir.object_id()
4746 };
4747 let dir = Directory::open(&store, object_id).await.expect("open failed");
4748 if casefold {
4749 dir.set_casefold(true).await.expect("set casefold");
4750 }
4751
4752 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4753
4754 for len in [144, 145, 255] {
4755 let filename = "a".repeat(len);
4756 let encrypted_name =
4757 encrypt_filename(&*key, dir.object_id(), &filename).expect("encrypt_filename");
4758 let proxy_filename = if casefold {
4759 let hash_code = key.hash_code_casefold(&filename);
4760 ProxyFilename::new_with_hash_code(hash_code as u64, &encrypted_name)
4761 } else {
4762 ProxyFilename::new(&encrypted_name)
4763 };
4764 let mut transaction = fs
4765 .root_store()
4766 .new_transaction(
4767 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4768 Options::default(),
4769 )
4770 .await
4771 .expect("new_transaction failed");
4772 let file = dir
4773 .create_child_file(&mut transaction, &filename)
4774 .await
4775 .expect("create_child_file failed");
4776 filenames.push((proxy_filename, file.object_id()));
4777 transaction.commit().await.expect("commit failed");
4778 }
4779
4780 fs.close().await.expect("Close failed");
4781 }
4782
4783 let device = fs.take_device().await;
4784 device.reopen(false);
4785 let fs = FxFilesystem::open(device).await.expect("open failed");
4786 {
4787 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4788 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4789 let store = root_volume
4790 .volume(
4791 "vol",
4792 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4793 )
4794 .await
4795 .expect("volume failed");
4796 let dir = Directory::open(&store, object_id).await.expect("open failed");
4797
4798 let layer_set = dir.store().tree().layer_set();
4800 let mut merger = layer_set.merger();
4801 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
4802 let mut entries = Vec::new();
4803 while let Some((name, _, _)) = iter.get() {
4804 entries.push(name.to_string());
4805 iter.advance().await.expect("advance failed");
4806 }
4807 assert_eq!(entries.len(), filenames.len());
4808
4809 for (proxy_filename, object_id) in &filenames {
4810 let proxy_filename_str: String = (*proxy_filename).into();
4811 assert!(entries.contains(&proxy_filename_str));
4812 let item = dir
4813 .lookup(&proxy_filename_str)
4814 .await
4815 .expect("lookup failed")
4816 .expect("lookup is not None");
4817 assert_eq!(item.0, *object_id, "Mismatch for filename '{proxy_filename:?}'");
4818 }
4819
4820 fs.close().await.expect("Close failed");
4821 }
4822 }
4823
4824 #[fuchsia::test]
4825 async fn test_lookup_cached_entry_after_unlock() {
4826 const FILENAME: &str = "foo";
4827 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4828 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4829 let object_id;
4830 let proxy_filename;
4831 {
4832 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4833 let root_volume = root_volume(fs.clone()).await.unwrap();
4834 let store = root_volume
4835 .new_volume(
4836 "vol",
4837 NewChildStoreOptions {
4838 options: StoreOptions {
4839 crypt: Some(crypt.clone()),
4840 ..StoreOptions::default()
4841 },
4842 ..Default::default()
4843 },
4844 )
4845 .await
4846 .unwrap();
4847
4848 crypt
4849 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4850 .expect("add_wrapping_key failed");
4851
4852 let mut transaction = fs
4853 .root_store()
4854 .new_transaction(lock_keys![], Options::default())
4855 .await
4856 .expect("new_transaction failed");
4857 let dir = Directory::create(&mut transaction, &store, Some(WRAPPING_KEY_ID))
4858 .await
4859 .expect("create failed");
4860 transaction.commit().await.expect("commit");
4861 object_id = dir.object_id();
4862
4863 let key = dir.get_fscrypt_key().await.expect("key").into_cipher().unwrap();
4864 let encrypted_name =
4865 encrypt_filename(&*key, object_id, FILENAME).expect("encrypt_filename");
4866 proxy_filename = ProxyFilename::new(&encrypted_name);
4867
4868 let mut transaction = fs
4869 .root_store()
4870 .new_transaction(
4871 lock_keys![LockKey::object(store.store_object_id(), object_id),],
4872 Options::default(),
4873 )
4874 .await
4875 .expect("new_transaction failed");
4876 dir.create_child_file(&mut transaction, FILENAME)
4877 .await
4878 .expect("create_child_file failed");
4879 transaction.commit().await.expect("commit failed");
4880
4881 fs.close().await.expect("Close failed");
4882 }
4883
4884 let device = fs.take_device().await;
4885 device.reopen(false);
4886 let fs = FxFilesystem::open(device).await.expect("open failed");
4887 {
4888 let crypt: Arc<CryptBase> = Arc::new(new_insecure_crypt());
4889 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4890 let store = root_volume
4891 .volume(
4892 "vol",
4893 StoreOptions { crypt: Some(crypt.clone()), ..StoreOptions::default() },
4894 )
4895 .await
4896 .expect("volume failed");
4897 let dir = Directory::open(&store, object_id).await.expect("open failed");
4898
4899 let proxy_filename_str: String = proxy_filename.into();
4900 dir.lookup(&proxy_filename_str)
4902 .await
4903 .expect("lookup failed")
4904 .expect("lookup is not None");
4905
4906 crypt
4907 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4908 .expect("add_wrapping_key failed");
4909
4910 assert!(dir.lookup(&proxy_filename_str).await.expect("lookup failed").is_none());
4913
4914 fs.close().await.expect("Close failed");
4915 }
4916 }
4917
4918 #[test_case(false, false; "no_encryption_no_casefold")]
4919 #[test_case(false, true; "no_encryption_casefold")]
4920 #[test_case(true, false; "encryption_no_casefold")]
4921 #[test_case(true, true; "encryption_casefold")]
4922 #[fuchsia::test]
4923 async fn test_traversal_position(encrypted: bool, casefold: bool) {
4924 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
4925 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
4926 {
4927 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4928 let crypt = Arc::new(new_insecure_crypt());
4929 crypt
4930 .add_wrapping_key(WRAPPING_KEY_ID, [1; 32].into())
4931 .expect("add_wrapping_key failed");
4932 let store = root_volume
4933 .new_volume(
4934 "test",
4935 NewChildStoreOptions {
4936 options: StoreOptions {
4937 crypt: Some(crypt.clone() as Arc<dyn Crypt>),
4938 ..StoreOptions::default()
4939 },
4940 ..Default::default()
4941 },
4942 )
4943 .await
4944 .expect("new_volume failed");
4945 let mut root_dir = Directory::open(&store, store.root_directory_object_id())
4946 .await
4947 .expect("open failed");
4948 if encrypted {
4949 let mut transaction = fs
4950 .root_store()
4951 .new_transaction(
4952 lock_keys![LockKey::object(
4953 store.store_object_id(),
4954 store.root_directory_object_id()
4955 )],
4956 Options::default(),
4957 )
4958 .await
4959 .expect("new_transaction failed");
4960 root_dir.set_wrapping_key(&mut transaction, WRAPPING_KEY_ID).await.unwrap();
4961 transaction.commit().await.unwrap();
4962
4963 root_dir = Directory::open(&store, store.root_directory_object_id())
4965 .await
4966 .expect("open failed");
4967 }
4968 if casefold {
4969 root_dir.set_casefold(true).await.unwrap();
4970 }
4971
4972 let mut transaction = fs
4973 .root_store()
4974 .new_transaction(
4975 lock_keys![LockKey::object(
4976 store.store_object_id(),
4977 store.root_directory_object_id()
4978 )],
4979 Options::default(),
4980 )
4981 .await
4982 .expect("new_transaction failed");
4983 let _ = root_dir.create_child_file(&mut transaction, "foo").await.unwrap();
4984 transaction.commit().await.unwrap();
4985
4986 let layer_set = store.tree().layer_set();
4987 let mut merger = layer_set.merger();
4988 let iter = root_dir.iter(&mut merger).await.expect("iter failed");
4989 let pos =
4990 iter.traversal_position(|name| name.to_string(), |bytes| format!("{:?}", bytes));
4991 assert!(
4992 pos.is_some(),
4993 "traversal_position returned None for encrypted={}, casefold={}",
4994 encrypted,
4995 casefold
4996 );
4997 }
4998 fs.close().await.expect("close failed");
4999 }
5000
5001 #[fuchsia::test]
5004 async fn test_casefold_same_dir_rename() -> Result<(), Error> {
5005 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5006 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5007
5008 let root_volume = root_volume(fs.clone()).await.unwrap();
5009 let store = root_volume.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
5010
5011 let dir = {
5012 let mut transaction = fs
5013 .root_store()
5014 .new_transaction(lock_keys![], Options::default())
5015 .await
5016 .expect("new_transaction failed");
5017 let dir =
5018 Directory::create(&mut transaction, &store, None).await.expect("create failed");
5019 transaction.commit().await.expect("commit");
5020 dir
5021 };
5022
5023 dir.set_casefold(true).await.expect("set casefold");
5025
5026 let file_id = {
5028 let mut transaction = fs
5029 .root_store()
5030 .new_transaction(
5031 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
5032 Options::default(),
5033 )
5034 .await
5035 .expect("new_transaction failed");
5036 let file =
5037 dir.create_child_file(&mut transaction, "FOO").await.expect("create file failed");
5038 transaction.commit().await.expect("commit failed");
5039 file.object_id()
5040 };
5041
5042 let (lookup_id_foo, _, _) = dir.lookup("foo").await.unwrap().unwrap();
5044 assert_eq!(lookup_id_foo, file_id);
5045 let (lookup_id_foo_upper, _, _) = dir.lookup("FOO").await.unwrap().unwrap();
5046 assert_eq!(lookup_id_foo_upper, file_id);
5047
5048 {
5050 let mut transaction = fs
5051 .root_store()
5052 .new_transaction(
5053 lock_keys![
5054 LockKey::object(store.store_object_id(), dir.object_id()),
5055 LockKey::object(store.store_object_id(), file_id),
5056 ],
5057 Options::default(),
5058 )
5059 .await
5060 .expect("new_transaction failed");
5061
5062 replace_child(&mut transaction, Some((&dir, "FOO")), (&dir, "foo"))
5063 .await
5064 .expect("same-dir casefold rename failed");
5065
5066 transaction.commit().await.expect("commit failed");
5067 }
5068
5069 let (final_id_foo, _, _) = dir.lookup("foo").await.unwrap().unwrap();
5071 assert_eq!(final_id_foo, file_id);
5072
5073 let file_handle =
5075 ObjectStore::open_object(&dir.owner(), file_id, HandleOptions::default(), None)
5076 .await
5077 .expect("Underlying file object was prematurely tombstoned / graveyarded!");
5078
5079 let properties = file_handle.get_properties().await.unwrap();
5081 assert_eq!(properties.refs, 1);
5082
5083 assert_eq!(dir.store().graveyard_count(), 0);
5085
5086 let mut count = 0;
5088 let mut found_casing = String::new();
5089 let layer_set = dir.store().tree().layer_set();
5090 let mut merger = layer_set.merger();
5091 let mut iter = dir.iter(&mut merger).await.expect("iter");
5092 while let Some(entry) = iter.get() {
5093 count += 1;
5094 found_casing = entry.0.to_string();
5095 iter.advance().await.expect("advance");
5096 }
5097 assert_eq!(count, 1);
5098 assert_eq!(found_casing, "foo"); fs.close().await.expect("Close failed");
5101 Ok(())
5102 }
5103
5104 #[fuchsia::test]
5105 async fn test_casefold_rename_mismatched_casing() -> Result<(), Error> {
5106 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
5107 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
5108
5109 let root_volume = root_volume(fs.clone()).await.unwrap();
5110 let store = root_volume.new_volume("vol", NewChildStoreOptions::default()).await.unwrap();
5111
5112 let dir = {
5113 let mut transaction = fs
5114 .root_store()
5115 .new_transaction(lock_keys![], Options::default())
5116 .await
5117 .expect("new_transaction failed");
5118 let dir =
5119 Directory::create(&mut transaction, &store, None).await.expect("create failed");
5120 transaction.commit().await.expect("commit");
5121 dir
5122 };
5123
5124 dir.set_casefold(true).await.expect("set casefold");
5125
5126 let file_id = {
5128 let mut transaction = fs
5129 .root_store()
5130 .new_transaction(
5131 lock_keys![LockKey::object(store.store_object_id(), dir.object_id())],
5132 Options::default(),
5133 )
5134 .await
5135 .expect("new_transaction failed");
5136 let file =
5137 dir.create_child_file(&mut transaction, "foo").await.expect("create file failed");
5138 transaction.commit().await.expect("commit failed");
5139 file.object_id()
5140 };
5141
5142 {
5144 let mut transaction = fs
5145 .root_store()
5146 .new_transaction(
5147 lock_keys![
5148 LockKey::object(store.store_object_id(), dir.object_id()),
5149 LockKey::object(store.store_object_id(), file_id),
5150 ],
5151 Options::default(),
5152 )
5153 .await
5154 .expect("new_transaction failed");
5155
5156 replace_child(&mut transaction, Some((&dir, "FOO")), (&dir, "bar"))
5157 .await
5158 .expect("rename failed");
5159
5160 transaction.commit().await.expect("commit failed");
5161 }
5162
5163 let lookup_foo = dir.lookup("foo").await.unwrap();
5165 assert!(
5166 lookup_foo.is_none(),
5167 "Old name 'foo' still exists! Lookup returned: {:?}",
5168 lookup_foo
5169 );
5170
5171 let (lookup_id_bar, _, _) = dir.lookup("bar").await.unwrap().expect("bar not found");
5173 assert_eq!(lookup_id_bar, file_id);
5174
5175 fs.close().await.expect("Close failed");
5176 Ok(())
5177 }
5178}