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