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