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