1use crate::errors::FxfsError;
6use crate::lsm_tree::merge::{Merger, MergerIterator};
7use crate::lsm_tree::types::{Item, ItemRef, LayerIterator};
8use crate::lsm_tree::Query;
9use crate::object_handle::{ObjectHandle, ObjectProperties, INVALID_OBJECT_ID};
10use crate::object_store::object_record::{
11 ChildValue, ObjectAttributes, ObjectDescriptor, ObjectItem, ObjectKey, ObjectKeyData,
12 ObjectKind, ObjectValue, Timestamp,
13};
14use crate::object_store::transaction::{
15 lock_keys, LockKey, LockKeys, Mutation, Options, Transaction,
16};
17use crate::object_store::{
18 DataObjectHandle, EncryptionKeys, HandleOptions, HandleOwner, ObjectStore,
19 SetExtendedAttributeMode, StoreObjectHandle,
20};
21use anyhow::{anyhow, bail, ensure, Context, Error};
22use base64::engine::general_purpose::URL_SAFE_NO_PAD as BASE64_URL_SAFE_NO_PAD;
23use base64::engine::Engine as _;
24use byteorder::{ByteOrder, LittleEndian};
25use fidl_fuchsia_io as fio;
26use fuchsia_sync::Mutex;
27use fxfs_crypto::{Cipher, CipherSet, Key, WrappedKeys};
28use std::fmt;
29use std::hash::{Hash, Hasher};
30use std::sync::atomic::{AtomicBool, Ordering};
31use std::sync::Arc;
32use zerocopy::IntoBytes;
33
34use super::FSCRYPT_KEY_ID;
35
36pub struct ReplaceContext<'a> {
39 pub transaction: Transaction<'a>,
40 pub src_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
41 pub dst_id_and_descriptor: Option<(u64, ObjectDescriptor)>,
42}
43
44pub struct Directory<S: HandleOwner> {
46 handle: StoreObjectHandle<S>,
47 is_deleted: AtomicBool,
49 casefold: AtomicBool,
51 wrapping_key_id: Mutex<Option<u128>>,
52}
53
54#[derive(Clone, Default)]
55pub struct MutableAttributesInternal {
56 sub_dirs: i64,
57 change_time: Option<Timestamp>,
58 modification_time: Option<u64>,
59 creation_time: Option<u64>,
60}
61
62impl MutableAttributesInternal {
63 pub fn new(
64 sub_dirs: i64,
65 change_time: Option<Timestamp>,
66 modification_time: Option<u64>,
67 creation_time: Option<u64>,
68 ) -> Self {
69 Self { sub_dirs, change_time, modification_time, creation_time }
70 }
71}
72
73fn get_casefold_hash(key: Option<&Key>, name: &str, casefold: bool) -> u32 {
86 if name == "" {
88 return 0;
89 }
90 let mut hasher = rustc_hash::FxHasher::default();
91 if casefold {
92 for ch in fxfs_unicode::casefold(name.chars()) {
93 ch.hash(&mut hasher);
94 }
95 } else {
96 name.hash(&mut hasher);
97 }
98 let mut hash = hasher.finish() as u32;
99 if let Some(key) = key {
100 key.encrypt(0, hash.as_mut_bytes()).unwrap();
101 }
102 hash
103}
104
105fn encrypt_filename(key: &Key, object_id: u64, name: &str) -> Result<Vec<u8>, Error> {
107 let mut name_bytes = name.to_string().into_bytes();
108 key.encrypt_filename(object_id, &mut name_bytes)?;
109 Ok(name_bytes)
110}
111
112fn decrypt_filename(key: &Key, object_id: u64, data: &Vec<u8>) -> Result<String, Error> {
114 let mut raw = data.clone();
115 key.decrypt_filename(object_id, &mut raw)?;
116 Ok(String::from_utf8(raw)?)
117}
118
119#[derive(Debug, Eq, PartialEq, Ord, PartialOrd)]
129struct SyntheticFilename {
130 casefold_hash: u32,
131 raw_prefix: Vec<u8>,
132 pub raw_hash: u64,
133}
134
135impl SyntheticFilename {
136 fn raw_filename_to_raw_hash(raw: &Vec<u8>) -> u64 {
140 let mut hasher = rustc_hash::FxHasher::default();
141 raw.hash(&mut hasher);
142 hasher.finish()
143 }
144
145 pub fn decode(synthetic_filename: &str) -> Self {
147 let mut data =
151 BASE64_URL_SAFE_NO_PAD.decode(synthetic_filename).unwrap_or_else(|_| vec![0u8; 12]);
152 if data.len() < 12 {
153 data.resize(12, 0);
154 }
155 let casefold_hash = LittleEndian::read_u32(&data[0..4]);
156 let raw_hash = LittleEndian::read_u64(&data[4..12]);
157 let raw_prefix = data[12..].to_vec();
158 Self { casefold_hash, raw_prefix, raw_hash }
159 }
160
161 pub fn encode(&self) -> String {
163 let mut data = [0u8; 60];
164 LittleEndian::write_u32(&mut data[0..4], self.casefold_hash);
165 LittleEndian::write_u64(&mut data[4..12], self.raw_hash);
166 let len = std::cmp::min(self.raw_prefix.len(), 48);
167 data[12..12 + len].copy_from_slice(&self.raw_prefix);
168 BASE64_URL_SAFE_NO_PAD.encode(&data[..12 + len])
169 }
170
171 pub fn from_object_key(casefold_hash: u32, raw: &Vec<u8>) -> Self {
173 let raw_hash = Self::raw_filename_to_raw_hash(raw);
174 let mut raw_prefix = raw.clone();
175 raw_prefix.truncate(48);
176 Self { casefold_hash, raw_prefix, raw_hash }
177 }
178
179 pub fn to_query_key(&self, object_id: u64) -> ObjectKey {
185 ObjectKey::encrypted_child(object_id, self.raw_prefix.clone(), self.casefold_hash)
186 }
187}
188
189#[fxfs_trace::trace]
190impl<S: HandleOwner> Directory<S> {
191 fn new(owner: Arc<S>, object_id: u64, wrapping_key_id: Option<u128>, casefold: bool) -> Self {
192 Directory {
193 handle: StoreObjectHandle::new(
194 owner,
195 object_id,
196 false,
197 HandleOptions::default(),
198 false,
199 ),
200 is_deleted: AtomicBool::new(false),
201 casefold: AtomicBool::new(casefold),
202 wrapping_key_id: Mutex::new(wrapping_key_id),
203 }
204 }
205
206 pub fn object_id(&self) -> u64 {
207 self.handle.object_id()
208 }
209
210 pub fn wrapping_key_id(&self) -> Option<u128> {
211 self.wrapping_key_id.lock().clone()
212 }
213
214 pub async fn get_fscrypt_key(&self) -> Result<Option<Key>, Error> {
218 let object_id = self.object_id();
219 let store = self.store();
220 store
221 .key_manager()
222 .get_fscrypt_key(object_id, store.crypt().unwrap().as_ref(), async || {
223 store.get_keys(object_id).await
224 })
225 .await
226 }
227
228 pub fn owner(&self) -> &Arc<S> {
229 self.handle.owner()
230 }
231
232 pub fn store(&self) -> &ObjectStore {
233 self.handle.store()
234 }
235
236 pub fn handle(&self) -> &StoreObjectHandle<S> {
237 &self.handle
238 }
239
240 pub fn is_deleted(&self) -> bool {
241 self.is_deleted.load(Ordering::Relaxed)
242 }
243
244 pub fn set_deleted(&self) {
245 self.is_deleted.store(true, Ordering::Relaxed);
246 }
247
248 pub fn casefold(&self) -> bool {
250 self.casefold.load(Ordering::Relaxed)
251 }
252
253 pub async fn set_casefold(&self, val: bool) -> Result<(), Error> {
255 let fs = self.store().filesystem();
256 let mut transaction = fs
258 .new_transaction(
259 lock_keys![LockKey::object(self.store().store_object_id(), self.object_id())],
260 Options::default(),
261 )
262 .await?;
263 ensure!(!self.has_children().await?, FxfsError::InvalidArgs);
264 let mut mutation =
265 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
266 if let ObjectValue::Object { kind: ObjectKind::Directory { casefold, .. }, .. } =
267 &mut mutation.item.value
268 {
269 *casefold = val;
270 } else {
271 return Err(
272 anyhow!(FxfsError::Inconsistent).context("casefold only applies to directories")
273 );
274 }
275 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
276 transaction.commit_with_callback(|_| self.casefold.store(val, Ordering::Relaxed)).await?;
277 Ok(())
278 }
279
280 pub async fn create(
281 transaction: &mut Transaction<'_>,
282 owner: &Arc<S>,
283 wrapping_key_id: Option<u128>,
284 ) -> Result<Directory<S>, Error> {
285 Self::create_with_options(transaction, owner, wrapping_key_id, false).await
286 }
287
288 pub async fn create_with_options(
289 transaction: &mut Transaction<'_>,
290 owner: &Arc<S>,
291 wrapping_key_id: Option<u128>,
292 casefold: bool,
293 ) -> Result<Directory<S>, Error> {
294 let store = owner.as_ref().as_ref();
295 let object_id = store.get_next_object_id(transaction.txn_guard()).await?;
296 let now = Timestamp::now();
297 transaction.add(
298 store.store_object_id(),
299 Mutation::insert_object(
300 ObjectKey::object(object_id),
301 ObjectValue::Object {
302 kind: ObjectKind::Directory { sub_dirs: 0, casefold, wrapping_key_id },
303 attributes: ObjectAttributes {
304 creation_time: now.clone(),
305 modification_time: now.clone(),
306 project_id: 0,
307 posix_attributes: None,
308 allocated_size: 0,
309 access_time: now.clone(),
310 change_time: now,
311 },
312 },
313 ),
314 );
315 if let Some(wrapping_key_id) = &wrapping_key_id {
316 if let Some(crypt) = store.crypt() {
317 let (key, unwrapped_key) =
318 crypt.create_key_with_id(object_id, *wrapping_key_id).await?;
319 transaction.add(
320 store.store_object_id(),
321 Mutation::insert_object(
322 ObjectKey::keys(object_id),
323 ObjectValue::keys(EncryptionKeys::AES256XTS(WrappedKeys::from(vec![(
324 FSCRYPT_KEY_ID,
325 key,
326 )]))),
327 ),
328 );
329 store.key_manager.insert(
334 object_id,
335 &vec![(FSCRYPT_KEY_ID, Some(unwrapped_key))],
336 false,
337 );
338 } else {
339 return Err(anyhow!("No crypt"));
340 }
341 }
342 Ok(Directory::new(owner.clone(), object_id, wrapping_key_id, casefold))
343 }
344
345 pub async fn set_wrapping_key(
346 &self,
347 transaction: &mut Transaction<'_>,
348 id: u128,
349 ) -> Result<Cipher, Error> {
350 let object_id = self.object_id();
351 let store = self.store();
352 if let Some(crypt) = store.crypt() {
353 let (key, unwrapped_key) = crypt.create_key_with_id(object_id, id).await?;
354 match store
355 .tree
356 .find(&ObjectKey::object(object_id))
357 .await?
358 .ok_or(FxfsError::NotFound)?
359 {
360 ObjectItem {
361 value:
362 ObjectValue::Object {
363 kind: ObjectKind::Directory { sub_dirs, wrapping_key_id, casefold },
364 attributes,
365 },
366 ..
367 } => {
368 if wrapping_key_id.is_some() {
369 return Err(anyhow!("wrapping key id is already set"));
370 }
371 if self.has_children().await? {
372 return Err(FxfsError::NotEmpty.into());
373 }
374 transaction.add(
375 store.store_object_id(),
376 Mutation::replace_or_insert_object(
377 ObjectKey::object(self.object_id()),
378 ObjectValue::Object {
379 kind: ObjectKind::Directory {
380 sub_dirs,
381 wrapping_key_id: Some(id),
382 casefold,
383 },
384 attributes,
385 },
386 ),
387 );
388 }
389 ObjectItem { value: ObjectValue::None, .. } => bail!(FxfsError::NotFound),
390 _ => bail!(FxfsError::NotDir),
391 }
392
393 match store.tree.find(&ObjectKey::keys(object_id)).await? {
394 None => {
395 transaction.add(
396 store.store_object_id(),
397 Mutation::insert_object(
398 ObjectKey::keys(object_id),
399 ObjectValue::keys(EncryptionKeys::AES256XTS(WrappedKeys::from(vec![
400 (FSCRYPT_KEY_ID, key),
401 ]))),
402 ),
403 );
404 }
405 Some(Item {
406 value: ObjectValue::Keys(EncryptionKeys::AES256XTS(mut keys)),
407 ..
408 }) => {
409 keys.push((FSCRYPT_KEY_ID, key));
410 transaction.add(
411 store.store_object_id(),
412 Mutation::replace_or_insert_object(
413 ObjectKey::keys(object_id),
414 ObjectValue::keys(EncryptionKeys::AES256XTS(keys)),
415 ),
416 );
417 }
418 Some(item) => bail!("Unexpected item in lookup: {item:?}"),
419 }
420 Ok(Cipher::new(FSCRYPT_KEY_ID, &unwrapped_key))
421 } else {
422 Err(anyhow!("No crypt"))
423 }
424 }
425
426 #[trace]
427 pub async fn open(owner: &Arc<S>, object_id: u64) -> Result<Directory<S>, Error> {
428 let store = owner.as_ref().as_ref();
429 match store.tree.find(&ObjectKey::object(object_id)).await?.ok_or(FxfsError::NotFound)? {
430 ObjectItem {
431 value:
432 ObjectValue::Object {
433 kind: ObjectKind::Directory { wrapping_key_id, casefold, .. },
434 ..
435 },
436 ..
437 } => Ok(Directory::new(owner.clone(), object_id, wrapping_key_id, casefold)),
438 _ => bail!(FxfsError::NotDir),
439 }
440 }
441
442 pub fn open_unchecked(
445 owner: Arc<S>,
446 object_id: u64,
447 wrapping_key_id: Option<u128>,
448 casefold: bool,
449 ) -> Self {
450 Self::new(owner, object_id, wrapping_key_id, casefold)
451 }
452
453 pub async fn acquire_context_for_replace(
466 &self,
467 src: Option<(&Directory<S>, &str)>,
468 dst: &str,
469 borrow_metadata_space: bool,
470 ) -> Result<ReplaceContext<'_>, Error> {
471 let store = self.store();
482 let mut child_object_id = INVALID_OBJECT_ID;
483 let mut src_object_id = src.map(|_| INVALID_OBJECT_ID);
484 let mut lock_keys = LockKeys::with_capacity(4);
485 lock_keys.push(LockKey::object(store.store_object_id(), self.object_id()));
486 loop {
487 lock_keys.truncate(1);
488 if let Some(src) = src {
489 lock_keys.push(LockKey::object(store.store_object_id(), src.0.object_id()));
490 if let Some(src_object_id) = src_object_id {
491 if src_object_id != INVALID_OBJECT_ID {
492 lock_keys.push(LockKey::object(store.store_object_id(), src_object_id));
493 }
494 }
495 }
496 if child_object_id != INVALID_OBJECT_ID {
497 lock_keys.push(LockKey::object(store.store_object_id(), child_object_id));
498 };
499 let fs = store.filesystem().clone();
500 let transaction = fs
501 .new_transaction(
502 lock_keys.clone(),
503 Options { borrow_metadata_space, ..Default::default() },
504 )
505 .await?;
506
507 let mut have_required_locks = true;
508 let mut src_id_and_descriptor = None;
509 if let Some((src_dir, src_name)) = src {
510 match src_dir.lookup(src_name).await? {
511 Some((object_id, object_descriptor)) => match object_descriptor {
512 ObjectDescriptor::File
513 | ObjectDescriptor::Directory
514 | ObjectDescriptor::Symlink => {
515 if src_object_id != Some(object_id) {
516 have_required_locks = false;
517 src_object_id = Some(object_id);
518 }
519 src_id_and_descriptor = Some((object_id, object_descriptor));
520 }
521 _ => bail!(FxfsError::Inconsistent),
522 },
523 None => {
524 bail!(FxfsError::NotFound)
526 }
527 }
528 };
529 let dst_id_and_descriptor = match self.lookup(dst).await? {
530 Some((object_id, object_descriptor)) => match object_descriptor {
531 ObjectDescriptor::File
532 | ObjectDescriptor::Directory
533 | ObjectDescriptor::Symlink => {
534 if child_object_id != object_id {
535 have_required_locks = false;
536 child_object_id = object_id
537 }
538 Some((object_id, object_descriptor))
539 }
540 _ => bail!(FxfsError::Inconsistent),
541 },
542 None => {
543 if child_object_id != INVALID_OBJECT_ID {
544 have_required_locks = false;
545 child_object_id = INVALID_OBJECT_ID;
546 }
547 None
548 }
549 };
550 if have_required_locks {
551 return Ok(ReplaceContext {
552 transaction,
553 src_id_and_descriptor,
554 dst_id_and_descriptor,
555 });
556 }
557 }
558 }
559
560 async fn has_children(&self) -> Result<bool, Error> {
561 if self.is_deleted() {
562 return Ok(false);
563 }
564 let layer_set = self.store().tree().layer_set();
565 let mut merger = layer_set.merger();
566 Ok(self.iter(&mut merger).await?.get().is_some())
567 }
568
569 #[trace]
571 pub async fn lookup(&self, name: &str) -> Result<Option<(u64, ObjectDescriptor)>, Error> {
572 if self.is_deleted() {
573 return Ok(None);
574 }
575 let res = if self.wrapping_key_id.lock().is_some() {
576 if let Some(fscrypt_key) = self.get_fscrypt_key().await? {
577 let target_casefold_hash =
578 get_casefold_hash(Some(&fscrypt_key), name, self.casefold());
579 if !self.casefold() {
580 let encrypted_name = encrypt_filename(&fscrypt_key, self.object_id(), name)?;
581 self.store()
582 .tree()
583 .find(&ObjectKey::encrypted_child(
584 self.object_id(),
585 encrypted_name,
586 target_casefold_hash,
587 ))
588 .await?
589 } else {
590 let key =
591 ObjectKey::encrypted_child(self.object_id(), vec![], target_casefold_hash);
592 let layer_set = self.store().tree().layer_set();
593 let mut merger = layer_set.merger();
594 let mut iter = merger.query(Query::FullRange(&key)).await?;
595 loop {
596 match iter.get() {
597 Some(ItemRef { value: ObjectValue::None, .. }) => {}
599 Some(ItemRef {
600 key:
601 key @ ObjectKey {
602 object_id,
603 data:
604 ObjectKeyData::EncryptedChild {
605 casefold_hash,
606 name: encrypted_name,
607 },
608 },
609 value,
610 sequence,
611 }) if *object_id == self.object_id()
612 && *casefold_hash == target_casefold_hash =>
613 {
614 let decrypted_name = decrypt_filename(
615 &fscrypt_key,
616 self.object_id(),
617 encrypted_name,
618 )?;
619 if fxfs_unicode::casefold_cmp(name, &decrypted_name)
620 == std::cmp::Ordering::Equal
621 {
622 break Some(Item {
623 key: key.clone(),
624 value: value.clone(),
625 sequence,
626 });
627 }
628 }
629 _ => break None,
630 }
631 iter.advance().await?;
632 }
633 }
634 } else {
635 let target_filename = SyntheticFilename::decode(name);
636 let query_key = target_filename.to_query_key(self.object_id());
637 let layer_set = self.store().tree().layer_set();
638 let mut merger = layer_set.merger();
639 let mut iter = merger.query(Query::FullRange(&query_key)).await?;
640 loop {
641 match iter.get() {
642 Some(ItemRef { value: ObjectValue::None, .. }) => {}
644 Some(ItemRef {
645 key:
646 key @ ObjectKey {
647 object_id,
648 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
649 },
650 value,
651 sequence,
652 }) if *object_id == self.object_id()
653 && *casefold_hash == target_filename.casefold_hash =>
654 {
655 let filename = SyntheticFilename::from_object_key(*casefold_hash, name);
656 if filename == target_filename {
657 break Some(Item {
658 key: key.clone(),
659 value: value.clone(),
660 sequence,
661 });
662 }
663 }
664 _ => break None,
665 }
666 iter.advance().await?;
667 }
668 }
669 } else {
670 self.store()
671 .tree()
672 .find(&ObjectKey::child(self.object_id(), name, self.casefold()))
673 .await?
674 };
675 match res {
676 None | Some(ObjectItem { value: ObjectValue::None, .. }) => Ok(None),
677 Some(ObjectItem {
678 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
679 ..
680 }) => Ok(Some((object_id, object_descriptor))),
681 Some(item) => Err(anyhow!(FxfsError::Inconsistent)
682 .context(format!("Unexpected item in lookup: {:?}", item))),
683 }
684 }
685
686 pub async fn create_child_dir(
687 &self,
688 transaction: &mut Transaction<'_>,
689 name: &str,
690 ) -> Result<Directory<S>, Error> {
691 ensure!(!self.is_deleted(), FxfsError::Deleted);
692
693 let handle = Directory::create_with_options(
694 transaction,
695 self.owner(),
696 self.wrapping_key_id(),
697 self.casefold(),
698 )
699 .await?;
700 if self.wrapping_key_id.lock().is_some() {
701 let key = if let Some(key) = self.get_fscrypt_key().await? {
702 key
703 } else {
704 bail!(FxfsError::NoKey);
705 };
706 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
707 let encrypted_name =
708 encrypt_filename(&key, self.object_id(), name).expect("encrypt_filename");
709 transaction.add(
710 self.store().store_object_id(),
711 Mutation::replace_or_insert_object(
712 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
713 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
714 ),
715 );
716 } else {
717 transaction.add(
718 self.store().store_object_id(),
719 Mutation::replace_or_insert_object(
720 ObjectKey::child(self.object_id(), &name, self.casefold()),
721 ObjectValue::child(handle.object_id(), ObjectDescriptor::Directory),
722 ),
723 );
724 }
725 let now = Timestamp::now();
726 self.update_dir_attributes_internal(
727 transaction,
728 self.object_id(),
729 MutableAttributesInternal {
730 sub_dirs: 1,
731 modification_time: Some(now.as_nanos()),
732 change_time: Some(now),
733 ..Default::default()
734 },
735 )
736 .await?;
737 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
738 Ok(handle)
739 }
740
741 pub async fn add_child_file<'a>(
742 &self,
743 transaction: &mut Transaction<'a>,
744 name: &str,
745 handle: &DataObjectHandle<S>,
746 ) -> Result<(), Error> {
747 ensure!(!self.is_deleted(), FxfsError::Deleted);
748 if self.wrapping_key_id.lock().is_some() {
749 let key = if let Some(key) = self.get_fscrypt_key().await? {
750 key
751 } else {
752 bail!(FxfsError::NoKey);
753 };
754 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
755 let encrypted_name =
756 encrypt_filename(&key, self.object_id(), name).expect("encrypt_filename");
757 transaction.add(
758 self.store().store_object_id(),
759 Mutation::replace_or_insert_object(
760 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
761 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
762 ),
763 );
764 } else {
765 transaction.add(
766 self.store().store_object_id(),
767 Mutation::replace_or_insert_object(
768 ObjectKey::child(self.object_id(), &name, self.casefold()),
769 ObjectValue::child(handle.object_id(), ObjectDescriptor::File),
770 ),
771 );
772 }
773 let now = Timestamp::now();
774 self.update_dir_attributes_internal(
775 transaction,
776 self.object_id(),
777 MutableAttributesInternal {
778 modification_time: Some(now.as_nanos()),
779 change_time: Some(now),
780 ..Default::default()
781 },
782 )
783 .await
784 }
785
786 fn copy_project_id_to_object_in_txn<'a>(
791 &self,
792 transaction: &mut Transaction<'a>,
793 object_id: u64,
794 ) -> Result<(), Error> {
795 let store_id = self.store().store_object_id();
796 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } =
798 transaction
799 .get_object_mutation(store_id, ObjectKey::object(self.object_id()))
800 .unwrap()
801 .item
802 .value
803 else {
804 return Err(anyhow!(FxfsError::Inconsistent));
805 };
806 if project_id > 0 {
807 let mut mutation = transaction
810 .get_object_mutation(store_id, ObjectKey::object(object_id))
811 .unwrap()
812 .clone();
813 if let ObjectValue::Object {
814 attributes: ObjectAttributes { project_id: child_project_id, .. },
815 ..
816 } = &mut mutation.item.value
817 {
818 *child_project_id = project_id;
819 } else {
820 return Err(anyhow!(FxfsError::Inconsistent));
821 }
822 transaction.add(store_id, Mutation::ObjectStore(mutation));
823 transaction.add(
824 store_id,
825 Mutation::merge_object(
826 ObjectKey::project_usage(self.store().root_directory_object_id(), project_id),
827 ObjectValue::BytesAndNodes { bytes: 0, nodes: 1 },
828 ),
829 );
830 }
831 Ok(())
832 }
833
834 pub async fn create_child_file<'a>(
835 &self,
836 transaction: &mut Transaction<'a>,
837 name: &str,
838 ) -> Result<DataObjectHandle<S>, Error> {
839 self.create_child_file_with_options(transaction, name, HandleOptions::default()).await
840 }
841
842 pub async fn create_child_file_with_options<'a>(
843 &self,
844 transaction: &mut Transaction<'a>,
845 name: &str,
846 options: HandleOptions,
847 ) -> Result<DataObjectHandle<S>, Error> {
848 ensure!(!self.is_deleted(), FxfsError::Deleted);
849 let wrapping_key_id = self.wrapping_key_id.lock().clone();
850 let handle =
851 ObjectStore::create_object(self.owner(), transaction, options, wrapping_key_id).await?;
852 self.add_child_file(transaction, name, &handle).await?;
853 self.copy_project_id_to_object_in_txn(transaction, handle.object_id())?;
854 Ok(handle)
855 }
856
857 pub async fn create_child_unnamed_temporary_file<'a>(
858 &self,
859 transaction: &mut Transaction<'a>,
860 ) -> Result<DataObjectHandle<S>, Error> {
861 ensure!(!self.is_deleted(), FxfsError::Deleted);
862 let wrapping_key_id = self.wrapping_key_id.lock().clone();
863 let handle = ObjectStore::create_object(
864 self.owner(),
865 transaction,
866 HandleOptions::default(),
867 wrapping_key_id,
868 )
869 .await?;
870
871 let ObjectValue::Object { attributes: ObjectAttributes { project_id, .. }, .. } = self
873 .store()
874 .txn_get_object_mutation(&transaction, self.object_id())
875 .await
876 .unwrap()
877 .item
878 .value
879 else {
880 bail!(anyhow!(FxfsError::Inconsistent)
881 .context("Directory.create_child_file_with_options: expected mutation object"));
882 };
883
884 let mut child_mutation = transaction
886 .get_object_mutation(
887 self.store().store_object_id(),
888 ObjectKey::object(handle.object_id()),
889 )
890 .unwrap()
891 .clone();
892 if let ObjectValue::Object {
893 attributes: ObjectAttributes { project_id: child_project_id, .. },
894 ..
895 } = &mut child_mutation.item.value
896 {
897 *child_project_id = project_id;
898 } else {
899 bail!(anyhow!(FxfsError::Inconsistent)
900 .context("Directory.create_child_file_with_options: expected file object"));
901 }
902 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(child_mutation));
903
904 self.store().add_to_graveyard(transaction, handle.object_id());
906
907 Ok(handle)
908 }
909
910 pub async fn create_symlink(
911 &self,
912 transaction: &mut Transaction<'_>,
913 link: &[u8],
914 name: &str,
915 ) -> Result<u64, Error> {
916 ensure!(!self.is_deleted(), FxfsError::Deleted);
917 ensure!(link.len() <= 256, FxfsError::BadPath);
921 let symlink_id = self.store().get_next_object_id(transaction.txn_guard()).await?;
922 transaction.add(
923 self.store().store_object_id(),
924 Mutation::insert_object(
925 ObjectKey::object(symlink_id),
926 ObjectValue::symlink(link, Timestamp::now(), Timestamp::now(), 0),
927 ),
928 );
929 transaction.add(
930 self.store().store_object_id(),
931 Mutation::replace_or_insert_object(
932 ObjectKey::child(self.object_id(), name, self.casefold()),
933 ObjectValue::child(symlink_id, ObjectDescriptor::Symlink),
934 ),
935 );
936 self.update_dir_attributes_internal(
937 transaction,
938 self.object_id(),
939 MutableAttributesInternal {
940 modification_time: Some(Timestamp::now().as_nanos()),
941 ..Default::default()
942 },
943 )
944 .await?;
945 Ok(symlink_id)
946 }
947
948 pub async fn add_child_volume(
949 &self,
950 transaction: &mut Transaction<'_>,
951 volume_name: &str,
952 store_object_id: u64,
953 ) -> Result<(), Error> {
954 ensure!(!self.is_deleted(), FxfsError::Deleted);
955 transaction.add(
956 self.store().store_object_id(),
957 Mutation::replace_or_insert_object(
958 ObjectKey::child(self.object_id(), volume_name, self.casefold()),
959 ObjectValue::child(store_object_id, ObjectDescriptor::Volume),
960 ),
961 );
962 let now = Timestamp::now();
963 self.update_dir_attributes_internal(
964 transaction,
965 self.object_id(),
966 MutableAttributesInternal {
967 modification_time: Some(now.as_nanos()),
968 change_time: Some(now),
969 ..Default::default()
970 },
971 )
972 .await
973 }
974
975 pub async fn delete_child_volume<'a>(
976 &self,
977 transaction: &mut Transaction<'a>,
978 volume_name: &str,
979 store_object_id: u64,
980 ) -> Result<(), Error> {
981 ensure!(!self.is_deleted(), FxfsError::Deleted);
982 transaction.add(
983 self.store().store_object_id(),
984 Mutation::replace_or_insert_object(
985 ObjectKey::child(self.object_id(), volume_name, self.casefold()),
986 ObjectValue::None,
987 ),
988 );
989 transaction.add(store_object_id, Mutation::DeleteVolume);
994 Ok(())
995 }
996
997 pub async fn insert_child<'a>(
1001 &self,
1002 transaction: &mut Transaction<'a>,
1003 name: &str,
1004 object_id: u64,
1005 descriptor: ObjectDescriptor,
1006 ) -> Result<(), Error> {
1007 ensure!(!self.is_deleted(), FxfsError::Deleted);
1008 let sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1009 if self.wrapping_key_id.lock().is_some() {
1011 if !matches!(descriptor, ObjectDescriptor::File | ObjectDescriptor::Directory) {
1012 return Err(anyhow!(FxfsError::InvalidArgs)
1013 .context("Encrypted directories can only have file or directory children"));
1014 }
1015 let key = self.get_fscrypt_key().await?.ok_or(FxfsError::NoKey)?;
1016 let casefold_hash = get_casefold_hash(Some(&key), name, self.casefold());
1017 let encrypted_name = encrypt_filename(&key, self.object_id(), name)?;
1018 transaction.add(
1019 self.store().store_object_id(),
1020 Mutation::replace_or_insert_object(
1021 ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash),
1022 ObjectValue::child(object_id, descriptor),
1023 ),
1024 );
1025 } else {
1026 transaction.add(
1027 self.store().store_object_id(),
1028 Mutation::replace_or_insert_object(
1029 ObjectKey::child(self.object_id(), &name, self.casefold()),
1030 ObjectValue::child(object_id, descriptor),
1031 ),
1032 );
1033 }
1034 let now = Timestamp::now();
1035 self.update_dir_attributes_internal(
1036 transaction,
1037 self.object_id(),
1038 MutableAttributesInternal {
1039 sub_dirs: sub_dirs_delta,
1040 modification_time: Some(now.as_nanos()),
1041 change_time: Some(now),
1042 ..Default::default()
1043 },
1044 )
1045 .await
1046 }
1047
1048 pub async fn update_attributes<'a>(
1051 &self,
1052 mut transaction: Transaction<'a>,
1053 node_attributes: Option<&fio::MutableNodeAttributes>,
1054 sub_dirs_delta: i64,
1055 change_time: Option<Timestamp>,
1056 ) -> Result<(), Error> {
1057 ensure!(!self.is_deleted(), FxfsError::Deleted);
1058
1059 if sub_dirs_delta != 0 {
1060 let mut mutation =
1061 self.store().txn_get_object_mutation(&transaction, self.object_id()).await?;
1062 if let ObjectValue::Object { kind: ObjectKind::Directory { sub_dirs, .. }, .. } =
1063 &mut mutation.item.value
1064 {
1065 *sub_dirs = sub_dirs.saturating_add_signed(sub_dirs_delta);
1066 } else {
1067 bail!(anyhow!(FxfsError::Inconsistent)
1068 .context("Directory.update_attributes: expected directory object"));
1069 };
1070
1071 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1072 }
1073
1074 let wrapping_key =
1075 if let Some(fio::MutableNodeAttributes { wrapping_key_id: Some(id), .. }) =
1076 node_attributes
1077 {
1078 Some((
1079 u128::from_le_bytes(*id),
1080 self.set_wrapping_key(&mut transaction, u128::from_le_bytes(*id)).await?,
1081 ))
1082 } else {
1083 None
1084 };
1085
1086 if node_attributes.is_some() || change_time.is_some() {
1088 self.handle.update_attributes(&mut transaction, node_attributes, change_time).await?;
1089 }
1090 transaction
1091 .commit_with_callback(|_| {
1092 if let Some((key_id, unwrapped_key)) = wrapping_key {
1093 *self.wrapping_key_id.lock() = Some(key_id);
1094 self.store().key_manager.merge(self.object_id(), |existing| {
1095 let mut new = existing.map_or(Vec::new(), |e| e.ciphers().to_vec());
1096 new.push(unwrapped_key);
1097 Arc::new(CipherSet::from(new))
1098 });
1099 }
1100 })
1101 .await?;
1102 Ok(())
1103 }
1104
1105 pub async fn update_dir_attributes_internal<'a>(
1109 &self,
1110 transaction: &mut Transaction<'a>,
1111 object_id: u64,
1112 mutable_node_attributes: MutableAttributesInternal,
1113 ) -> Result<(), Error> {
1114 ensure!(!self.is_deleted(), FxfsError::Deleted);
1115
1116 let mut mutation = self.store().txn_get_object_mutation(transaction, object_id).await?;
1117 if let ObjectValue::Object {
1118 kind: ObjectKind::Directory { sub_dirs, .. },
1119 ref mut attributes,
1120 ..
1121 } = &mut mutation.item.value
1122 {
1123 if let Some(time) = mutable_node_attributes.modification_time {
1124 attributes.modification_time = Timestamp::from_nanos(time);
1125 }
1126 if let Some(time) = mutable_node_attributes.change_time {
1127 attributes.change_time = time;
1128 }
1129 if mutable_node_attributes.sub_dirs != 0 {
1130 *sub_dirs = sub_dirs.saturating_add_signed(mutable_node_attributes.sub_dirs);
1131 }
1132 if let Some(time) = mutable_node_attributes.creation_time {
1133 attributes.creation_time = Timestamp::from_nanos(time);
1134 }
1135 } else {
1136 bail!(anyhow!(FxfsError::Inconsistent)
1137 .context("Directory.update_attributes: expected directory object"));
1138 };
1139 transaction.add(self.store().store_object_id(), Mutation::ObjectStore(mutation));
1140 Ok(())
1141 }
1142
1143 pub async fn get_properties(&self) -> Result<ObjectProperties, Error> {
1144 if self.is_deleted() {
1145 return Ok(ObjectProperties {
1146 refs: 0,
1147 allocated_size: 0,
1148 data_attribute_size: 0,
1149 creation_time: Timestamp::zero(),
1150 modification_time: Timestamp::zero(),
1151 access_time: Timestamp::zero(),
1152 change_time: Timestamp::zero(),
1153 sub_dirs: 0,
1154 posix_attributes: None,
1155 casefold: false,
1156 wrapping_key_id: None,
1157 });
1158 }
1159
1160 let item = self
1161 .store()
1162 .tree()
1163 .find(&ObjectKey::object(self.object_id()))
1164 .await?
1165 .ok_or(FxfsError::NotFound)?;
1166 match item.value {
1167 ObjectValue::Object {
1168 kind: ObjectKind::Directory { sub_dirs, casefold, wrapping_key_id },
1169 attributes:
1170 ObjectAttributes {
1171 creation_time,
1172 modification_time,
1173 posix_attributes,
1174 access_time,
1175 change_time,
1176 ..
1177 },
1178 } => Ok(ObjectProperties {
1179 refs: 1,
1180 allocated_size: 0,
1181 data_attribute_size: 0,
1182 creation_time,
1183 modification_time,
1184 access_time,
1185 change_time,
1186 sub_dirs,
1187 posix_attributes,
1188 casefold,
1189 wrapping_key_id,
1190 }),
1191 _ => {
1192 bail!(anyhow!(FxfsError::Inconsistent)
1193 .context("get_properties: Expected object value"))
1194 }
1195 }
1196 }
1197
1198 pub async fn list_extended_attributes(&self) -> Result<Vec<Vec<u8>>, Error> {
1199 ensure!(!self.is_deleted(), FxfsError::Deleted);
1200 self.handle.list_extended_attributes().await
1201 }
1202
1203 pub async fn get_extended_attribute(&self, name: Vec<u8>) -> Result<Vec<u8>, Error> {
1204 ensure!(!self.is_deleted(), FxfsError::Deleted);
1205 self.handle.get_extended_attribute(name).await
1206 }
1207
1208 pub async fn set_extended_attribute(
1209 &self,
1210 name: Vec<u8>,
1211 value: Vec<u8>,
1212 mode: SetExtendedAttributeMode,
1213 ) -> Result<(), Error> {
1214 ensure!(!self.is_deleted(), FxfsError::Deleted);
1215 self.handle.set_extended_attribute(name, value, mode).await
1216 }
1217
1218 pub async fn remove_extended_attribute(&self, name: Vec<u8>) -> Result<(), Error> {
1219 ensure!(!self.is_deleted(), FxfsError::Deleted);
1220 self.handle.remove_extended_attribute(name).await
1221 }
1222
1223 pub async fn iter<'a, 'b>(
1231 &self,
1232 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1233 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1234 self.iter_from(merger, "").await
1235 }
1236
1237 pub async fn iter_from<'a, 'b>(
1244 &self,
1245 merger: &'a mut Merger<'b, ObjectKey, ObjectValue>,
1246 from: &str,
1247 ) -> Result<DirectoryIterator<'a, 'b>, Error> {
1248 ensure!(!self.is_deleted(), FxfsError::Deleted);
1249
1250 let (query_key, requested_filename) = if self.wrapping_key_id.lock().is_some() {
1254 if let Some(key) = self.get_fscrypt_key().await? {
1255 let casefold_hash = get_casefold_hash(Some(&key), from, self.casefold());
1257 let encrypted_name = encrypt_filename(&key, self.object_id(), from)?;
1258 (ObjectKey::encrypted_child(self.object_id(), encrypted_name, casefold_hash), None)
1259 } else {
1260 let filename = SyntheticFilename::decode(from);
1262 let key = filename.to_query_key(self.object_id());
1263 if from == "" {
1264 (key, None)
1266 } else {
1267 (key, Some(filename))
1269 }
1270 }
1271 } else {
1272 (ObjectKey::child(self.object_id(), from, self.casefold()), None)
1274 };
1275 let mut iter = merger.query(Query::FullRange(&query_key)).await?;
1276 loop {
1277 match iter.get() {
1278 Some(ItemRef {
1280 key: ObjectKey { object_id, .. },
1281 value: ObjectValue::None,
1282 ..
1283 }) if *object_id == self.object_id() => {}
1284 Some(ItemRef {
1286 key:
1287 ObjectKey {
1288 object_id,
1289 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
1290 ..
1291 },
1292 ..
1293 }) if *object_id == self.object_id() => {
1294 if let Some(requested_filename) = &requested_filename {
1296 let filename = SyntheticFilename::from_object_key(*casefold_hash, name);
1297 if &filename == requested_filename {
1298 break;
1299 }
1300 } else {
1301 break;
1304 }
1305 }
1306 _ => break,
1307 }
1308 iter.advance().await?;
1309 }
1310 let key = if self.wrapping_key_id.lock().is_some() {
1311 self.get_fscrypt_key().await?
1312 } else {
1313 None
1314 };
1315 let mut dir_iter =
1316 DirectoryIterator { object_id: self.object_id(), iter, key, filename: None };
1317 if let Some(ItemRef {
1325 key:
1326 ObjectKey {
1327 object_id, data: ObjectKeyData::EncryptedChild { casefold_hash, name }, ..
1328 },
1329 ..
1330 }) = dir_iter.iter.get()
1331 {
1332 let object_id = *object_id;
1333 let casefold_hash = *casefold_hash;
1334 let name = name.clone();
1335 dir_iter.update_encrypted_filename(object_id, casefold_hash, name)?;
1336 }
1337 Ok(dir_iter)
1338 }
1339}
1340
1341impl<S: HandleOwner> fmt::Debug for Directory<S> {
1342 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1343 f.debug_struct("Directory")
1344 .field("store_id", &self.store().store_object_id())
1345 .field("object_id", &self.object_id())
1346 .finish()
1347 }
1348}
1349
1350pub struct DirectoryIterator<'a, 'b> {
1351 object_id: u64,
1352 iter: MergerIterator<'a, 'b, ObjectKey, ObjectValue>,
1353 key: Option<Key>,
1354 filename: Option<String>,
1356}
1357
1358impl DirectoryIterator<'_, '_> {
1359 pub fn get(&self) -> Option<(&str, u64, &ObjectDescriptor)> {
1360 match self.iter.get() {
1361 Some(ItemRef {
1362 key: ObjectKey { object_id: oid, data: ObjectKeyData::Child { name } },
1363 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1364 ..
1365 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1366 Some(ItemRef {
1367 key: ObjectKey { object_id: oid, data: ObjectKeyData::CasefoldChild { name } },
1368 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1369 ..
1370 }) if *oid == self.object_id => Some((&name, *object_id, object_descriptor)),
1371 Some(ItemRef {
1372 key: ObjectKey { object_id: oid, data: ObjectKeyData::EncryptedChild { .. } },
1373 value: ObjectValue::Child(ChildValue { object_id, object_descriptor }),
1374 ..
1375 }) if *oid == self.object_id => {
1376 Some((self.filename.as_ref().unwrap(), *object_id, object_descriptor))
1377 }
1378 _ => None,
1379 }
1380 }
1381
1382 pub(super) fn update_encrypted_filename(
1385 &mut self,
1386 object_id: u64,
1387 casefold_hash: u32,
1388 mut name: Vec<u8>,
1389 ) -> Result<(), Error> {
1390 if let Some(key) = &self.key {
1391 key.decrypt_filename(object_id, &mut name)?;
1392 self.filename = Some(String::from_utf8(name).map_err(|_| {
1393 anyhow!(FxfsError::Internal).context("Bad UTF-8 encrypted filename")
1394 })?);
1395 } else {
1396 self.filename = Some(SyntheticFilename::from_object_key(casefold_hash, &name).encode());
1397 }
1398 Ok(())
1399 }
1400
1401 pub async fn advance(&mut self) -> Result<(), Error> {
1402 loop {
1403 self.iter.advance().await?;
1404 match self.iter.get() {
1406 Some(ItemRef {
1407 key: ObjectKey { object_id, .. },
1408 value: ObjectValue::None,
1409 ..
1410 }) if *object_id == self.object_id => {}
1411 Some(ItemRef {
1412 key:
1413 ObjectKey {
1414 object_id,
1415 data: ObjectKeyData::EncryptedChild { casefold_hash, name },
1416 },
1417 value: ObjectValue::Child(_),
1418 ..
1419 }) if *object_id == self.object_id => {
1420 self.update_encrypted_filename(*object_id, *casefold_hash, name.clone())?;
1423 return Ok(());
1424 }
1425 _ => return Ok(()),
1426 }
1427 }
1428 }
1429}
1430
1431#[derive(Debug)]
1434pub enum ReplacedChild {
1435 None,
1436 Object(u64),
1438 ObjectWithRemainingLinks(u64),
1439 Directory(u64),
1440}
1441
1442pub async fn replace_child<'a, S: HandleOwner>(
1450 transaction: &mut Transaction<'a>,
1451 src: Option<(&'a Directory<S>, &str)>,
1452 dst: (&'a Directory<S>, &str),
1453) -> Result<ReplacedChild, Error> {
1454 let mut sub_dirs_delta: i64 = 0;
1455 let now = Timestamp::now();
1456
1457 let src = if let Some((src_dir, src_name)) = src {
1458 let store_id = dst.0.store().store_object_id();
1459 assert_eq!(store_id, src_dir.store().store_object_id());
1460 match (src_dir.wrapping_key_id(), dst.0.wrapping_key_id()) {
1461 (Some(src_id), Some(dst_id)) => {
1462 ensure!(src_id == dst_id, FxfsError::NotSupported);
1463 let key = if let Some(key) = src_dir.get_fscrypt_key().await? {
1466 key
1467 } else {
1468 bail!(FxfsError::NoKey);
1469 };
1470
1471 let src_casefold_hash = get_casefold_hash(Some(&key), src_name, src_dir.casefold());
1472 let encrypted_src_name = encrypt_filename(&key, src_dir.object_id(), src_name)?;
1473 transaction.add(
1474 store_id,
1475 Mutation::replace_or_insert_object(
1476 ObjectKey::encrypted_child(
1477 src_dir.object_id(),
1478 encrypted_src_name,
1479 src_casefold_hash,
1480 ),
1481 ObjectValue::None,
1482 ),
1483 );
1484 }
1485 (None, None) => {
1486 transaction.add(
1487 store_id,
1488 Mutation::replace_or_insert_object(
1489 ObjectKey::child(src_dir.object_id(), src_name, src_dir.casefold()),
1490 ObjectValue::None,
1491 ),
1492 );
1493 }
1494 _ => bail!(FxfsError::NotSupported),
1496 }
1497 let (id, descriptor) = src_dir.lookup(src_name).await?.ok_or(FxfsError::NotFound)?;
1498 src_dir.store().update_attributes(transaction, id, None, Some(now)).await?;
1499 if src_dir.object_id() != dst.0.object_id() {
1500 sub_dirs_delta = if descriptor == ObjectDescriptor::Directory { 1 } else { 0 };
1501 src_dir
1502 .update_dir_attributes_internal(
1503 transaction,
1504 src_dir.object_id(),
1505 MutableAttributesInternal {
1506 sub_dirs: -sub_dirs_delta,
1507 modification_time: Some(now.as_nanos()),
1508 change_time: Some(now),
1509 ..Default::default()
1510 },
1511 )
1512 .await?;
1513 }
1514 Some((id, descriptor))
1515 } else {
1516 None
1517 };
1518 replace_child_with_object(transaction, src, dst, sub_dirs_delta, now).await
1519}
1520
1521pub async fn replace_child_with_object<'a, S: HandleOwner>(
1530 transaction: &mut Transaction<'a>,
1531 src: Option<(u64, ObjectDescriptor)>,
1532 dst: (&'a Directory<S>, &str),
1533 mut sub_dirs_delta: i64,
1534 timestamp: Timestamp,
1535) -> Result<ReplacedChild, Error> {
1536 let deleted_id_and_descriptor = dst.0.lookup(dst.1).await?;
1537 let store_id = dst.0.store().store_object_id();
1538 let result = match deleted_id_and_descriptor {
1541 Some((old_id, ObjectDescriptor::File | ObjectDescriptor::Symlink)) => {
1542 let was_last_ref = dst.0.store().adjust_refs(transaction, old_id, -1).await?;
1543 dst.0.store().update_attributes(transaction, old_id, None, Some(timestamp)).await?;
1544 if was_last_ref {
1545 ReplacedChild::Object(old_id)
1546 } else {
1547 ReplacedChild::ObjectWithRemainingLinks(old_id)
1548 }
1549 }
1550 Some((old_id, ObjectDescriptor::Directory)) => {
1551 let dir = Directory::open(&dst.0.owner(), old_id).await?;
1552 if dir.has_children().await? {
1553 bail!(FxfsError::NotEmpty);
1554 }
1555 dst.0.store().add_to_graveyard(transaction, old_id);
1558 dst.0.store().filesystem().graveyard().queue_tombstone_object(store_id, old_id);
1559 sub_dirs_delta -= 1;
1560 ReplacedChild::Directory(old_id)
1561 }
1562 Some((_, ObjectDescriptor::Volume)) => {
1563 bail!(anyhow!(FxfsError::Inconsistent).context("Unexpected volume child"))
1564 }
1565 None => {
1566 if src.is_none() {
1567 bail!(FxfsError::NotFound);
1569 }
1570 ReplacedChild::None
1571 }
1572 };
1573 let new_value = match src {
1574 Some((id, descriptor)) => ObjectValue::child(id, descriptor),
1575 None => ObjectValue::None,
1576 };
1577 if dst.0.wrapping_key_id().is_some() {
1578 if let Some(key) = dst.0.get_fscrypt_key().await? {
1579 let dst_casefold_hash = get_casefold_hash(Some(&key), dst.1, dst.0.casefold());
1580 let encrypted_dst_name = encrypt_filename(&key, dst.0.object_id(), dst.1)?;
1581 transaction.add(
1582 store_id,
1583 Mutation::replace_or_insert_object(
1584 ObjectKey::encrypted_child(
1585 dst.0.object_id(),
1586 encrypted_dst_name,
1587 dst_casefold_hash,
1588 ),
1589 new_value,
1590 ),
1591 );
1592 } else {
1593 if !matches!(new_value, ObjectValue::None) {
1594 bail!(FxfsError::NoKey);
1596 }
1597 let synthetic_filename = SyntheticFilename::decode(dst.1);
1601
1602 let layer_set = dst.0.store().tree().layer_set();
1603 let mut merger = layer_set.merger();
1604 let iter = dst.0.iter_from(&mut merger, dst.1).await.context("iter_from")?;
1605 if let Some(ItemRef {
1606 key:
1607 key @ ObjectKey {
1608 data: ObjectKeyData::EncryptedChild { casefold_hash, name }, ..
1609 },
1610 ..
1611 }) = iter.iter.get()
1612 {
1613 let filename = SyntheticFilename::from_object_key(*casefold_hash, name);
1614 if filename == synthetic_filename {
1615 transaction
1616 .add(store_id, Mutation::replace_or_insert_object(key.clone(), new_value));
1617 } else {
1618 bail!(FxfsError::NotFound);
1619 }
1620 } else {
1621 bail!(FxfsError::NotFound);
1622 }
1623 }
1624 } else {
1625 transaction.add(
1626 store_id,
1627 Mutation::replace_or_insert_object(
1628 ObjectKey::child(dst.0.object_id(), dst.1, dst.0.casefold()),
1629 new_value,
1630 ),
1631 );
1632 }
1633 dst.0
1634 .update_dir_attributes_internal(
1635 transaction,
1636 dst.0.object_id(),
1637 MutableAttributesInternal {
1638 sub_dirs: sub_dirs_delta,
1639 modification_time: Some(timestamp.as_nanos()),
1640 change_time: Some(timestamp),
1641 ..Default::default()
1642 },
1643 )
1644 .await?;
1645 Ok(result)
1646}
1647
1648#[cfg(test)]
1649mod tests {
1650 use super::{
1651 encrypt_filename, get_casefold_hash, replace_child_with_object, SyntheticFilename,
1652 };
1653 use crate::errors::FxfsError;
1654 use crate::filesystem::{FxFilesystem, JournalingObject, SyncOptions};
1655 use crate::object_handle::{ObjectHandle, ReadObjectHandle, WriteObjectHandle};
1656 use crate::object_store::directory::{
1657 replace_child, Directory, MutableAttributesInternal, ReplacedChild,
1658 };
1659 use crate::object_store::object_record::Timestamp;
1660 use crate::object_store::transaction::{lock_keys, Options};
1661 use crate::object_store::volume::root_volume;
1662 use crate::object_store::{
1663 HandleOptions, LockKey, ObjectDescriptor, ObjectStore, SetExtendedAttributeMode,
1664 StoreObjectHandle, NO_OWNER,
1665 };
1666 use assert_matches::assert_matches;
1667 use fidl_fuchsia_io as fio;
1668 use fxfs_crypto::Crypt;
1669 use fxfs_insecure_crypto::InsecureCrypt;
1670 use std::collections::HashSet;
1671 use std::sync::Arc;
1672 use storage_device::fake_device::FakeDevice;
1673 use storage_device::DeviceHolder;
1674
1675 const TEST_DEVICE_BLOCK_SIZE: u32 = 512;
1676
1677 #[fuchsia::test]
1678 async fn test_create_directory() {
1679 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
1680 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1681 let object_id = {
1682 let mut transaction = fs
1683 .clone()
1684 .new_transaction(lock_keys![], Options::default())
1685 .await
1686 .expect("new_transaction failed");
1687 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
1688 .await
1689 .expect("create failed");
1690
1691 let child_dir = dir
1692 .create_child_dir(&mut transaction, "foo")
1693 .await
1694 .expect("create_child_dir failed");
1695 let _child_dir_file = child_dir
1696 .create_child_file(&mut transaction, "bar")
1697 .await
1698 .expect("create_child_file failed");
1699 let _child_file = dir
1700 .create_child_file(&mut transaction, "baz")
1701 .await
1702 .expect("create_child_file failed");
1703 dir.add_child_volume(&mut transaction, "corge", 100)
1704 .await
1705 .expect("add_child_volume failed");
1706 transaction.commit().await.expect("commit failed");
1707 fs.sync(SyncOptions::default()).await.expect("sync failed");
1708 dir.object_id()
1709 };
1710 fs.close().await.expect("Close failed");
1711 let device = fs.take_device().await;
1712 device.reopen(false);
1713 let fs = FxFilesystem::open(device).await.expect("open failed");
1714 {
1715 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
1716 let (object_id, object_descriptor) =
1717 dir.lookup("foo").await.expect("lookup failed").expect("not found");
1718 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
1719 let child_dir =
1720 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
1721 let (object_id, object_descriptor) =
1722 child_dir.lookup("bar").await.expect("lookup failed").expect("not found");
1723 assert_eq!(object_descriptor, ObjectDescriptor::File);
1724 let _child_dir_file = ObjectStore::open_object(
1725 &fs.root_store(),
1726 object_id,
1727 HandleOptions::default(),
1728 None,
1729 )
1730 .await
1731 .expect("open object failed");
1732 let (object_id, object_descriptor) =
1733 dir.lookup("baz").await.expect("lookup failed").expect("not found");
1734 assert_eq!(object_descriptor, ObjectDescriptor::File);
1735 let _child_file = ObjectStore::open_object(
1736 &fs.root_store(),
1737 object_id,
1738 HandleOptions::default(),
1739 None,
1740 )
1741 .await
1742 .expect("open object failed");
1743 let (object_id, object_descriptor) =
1744 dir.lookup("corge").await.expect("lookup failed").expect("not found");
1745 assert_eq!(object_id, 100);
1746 if let ObjectDescriptor::Volume = object_descriptor {
1747 } else {
1748 panic!("wrong ObjectDescriptor");
1749 }
1750
1751 assert_eq!(dir.lookup("qux").await.expect("lookup failed"), None);
1752 }
1753 fs.close().await.expect("Close failed");
1754 }
1755
1756 #[fuchsia::test]
1757 async fn test_set_wrapping_key_does_not_exist() {
1758 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1759 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1760 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1761 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1762 let store = root_volume
1763 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1764 .await
1765 .expect("new_volume failed");
1766
1767 let mut transaction = fs
1768 .clone()
1769 .new_transaction(
1770 lock_keys![LockKey::object(
1771 store.store_object_id(),
1772 store.root_directory_object_id()
1773 )],
1774 Options::default(),
1775 )
1776 .await
1777 .expect("new transaction failed");
1778 let root_directory =
1779 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1780 let directory = root_directory
1781 .create_child_dir(&mut transaction, "foo")
1782 .await
1783 .expect("create_child_dir failed");
1784 transaction.commit().await.expect("commit failed");
1785 let mut transaction = fs
1786 .clone()
1787 .new_transaction(
1788 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1789 Options::default(),
1790 )
1791 .await
1792 .expect("new transaction failed");
1793 directory
1794 .set_wrapping_key(&mut transaction, 2)
1795 .await
1796 .expect_err("wrapping key id 2 has not been added");
1797 transaction.commit().await.expect("commit failed");
1798 crypt.add_wrapping_key(2, [1; 32]);
1799 let mut transaction = fs
1800 .clone()
1801 .new_transaction(
1802 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1803 Options::default(),
1804 )
1805 .await
1806 .expect("new transaction failed");
1807 directory
1808 .set_wrapping_key(&mut transaction, 2)
1809 .await
1810 .expect("wrapping key id 2 has been added");
1811 fs.close().await.expect("Close failed");
1812 }
1813
1814 #[fuchsia::test]
1815 async fn test_set_encryption_policy_on_unencrypted_nonempty_dir() {
1816 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1817 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1818 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1819 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1820 let store = root_volume
1821 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1822 .await
1823 .expect("new_volume failed");
1824
1825 let mut transaction = fs
1826 .clone()
1827 .new_transaction(
1828 lock_keys![LockKey::object(
1829 store.store_object_id(),
1830 store.root_directory_object_id()
1831 )],
1832 Options::default(),
1833 )
1834 .await
1835 .expect("new transaction failed");
1836 let root_directory =
1837 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1838 let directory = root_directory
1839 .create_child_dir(&mut transaction, "foo")
1840 .await
1841 .expect("create_child_dir failed");
1842 let _file = directory
1843 .create_child_file(&mut transaction, "bar")
1844 .await
1845 .expect("create_child_file failed");
1846 transaction.commit().await.expect("commit failed");
1847 let mut transaction = fs
1848 .clone()
1849 .new_transaction(
1850 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1851 Options::default(),
1852 )
1853 .await
1854 .expect("new transaction failed");
1855 directory.set_wrapping_key(&mut transaction, 2).await.expect_err("directory is not empty");
1856 transaction.commit().await.expect("commit failed");
1857 fs.close().await.expect("Close failed");
1858 }
1859
1860 #[fuchsia::test]
1861 async fn test_create_file_or_subdir_in_locked_directory() {
1862 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1863 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1864 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1865 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
1866 let store = root_volume
1867 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1868 .await
1869 .expect("new_volume failed");
1870
1871 let mut transaction = fs
1872 .clone()
1873 .new_transaction(
1874 lock_keys![LockKey::object(
1875 store.store_object_id(),
1876 store.root_directory_object_id()
1877 )],
1878 Options::default(),
1879 )
1880 .await
1881 .expect("new transaction failed");
1882 let root_directory =
1883 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
1884 let directory = root_directory
1885 .create_child_dir(&mut transaction, "foo")
1886 .await
1887 .expect("create_child_dir failed");
1888 transaction.commit().await.expect("commit failed");
1889 crypt.add_wrapping_key(2, [1; 32]);
1890 let transaction = fs
1891 .clone()
1892 .new_transaction(
1893 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1894 Options::default(),
1895 )
1896 .await
1897 .expect("new transaction failed");
1898 directory
1899 .update_attributes(
1900 transaction,
1901 Some(&fio::MutableNodeAttributes {
1902 wrapping_key_id: Some(u128::to_le_bytes(2)),
1903 ..Default::default()
1904 }),
1905 0,
1906 None,
1907 )
1908 .await
1909 .expect("update attributes failed");
1910 crypt.remove_wrapping_key(2);
1911 let mut transaction = fs
1912 .clone()
1913 .new_transaction(
1914 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1915 Options::default(),
1916 )
1917 .await
1918 .expect("new transaction failed");
1919 directory
1920 .create_child_dir(&mut transaction, "bar")
1921 .await
1922 .expect_err("cannot create a dir inside of a locked encrypted directory");
1923 directory
1924 .create_child_file(&mut transaction, "baz")
1925 .await
1926 .map(|_| ())
1927 .expect_err("cannot create a file inside of a locked encrypted directory");
1928 fs.close().await.expect("Close failed");
1929 }
1930
1931 #[fuchsia::test]
1932 async fn test_replace_child_with_object_in_locked_directory() {
1933 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
1934 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
1935 let crypt = Arc::new(InsecureCrypt::new());
1936
1937 let (parent_oid, src_oid, dst_oid) = {
1938 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
1939 let store = root_volume
1940 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
1941 .await
1942 .expect("new_volume failed");
1943
1944 let mut transaction = fs
1945 .clone()
1946 .new_transaction(
1947 lock_keys![LockKey::object(
1948 store.store_object_id(),
1949 store.root_directory_object_id()
1950 )],
1951 Options::default(),
1952 )
1953 .await
1954 .expect("new transaction failed");
1955 let root_directory = Directory::open(&store, store.root_directory_object_id())
1956 .await
1957 .expect("open failed");
1958 let directory = root_directory
1959 .create_child_dir(&mut transaction, "foo")
1960 .await
1961 .expect("create_child_dir failed");
1962 transaction.commit().await.expect("commit failed");
1963 crypt.add_wrapping_key(2, [1; 32]);
1964 let 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 .update_attributes(
1974 transaction,
1975 Some(&fio::MutableNodeAttributes {
1976 wrapping_key_id: Some(u128::to_le_bytes(2)),
1977 ..Default::default()
1978 }),
1979 0,
1980 None,
1981 )
1982 .await
1983 .expect("update attributes failed");
1984 let mut transaction = fs
1985 .clone()
1986 .new_transaction(
1987 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
1988 Options::default(),
1989 )
1990 .await
1991 .expect("new transaction failed");
1992 let src_child = directory
1993 .create_child_dir(&mut transaction, "fee")
1994 .await
1995 .expect("create_child_dir failed");
1996 let dst_child = directory
1997 .create_child_dir(&mut transaction, "faa")
1998 .await
1999 .expect("create_child_dir failed");
2000 transaction.commit().await.expect("commit failed");
2001 crypt.remove_wrapping_key(2);
2002 (directory.object_id(), src_child.object_id(), dst_child.object_id())
2003 };
2004 fs.close().await.expect("Close failed");
2005 let device = fs.take_device().await;
2006 device.reopen(false);
2007 let fs = FxFilesystem::open(device).await.expect("open failed");
2008 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2009 let store = root_volume
2010 .volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
2011 .await
2012 .expect("volume failed");
2013
2014 {
2015 let parent_directory = Directory::open(&store, parent_oid).await.expect("open failed");
2016 let layer_set = store.tree().layer_set();
2017 let mut merger = layer_set.merger();
2018 let mut encrypted_src_name = None;
2019 let mut encrypted_dst_name = None;
2020 let mut iter =
2021 parent_directory.iter_from(&mut merger, "").await.expect("iter_from failed");
2022 while let Some((name, object_id, object_descriptor)) = iter.get() {
2023 assert!(matches!(object_descriptor, ObjectDescriptor::Directory));
2024 if object_id == dst_oid {
2025 encrypted_dst_name = Some(name.to_string());
2026 } else if object_id == src_oid {
2027 encrypted_src_name = Some(name.to_string());
2028 }
2029 iter.advance().await.expect("iter advance failed");
2030 }
2031
2032 let src_child = parent_directory
2033 .lookup(&encrypted_src_name.expect("src child not found"))
2034 .await
2035 .expect("lookup failed")
2036 .expect("not found");
2037 let mut transaction = fs
2038 .clone()
2039 .new_transaction(
2040 lock_keys![LockKey::object(
2041 store.store_object_id(),
2042 parent_directory.object_id(),
2043 )],
2044 Options::default(),
2045 )
2046 .await
2047 .expect("new transaction failed");
2048 replace_child_with_object(
2049 &mut transaction,
2050 Some(src_child),
2051 (&parent_directory, &encrypted_dst_name.expect("dst child not found")),
2052 0,
2053 Timestamp::now(),
2054 )
2055 .await
2056 .expect_err("renames should fail within a locked directory");
2057 }
2058 fs.close().await.expect("Close failed");
2059 }
2060
2061 #[fuchsia::test]
2062 async fn test_set_encryption_policy_on_unencrypted_file() {
2063 let device = DeviceHolder::new(FakeDevice::new(8192, 4096));
2064 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2065 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
2066 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
2067 let store = root_volume
2068 .new_volume("test", NO_OWNER, Some(crypt.clone() as Arc<dyn Crypt>))
2069 .await
2070 .expect("new_volume failed");
2071
2072 let mut transaction = fs
2073 .clone()
2074 .new_transaction(
2075 lock_keys![LockKey::object(
2076 store.store_object_id(),
2077 store.root_directory_object_id()
2078 )],
2079 Options::default(),
2080 )
2081 .await
2082 .expect("new transaction failed");
2083 let root_directory =
2084 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
2085 let file_handle = root_directory
2086 .create_child_file(&mut transaction, "foo")
2087 .await
2088 .expect("create_child_dir failed");
2089 transaction.commit().await.expect("commit failed");
2090 let mut transaction = fs
2091 .clone()
2092 .new_transaction(
2093 lock_keys![LockKey::object(store.store_object_id(), file_handle.object_id())],
2094 Options::default(),
2095 )
2096 .await
2097 .expect("new transaction failed");
2098 let mut wrapping_key_id = [0; 16];
2099 wrapping_key_id[0] = 2;
2100 file_handle
2101 .update_attributes(
2102 &mut transaction,
2103 Some(&fio::MutableNodeAttributes {
2104 wrapping_key_id: Some(wrapping_key_id),
2105 ..Default::default()
2106 }),
2107 None,
2108 )
2109 .await
2110 .expect_err("Cannot update the wrapping key id of a file");
2111 fs.close().await.expect("Close failed");
2112 }
2113
2114 #[fuchsia::test]
2115 async fn test_delete_child() {
2116 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2117 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2118 let dir;
2119 let child;
2120 let mut transaction = fs
2121 .clone()
2122 .new_transaction(lock_keys![], Options::default())
2123 .await
2124 .expect("new_transaction failed");
2125 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2126 .await
2127 .expect("create failed");
2128
2129 child =
2130 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2131 transaction.commit().await.expect("commit failed");
2132
2133 transaction = fs
2134 .clone()
2135 .new_transaction(
2136 lock_keys![
2137 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2138 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2139 ],
2140 Options::default(),
2141 )
2142 .await
2143 .expect("new_transaction failed");
2144 assert_matches!(
2145 replace_child(&mut transaction, None, (&dir, "foo"))
2146 .await
2147 .expect("replace_child failed"),
2148 ReplacedChild::Object(..)
2149 );
2150 transaction.commit().await.expect("commit failed");
2151
2152 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2153 fs.close().await.expect("Close failed");
2154 }
2155
2156 #[fuchsia::test]
2157 async fn test_delete_child_with_children_fails() {
2158 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2159 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2160 let dir;
2161 let child;
2162 let bar;
2163 let mut transaction = fs
2164 .clone()
2165 .new_transaction(lock_keys![], Options::default())
2166 .await
2167 .expect("new_transaction failed");
2168 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2169 .await
2170 .expect("create failed");
2171
2172 child =
2173 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2174 bar = child
2175 .create_child_file(&mut transaction, "bar")
2176 .await
2177 .expect("create_child_file failed");
2178 transaction.commit().await.expect("commit failed");
2179
2180 transaction = fs
2181 .clone()
2182 .new_transaction(
2183 lock_keys![
2184 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2185 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2186 ],
2187 Options::default(),
2188 )
2189 .await
2190 .expect("new_transaction failed");
2191 assert_eq!(
2192 replace_child(&mut transaction, None, (&dir, "foo"))
2193 .await
2194 .expect_err("replace_child succeeded")
2195 .downcast::<FxfsError>()
2196 .expect("wrong error"),
2197 FxfsError::NotEmpty
2198 );
2199 transaction.commit().await.expect("commit failed");
2200
2201 transaction = fs
2202 .clone()
2203 .new_transaction(
2204 lock_keys![
2205 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2206 LockKey::object(fs.root_store().store_object_id(), bar.object_id()),
2207 ],
2208 Options::default(),
2209 )
2210 .await
2211 .expect("new_transaction failed");
2212 assert_matches!(
2213 replace_child(&mut transaction, None, (&child, "bar"))
2214 .await
2215 .expect("replace_child failed"),
2216 ReplacedChild::Object(..)
2217 );
2218 transaction.commit().await.expect("commit failed");
2219
2220 transaction = fs
2221 .clone()
2222 .new_transaction(
2223 lock_keys![
2224 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2225 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2226 ],
2227 Options::default(),
2228 )
2229 .await
2230 .expect("new_transaction failed");
2231 assert_matches!(
2232 replace_child(&mut transaction, None, (&dir, "foo"))
2233 .await
2234 .expect("replace_child failed"),
2235 ReplacedChild::Directory(..)
2236 );
2237 transaction.commit().await.expect("commit failed");
2238
2239 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2240 fs.close().await.expect("Close failed");
2241 }
2242
2243 #[fuchsia::test]
2244 async fn test_delete_and_reinsert_child() {
2245 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2246 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2247 let dir;
2248 let child;
2249 let mut transaction = fs
2250 .clone()
2251 .new_transaction(lock_keys![], Options::default())
2252 .await
2253 .expect("new_transaction failed");
2254 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2255 .await
2256 .expect("create failed");
2257
2258 child =
2259 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2260 transaction.commit().await.expect("commit failed");
2261
2262 transaction = fs
2263 .clone()
2264 .new_transaction(
2265 lock_keys![
2266 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2267 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2268 ],
2269 Options::default(),
2270 )
2271 .await
2272 .expect("new_transaction failed");
2273 assert_matches!(
2274 replace_child(&mut transaction, None, (&dir, "foo"))
2275 .await
2276 .expect("replace_child failed"),
2277 ReplacedChild::Object(..)
2278 );
2279 transaction.commit().await.expect("commit failed");
2280
2281 transaction = fs
2282 .clone()
2283 .new_transaction(
2284 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2285 Options::default(),
2286 )
2287 .await
2288 .expect("new_transaction failed");
2289 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2290 transaction.commit().await.expect("commit failed");
2291
2292 dir.lookup("foo").await.expect("lookup failed");
2293 fs.close().await.expect("Close failed");
2294 }
2295
2296 #[fuchsia::test]
2297 async fn test_delete_child_persists() {
2298 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2299 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2300 let object_id = {
2301 let dir;
2302 let child;
2303 let mut transaction = fs
2304 .clone()
2305 .new_transaction(lock_keys![], Options::default())
2306 .await
2307 .expect("new_transaction failed");
2308 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2309 .await
2310 .expect("create failed");
2311
2312 child = dir
2313 .create_child_file(&mut transaction, "foo")
2314 .await
2315 .expect("create_child_file failed");
2316 transaction.commit().await.expect("commit failed");
2317 dir.lookup("foo").await.expect("lookup failed");
2318
2319 transaction = fs
2320 .clone()
2321 .new_transaction(
2322 lock_keys![
2323 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2324 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2325 ],
2326 Options::default(),
2327 )
2328 .await
2329 .expect("new_transaction failed");
2330 assert_matches!(
2331 replace_child(&mut transaction, None, (&dir, "foo"))
2332 .await
2333 .expect("replace_child failed"),
2334 ReplacedChild::Object(..)
2335 );
2336 transaction.commit().await.expect("commit failed");
2337
2338 fs.sync(SyncOptions::default()).await.expect("sync failed");
2339 dir.object_id()
2340 };
2341
2342 fs.close().await.expect("Close failed");
2343 let device = fs.take_device().await;
2344 device.reopen(false);
2345 let fs = FxFilesystem::open(device).await.expect("open failed");
2346 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
2347 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2348 fs.close().await.expect("Close failed");
2349 }
2350
2351 #[fuchsia::test]
2352 async fn test_replace_child() {
2353 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2354 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2355 let dir;
2356 let child_dir1;
2357 let child_dir2;
2358 let mut transaction = fs
2359 .clone()
2360 .new_transaction(lock_keys![], Options::default())
2361 .await
2362 .expect("new_transaction failed");
2363 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2364 .await
2365 .expect("create failed");
2366
2367 child_dir1 =
2368 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2369 child_dir2 =
2370 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2371 let file = child_dir1
2372 .create_child_file(&mut transaction, "foo")
2373 .await
2374 .expect("create_child_file failed");
2375 transaction.commit().await.expect("commit failed");
2376
2377 transaction = fs
2378 .clone()
2379 .new_transaction(
2380 lock_keys![
2381 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2382 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2383 LockKey::object(fs.root_store().store_object_id(), file.object_id()),
2384 ],
2385 Options::default(),
2386 )
2387 .await
2388 .expect("new_transaction failed");
2389 assert_matches!(
2390 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2391 .await
2392 .expect("replace_child failed"),
2393 ReplacedChild::None
2394 );
2395 transaction.commit().await.expect("commit failed");
2396
2397 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2398 child_dir2.lookup("bar").await.expect("lookup failed");
2399 fs.close().await.expect("Close failed");
2400 }
2401
2402 #[fuchsia::test]
2403 async fn test_replace_child_overwrites_dst() {
2404 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2405 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2406 let dir;
2407 let child_dir1;
2408 let child_dir2;
2409 let mut transaction = fs
2410 .clone()
2411 .new_transaction(lock_keys![], Options::default())
2412 .await
2413 .expect("new_transaction failed");
2414 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2415 .await
2416 .expect("create failed");
2417
2418 child_dir1 =
2419 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2420 child_dir2 =
2421 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2422 let foo = child_dir1
2423 .create_child_file(&mut transaction, "foo")
2424 .await
2425 .expect("create_child_file failed");
2426 let bar = child_dir2
2427 .create_child_file(&mut transaction, "bar")
2428 .await
2429 .expect("create_child_file failed");
2430 let foo_oid = foo.object_id();
2431 let bar_oid = bar.object_id();
2432 transaction.commit().await.expect("commit failed");
2433
2434 {
2435 let mut buf = foo.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2436 buf.as_mut_slice().fill(0xaa);
2437 foo.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2438 buf.as_mut_slice().fill(0xbb);
2439 bar.write_or_append(Some(0), buf.as_ref()).await.expect("write failed");
2440 }
2441 std::mem::drop(bar);
2442 std::mem::drop(foo);
2443
2444 transaction = fs
2445 .clone()
2446 .new_transaction(
2447 lock_keys![
2448 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2449 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2450 LockKey::object(fs.root_store().store_object_id(), foo_oid),
2451 LockKey::object(fs.root_store().store_object_id(), bar_oid),
2452 ],
2453 Options::default(),
2454 )
2455 .await
2456 .expect("new_transaction failed");
2457 assert_matches!(
2458 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2459 .await
2460 .expect("replace_child failed"),
2461 ReplacedChild::Object(..)
2462 );
2463 transaction.commit().await.expect("commit failed");
2464
2465 assert_eq!(child_dir1.lookup("foo").await.expect("lookup failed"), None);
2466
2467 let (oid, object_descriptor) =
2469 child_dir2.lookup("bar").await.expect("lookup failed").expect("not found");
2470 assert_eq!(object_descriptor, ObjectDescriptor::File);
2471 let bar =
2472 ObjectStore::open_object(&child_dir2.owner(), oid, HandleOptions::default(), None)
2473 .await
2474 .expect("Open failed");
2475 let mut buf = bar.allocate_buffer(TEST_DEVICE_BLOCK_SIZE as usize).await;
2476 bar.read(0, buf.as_mut()).await.expect("read failed");
2477 assert_eq!(buf.as_slice(), vec![0xaa; TEST_DEVICE_BLOCK_SIZE as usize]);
2478 fs.close().await.expect("Close failed");
2479 }
2480
2481 #[fuchsia::test]
2482 async fn test_replace_child_fails_if_would_overwrite_nonempty_dir() {
2483 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2484 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2485 let dir;
2486 let child_dir1;
2487 let child_dir2;
2488 let mut transaction = fs
2489 .clone()
2490 .new_transaction(lock_keys![], Options::default())
2491 .await
2492 .expect("new_transaction failed");
2493 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2494 .await
2495 .expect("create failed");
2496
2497 child_dir1 =
2498 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
2499 child_dir2 =
2500 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
2501 let foo = child_dir1
2502 .create_child_file(&mut transaction, "foo")
2503 .await
2504 .expect("create_child_file failed");
2505 let nested_child = child_dir2
2506 .create_child_dir(&mut transaction, "bar")
2507 .await
2508 .expect("create_child_file failed");
2509 nested_child
2510 .create_child_file(&mut transaction, "baz")
2511 .await
2512 .expect("create_child_file failed");
2513 transaction.commit().await.expect("commit failed");
2514
2515 transaction = fs
2516 .clone()
2517 .new_transaction(
2518 lock_keys![
2519 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
2520 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
2521 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2522 LockKey::object(fs.root_store().store_object_id(), nested_child.object_id()),
2523 ],
2524 Options::default(),
2525 )
2526 .await
2527 .expect("new_transaction failed");
2528 assert_eq!(
2529 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&child_dir2, "bar"))
2530 .await
2531 .expect_err("replace_child succeeded")
2532 .downcast::<FxfsError>()
2533 .expect("wrong error"),
2534 FxfsError::NotEmpty
2535 );
2536 fs.close().await.expect("Close failed");
2537 }
2538
2539 #[fuchsia::test]
2540 async fn test_replace_child_within_dir() {
2541 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2542 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2543 let dir;
2544 let mut transaction = fs
2545 .clone()
2546 .new_transaction(lock_keys![], Options::default())
2547 .await
2548 .expect("new_transaction failed");
2549 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2550 .await
2551 .expect("create failed");
2552 let foo =
2553 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_file failed");
2554 transaction.commit().await.expect("commit failed");
2555
2556 transaction = fs
2557 .clone()
2558 .new_transaction(
2559 lock_keys![
2560 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2561 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
2562 ],
2563 Options::default(),
2564 )
2565 .await
2566 .expect("new_transaction failed");
2567 assert_matches!(
2568 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
2569 .await
2570 .expect("replace_child failed"),
2571 ReplacedChild::None
2572 );
2573 transaction.commit().await.expect("commit failed");
2574
2575 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2576 dir.lookup("bar").await.expect("lookup new name failed");
2577 fs.close().await.expect("Close failed");
2578 }
2579
2580 #[fuchsia::test]
2581 async fn test_iterate() {
2582 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2583 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2584 let dir;
2585 let mut transaction = fs
2586 .clone()
2587 .new_transaction(lock_keys![], Options::default())
2588 .await
2589 .expect("new_transaction failed");
2590 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2591 .await
2592 .expect("create failed");
2593 let _cat =
2594 dir.create_child_file(&mut transaction, "cat").await.expect("create_child_file failed");
2595 let _ball = dir
2596 .create_child_file(&mut transaction, "ball")
2597 .await
2598 .expect("create_child_file failed");
2599 let apple = dir
2600 .create_child_file(&mut transaction, "apple")
2601 .await
2602 .expect("create_child_file failed");
2603 let _dog =
2604 dir.create_child_file(&mut transaction, "dog").await.expect("create_child_file failed");
2605 transaction.commit().await.expect("commit failed");
2606 transaction = fs
2607 .clone()
2608 .new_transaction(
2609 lock_keys![
2610 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2611 LockKey::object(fs.root_store().store_object_id(), apple.object_id()),
2612 ],
2613 Options::default(),
2614 )
2615 .await
2616 .expect("new_transaction failed");
2617 replace_child(&mut transaction, None, (&dir, "apple")).await.expect("replace_child failed");
2618 transaction.commit().await.expect("commit failed");
2619 let layer_set = dir.store().tree().layer_set();
2620 let mut merger = layer_set.merger();
2621 let mut iter = dir.iter(&mut merger).await.expect("iter failed");
2622 let mut entries = Vec::new();
2623 while let Some((name, _, _)) = iter.get() {
2624 entries.push(name.to_string());
2625 iter.advance().await.expect("advance failed");
2626 }
2627 assert_eq!(&entries, &["ball", "cat", "dog"]);
2628 fs.close().await.expect("Close failed");
2629 }
2630
2631 #[fuchsia::test]
2632 async fn test_sub_dir_count() {
2633 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2634 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2635 let dir;
2636 let child_dir;
2637 let mut transaction = fs
2638 .clone()
2639 .new_transaction(lock_keys![], Options::default())
2640 .await
2641 .expect("new_transaction failed");
2642 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2643 .await
2644 .expect("create failed");
2645 child_dir =
2646 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2647 transaction.commit().await.expect("commit failed");
2648 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2649
2650 transaction = fs
2652 .clone()
2653 .new_transaction(
2654 lock_keys![
2655 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2656 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2657 ],
2658 Options::default(),
2659 )
2660 .await
2661 .expect("new_transaction failed");
2662 replace_child(&mut transaction, Some((&dir, "foo")), (&dir, "bar"))
2663 .await
2664 .expect("replace_child failed");
2665 transaction.commit().await.expect("commit failed");
2666
2667 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2668 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2669
2670 transaction = fs
2672 .clone()
2673 .new_transaction(
2674 lock_keys![LockKey::object(
2675 fs.root_store().store_object_id(),
2676 child_dir.object_id()
2677 )],
2678 Options::default(),
2679 )
2680 .await
2681 .expect("new_transaction failed");
2682 let second_child = child_dir
2683 .create_child_dir(&mut transaction, "baz")
2684 .await
2685 .expect("create_child_dir failed");
2686 transaction.commit().await.expect("commit failed");
2687
2688 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2689
2690 transaction = fs
2691 .clone()
2692 .new_transaction(
2693 lock_keys![
2694 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2695 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2696 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
2697 ],
2698 Options::default(),
2699 )
2700 .await
2701 .expect("new_transaction failed");
2702 replace_child(&mut transaction, Some((&child_dir, "baz")), (&dir, "foo"))
2703 .await
2704 .expect("replace_child failed");
2705 transaction.commit().await.expect("commit failed");
2706
2707 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 2);
2708 assert_eq!(child_dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2709
2710 transaction = fs
2712 .clone()
2713 .new_transaction(
2714 lock_keys![
2715 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2716 LockKey::object(fs.root_store().store_object_id(), second_child.object_id()),
2717 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2718 ],
2719 Options::default(),
2720 )
2721 .await
2722 .expect("new_transaction failed");
2723 replace_child(&mut transaction, Some((&dir, "bar")), (&dir, "foo"))
2724 .await
2725 .expect("replace_child failed");
2726 transaction.commit().await.expect("commit failed");
2727
2728 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 1);
2729
2730 transaction = fs
2732 .clone()
2733 .new_transaction(
2734 lock_keys![
2735 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2736 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
2737 ],
2738 Options::default(),
2739 )
2740 .await
2741 .expect("new_transaction failed");
2742 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
2743 transaction.commit().await.expect("commit failed");
2744
2745 assert_eq!(dir.get_properties().await.expect("get_properties failed").sub_dirs, 0);
2746 fs.close().await.expect("Close failed");
2747 }
2748
2749 #[fuchsia::test]
2750 async fn test_deleted_dir() {
2751 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2752 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2753 let dir;
2754 let mut transaction = fs
2755 .clone()
2756 .new_transaction(lock_keys![], Options::default())
2757 .await
2758 .expect("new_transaction failed");
2759 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2760 .await
2761 .expect("create failed");
2762 let child =
2763 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2764 dir.create_child_dir(&mut transaction, "bar").await.expect("create_child_dir failed");
2765 transaction.commit().await.expect("commit failed");
2766
2767 dir.store().flush().await.expect("flush failed");
2769
2770 transaction = fs
2772 .clone()
2773 .new_transaction(
2774 lock_keys![
2775 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
2776 LockKey::object(fs.root_store().store_object_id(), child.object_id()),
2777 ],
2778 Options::default(),
2779 )
2780 .await
2781 .expect("new_transaction failed");
2782 replace_child(&mut transaction, None, (&dir, "foo")).await.expect("replace_child failed");
2783 transaction.commit().await.expect("commit failed");
2784
2785 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2787
2788 assert!(dir.lookup("bar").await.expect("lookup failed").is_some());
2790
2791 dir.set_deleted();
2793
2794 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2795 assert_eq!(dir.lookup("bar").await.expect("lookup failed"), None);
2796 assert!(!dir.has_children().await.expect("has_children failed"));
2797
2798 transaction = fs
2799 .clone()
2800 .new_transaction(lock_keys![], Options::default())
2801 .await
2802 .expect("new_transaction failed");
2803
2804 let assert_access_denied = |result| {
2805 if let Err(e) = result {
2806 assert!(FxfsError::Deleted.matches(&e));
2807 } else {
2808 panic!();
2809 }
2810 };
2811 assert_access_denied(dir.create_child_dir(&mut transaction, "baz").await.map(|_| {}));
2812 assert_access_denied(dir.create_child_file(&mut transaction, "baz").await.map(|_| {}));
2813 assert_access_denied(dir.add_child_volume(&mut transaction, "baz", 1).await);
2814 assert_access_denied(
2815 dir.insert_child(&mut transaction, "baz", 1, ObjectDescriptor::File).await,
2816 );
2817 assert_access_denied(
2818 dir.update_dir_attributes_internal(
2819 &mut transaction,
2820 dir.object_id(),
2821 MutableAttributesInternal {
2822 creation_time: Some(Timestamp::zero().as_nanos()),
2823 ..Default::default()
2824 },
2825 )
2826 .await,
2827 );
2828 let layer_set = dir.store().tree().layer_set();
2829 let mut merger = layer_set.merger();
2830 assert_access_denied(dir.iter(&mut merger).await.map(|_| {}));
2831 }
2832
2833 #[fuchsia::test]
2834 async fn test_create_symlink() {
2835 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2836 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2837 let (dir_id, symlink_id) = {
2838 let mut transaction = fs
2839 .clone()
2840 .new_transaction(lock_keys![], Options::default())
2841 .await
2842 .expect("new_transaction failed");
2843 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
2844 .await
2845 .expect("create failed");
2846
2847 let symlink_id = dir
2848 .create_symlink(&mut transaction, b"link", "foo")
2849 .await
2850 .expect("create_symlink failed");
2851 transaction.commit().await.expect("commit failed");
2852
2853 fs.sync(SyncOptions::default()).await.expect("sync failed");
2854 (dir.object_id(), symlink_id)
2855 };
2856 fs.close().await.expect("Close failed");
2857 let device = fs.take_device().await;
2858 device.reopen(false);
2859 let fs = FxFilesystem::open(device).await.expect("open failed");
2860 {
2861 let dir = Directory::open(&fs.root_store(), dir_id).await.expect("open failed");
2862 assert_eq!(
2863 dir.lookup("foo").await.expect("lookup failed").expect("not found"),
2864 (symlink_id, ObjectDescriptor::Symlink)
2865 );
2866 }
2867 fs.close().await.expect("Close failed");
2868 }
2869
2870 #[fuchsia::test]
2871 async fn test_read_symlink() {
2872 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2873 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2874 let mut transaction = fs
2875 .clone()
2876 .new_transaction(lock_keys![], Options::default())
2877 .await
2878 .expect("new_transaction failed");
2879 let store = fs.root_store();
2880 let dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
2881
2882 let symlink_id = dir
2883 .create_symlink(&mut transaction, b"link", "foo")
2884 .await
2885 .expect("create_symlink failed");
2886 transaction.commit().await.expect("commit failed");
2887
2888 let link = store.read_symlink(symlink_id).await.expect("read_symlink failed");
2889 assert_eq!(&link, b"link");
2890 fs.close().await.expect("Close failed");
2891 }
2892
2893 #[fuchsia::test]
2894 async fn test_unlink_symlink() {
2895 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2896 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2897 let dir;
2898 let mut transaction = fs
2899 .clone()
2900 .new_transaction(lock_keys![], Options::default())
2901 .await
2902 .expect("new_transaction failed");
2903 let store = fs.root_store();
2904 dir = Directory::create(&mut transaction, &store, None).await.expect("create failed");
2905
2906 let symlink_id = dir
2907 .create_symlink(&mut transaction, b"link", "foo")
2908 .await
2909 .expect("create_symlink failed");
2910 transaction.commit().await.expect("commit failed");
2911 transaction = fs
2912 .clone()
2913 .new_transaction(
2914 lock_keys![
2915 LockKey::object(store.store_object_id(), dir.object_id()),
2916 LockKey::object(store.store_object_id(), symlink_id),
2917 ],
2918 Options::default(),
2919 )
2920 .await
2921 .expect("new_transaction failed");
2922 assert_matches!(
2923 replace_child(&mut transaction, None, (&dir, "foo"))
2924 .await
2925 .expect("replace_child failed"),
2926 ReplacedChild::Object(_)
2927 );
2928 transaction.commit().await.expect("commit failed");
2929
2930 assert_eq!(dir.lookup("foo").await.expect("lookup failed"), None);
2931 fs.close().await.expect("Close failed");
2932 }
2933
2934 #[fuchsia::test]
2935 async fn test_get_properties() {
2936 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
2937 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
2938 let dir;
2939 let mut transaction = fs
2940 .clone()
2941 .new_transaction(lock_keys![], Options::default())
2942 .await
2943 .expect("new_transaction failed");
2944
2945 dir = Directory::create(&mut transaction, &fs.root_store(), None)
2946 .await
2947 .expect("create failed");
2948 transaction.commit().await.expect("commit failed");
2949
2950 let mut properties = dir.get_properties().await.expect("get_properties failed");
2952 let dir_creation_time = properties.creation_time;
2953 assert_eq!(dir_creation_time, properties.modification_time);
2954 assert_eq!(properties.sub_dirs, 0);
2955 assert!(properties.posix_attributes.is_none());
2956
2957 transaction = fs
2959 .clone()
2960 .new_transaction(
2961 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
2962 Options::default(),
2963 )
2964 .await
2965 .expect("new_transaction failed");
2966 let child_dir =
2967 dir.create_child_dir(&mut transaction, "foo").await.expect("create_child_dir failed");
2968 transaction.commit().await.expect("commit failed");
2969
2970 properties = dir.get_properties().await.expect("get_properties failed");
2972 assert_eq!(dir_creation_time, properties.creation_time);
2974 assert!(dir_creation_time < properties.modification_time);
2975 assert_eq!(properties.sub_dirs, 1);
2976 assert!(properties.posix_attributes.is_none());
2977
2978 properties = child_dir.get_properties().await.expect("get_properties failed");
2980 assert_eq!(properties.creation_time, properties.modification_time);
2981 assert_eq!(properties.sub_dirs, 0);
2982 assert!(properties.posix_attributes.is_none());
2983
2984 transaction = fs
2986 .clone()
2987 .new_transaction(
2988 lock_keys![LockKey::object(
2989 fs.root_store().store_object_id(),
2990 child_dir.object_id()
2991 )],
2992 Options::default(),
2993 )
2994 .await
2995 .expect("new_transaction failed");
2996 let child_dir_file = child_dir
2997 .create_child_file(&mut transaction, "bar")
2998 .await
2999 .expect("create_child_file failed");
3000 child_dir_file
3001 .update_attributes(
3002 &mut transaction,
3003 Some(&fio::MutableNodeAttributes { gid: Some(1), ..Default::default() }),
3004 None,
3005 )
3006 .await
3007 .expect("Updating attributes");
3008 transaction.commit().await.expect("commit failed");
3009
3010 properties = child_dir.get_properties().await.expect("get_properties failed");
3012 assert!(properties.creation_time < properties.modification_time);
3013 assert!(properties.posix_attributes.is_none());
3014
3015 properties = child_dir_file.get_properties().await.expect("get_properties failed");
3017 assert_eq!(properties.creation_time, properties.modification_time);
3018 assert_eq!(properties.sub_dirs, 0);
3019 assert!(properties.posix_attributes.is_some());
3020 assert_eq!(properties.posix_attributes.unwrap().gid, 1);
3021 assert_eq!(properties.posix_attributes.unwrap().uid, 0);
3023 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3024 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3025 }
3026
3027 #[fuchsia::test]
3028 async fn test_update_create_attributes() {
3029 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3030 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3031 let dir;
3032 let mut transaction = fs
3033 .clone()
3034 .new_transaction(lock_keys![], Options::default())
3035 .await
3036 .expect("new_transaction failed");
3037
3038 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3039 .await
3040 .expect("create failed");
3041 transaction.commit().await.expect("commit failed");
3042 let mut properties = dir.get_properties().await.expect("get_properties failed");
3043 assert_eq!(properties.sub_dirs, 0);
3044 assert!(properties.posix_attributes.is_none());
3045 let creation_time = properties.creation_time;
3046 let modification_time = properties.modification_time;
3047 assert_eq!(creation_time, modification_time);
3048
3049 transaction = fs
3055 .clone()
3056 .new_transaction(
3057 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3058 Options::default(),
3059 )
3060 .await
3061 .expect("new_transaction failed");
3062 let now = Timestamp::now();
3063 dir.update_attributes(
3064 transaction,
3065 Some(&fio::MutableNodeAttributes {
3066 modification_time: Some(now.as_nanos()),
3067 uid: Some(1),
3068 gid: Some(2),
3069 ..Default::default()
3070 }),
3071 0,
3072 None,
3073 )
3074 .await
3075 .expect("update_attributes failed");
3076 properties = dir.get_properties().await.expect("get_properties failed");
3077 assert_eq!(properties.modification_time, now);
3079 assert!(properties.posix_attributes.is_some());
3080 assert_eq!(properties.posix_attributes.unwrap().uid, 1);
3081 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3082 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3084 assert_eq!(properties.posix_attributes.unwrap().rdev, 0);
3085 assert_eq!(properties.sub_dirs, 0);
3087 assert_eq!(properties.creation_time, creation_time);
3088
3089 let transaction = fs
3092 .clone()
3093 .new_transaction(
3094 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3095 Options::default(),
3096 )
3097 .await
3098 .expect("new_transaction failed");
3099 dir.update_attributes(
3100 transaction,
3101 Some(&fio::MutableNodeAttributes {
3102 creation_time: Some(now.as_nanos()),
3103 uid: Some(3),
3104 rdev: Some(10),
3105 ..Default::default()
3106 }),
3107 0,
3108 None,
3109 )
3110 .await
3111 .expect("update_attributes failed");
3112 properties = dir.get_properties().await.expect("get_properties failed");
3113 assert_eq!(properties.creation_time, now);
3114 assert!(properties.posix_attributes.is_some());
3115 assert_eq!(properties.posix_attributes.unwrap().uid, 3);
3116 assert_eq!(properties.posix_attributes.unwrap().rdev, 10);
3117 assert_eq!(properties.sub_dirs, 0);
3119 assert_eq!(properties.modification_time, now);
3120 assert_eq!(properties.posix_attributes.unwrap().gid, 2);
3121 assert_eq!(properties.posix_attributes.unwrap().mode, 0);
3122 }
3123
3124 #[fuchsia::test]
3125 async fn write_to_directory_attribute_creates_keys() {
3126 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3127 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3128 let crypt = Arc::new(InsecureCrypt::new());
3129
3130 {
3131 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3132 let store = root_volume
3133 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3134 .await
3135 .expect("new_volume failed");
3136 let mut transaction = filesystem
3137 .clone()
3138 .new_transaction(
3139 lock_keys![LockKey::object(
3140 store.store_object_id(),
3141 store.root_directory_object_id()
3142 )],
3143 Options::default(),
3144 )
3145 .await
3146 .expect("new transaction failed");
3147 let root_directory = Directory::open(&store, store.root_directory_object_id())
3148 .await
3149 .expect("open failed");
3150 let directory = root_directory
3151 .create_child_dir(&mut transaction, "foo")
3152 .await
3153 .expect("create_child_dir failed");
3154 transaction.commit().await.expect("commit failed");
3155
3156 let mut transaction = filesystem
3157 .clone()
3158 .new_transaction(
3159 lock_keys![LockKey::object(store.store_object_id(), directory.object_id())],
3160 Options::default(),
3161 )
3162 .await
3163 .expect("new transaction failed");
3164 let _ = directory
3165 .handle
3166 .write_attr(&mut transaction, 1, b"bar")
3167 .await
3168 .expect("write_attr failed");
3169 transaction.commit().await.expect("commit failed");
3170 }
3171
3172 filesystem.close().await.expect("Close failed");
3173 let device = filesystem.take_device().await;
3174 device.reopen(false);
3175 let filesystem = FxFilesystem::open(device).await.expect("open failed");
3176
3177 {
3178 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3179 let volume =
3180 root_volume.volume("vol", NO_OWNER, Some(crypt)).await.expect("volume failed");
3181 let root_directory = Directory::open(&volume, volume.root_directory_object_id())
3182 .await
3183 .expect("open failed");
3184 let directory = Directory::open(
3185 &volume,
3186 root_directory.lookup("foo").await.expect("lookup failed").expect("not found").0,
3187 )
3188 .await
3189 .expect("open failed");
3190 let mut buffer = directory.handle.allocate_buffer(10).await;
3191 assert_eq!(directory.handle.read(1, 0, buffer.as_mut()).await.expect("read failed"), 3);
3192 assert_eq!(&buffer.as_slice()[..3], b"bar");
3193 }
3194
3195 filesystem.close().await.expect("Close failed");
3196 }
3197
3198 #[fuchsia::test]
3199 async fn directory_with_extended_attributes() {
3200 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3201 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3202 let crypt = Arc::new(InsecureCrypt::new());
3203
3204 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3205 let store = root_volume
3206 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3207 .await
3208 .expect("new_volume failed");
3209 let directory =
3210 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3211
3212 let test_small_name = b"security.selinux".to_vec();
3213 let test_small_value = b"foo".to_vec();
3214 let test_large_name = b"large.attribute".to_vec();
3215 let test_large_value = vec![1u8; 500];
3216
3217 directory
3218 .set_extended_attribute(
3219 test_small_name.clone(),
3220 test_small_value.clone(),
3221 SetExtendedAttributeMode::Set,
3222 )
3223 .await
3224 .unwrap();
3225 assert_eq!(
3226 directory.get_extended_attribute(test_small_name.clone()).await.unwrap(),
3227 test_small_value
3228 );
3229
3230 directory
3231 .set_extended_attribute(
3232 test_large_name.clone(),
3233 test_large_value.clone(),
3234 SetExtendedAttributeMode::Set,
3235 )
3236 .await
3237 .unwrap();
3238 assert_eq!(
3239 directory.get_extended_attribute(test_large_name.clone()).await.unwrap(),
3240 test_large_value
3241 );
3242
3243 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3244 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3245 .await
3246 .unwrap();
3247
3248 directory.remove_extended_attribute(test_small_name.clone()).await.unwrap();
3249 directory.remove_extended_attribute(test_large_name.clone()).await.unwrap();
3250
3251 filesystem.close().await.expect("close failed");
3252 }
3253
3254 #[fuchsia::test]
3255 async fn remove_directory_with_extended_attributes() {
3256 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3257 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3258 let crypt = Arc::new(InsecureCrypt::new());
3259
3260 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3261 let store = root_volume
3262 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3263 .await
3264 .expect("new_volume failed");
3265 let mut transaction = filesystem
3266 .clone()
3267 .new_transaction(
3268 lock_keys![LockKey::object(
3269 store.store_object_id(),
3270 store.root_directory_object_id()
3271 )],
3272 Options::default(),
3273 )
3274 .await
3275 .expect("new transaction failed");
3276 let root_directory =
3277 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3278 let directory = root_directory
3279 .create_child_dir(&mut transaction, "foo")
3280 .await
3281 .expect("create_child_dir failed");
3282 transaction.commit().await.expect("commit failed");
3283
3284 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3285 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3286 .await
3287 .unwrap();
3288
3289 let test_small_name = b"security.selinux".to_vec();
3290 let test_small_value = b"foo".to_vec();
3291 let test_large_name = b"large.attribute".to_vec();
3292 let test_large_value = vec![1u8; 500];
3293
3294 directory
3295 .set_extended_attribute(
3296 test_small_name.clone(),
3297 test_small_value.clone(),
3298 SetExtendedAttributeMode::Set,
3299 )
3300 .await
3301 .unwrap();
3302 directory
3303 .set_extended_attribute(
3304 test_large_name.clone(),
3305 test_large_value.clone(),
3306 SetExtendedAttributeMode::Set,
3307 )
3308 .await
3309 .unwrap();
3310
3311 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3312 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3313 .await
3314 .unwrap();
3315
3316 let mut transaction = filesystem
3317 .clone()
3318 .new_transaction(
3319 lock_keys![
3320 LockKey::object(store.store_object_id(), root_directory.object_id()),
3321 LockKey::object(store.store_object_id(), directory.object_id()),
3322 ],
3323 Options::default(),
3324 )
3325 .await
3326 .expect("new_transaction failed");
3327 replace_child(&mut transaction, None, (&root_directory, "foo"))
3328 .await
3329 .expect("replace_child failed");
3330 transaction.commit().await.unwrap();
3331
3332 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3333 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3334 .await
3335 .unwrap();
3336
3337 filesystem.close().await.expect("close failed");
3338 }
3339
3340 #[fuchsia::test]
3341 async fn remove_symlink_with_extended_attributes() {
3342 let device = DeviceHolder::new(FakeDevice::new(16384, 512));
3343 let filesystem = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3344 let crypt = Arc::new(InsecureCrypt::new());
3345
3346 let root_volume = root_volume(filesystem.clone()).await.expect("root_volume failed");
3347 let store = root_volume
3348 .new_volume("vol", NO_OWNER, Some(crypt.clone()))
3349 .await
3350 .expect("new_volume failed");
3351 let mut transaction = filesystem
3352 .clone()
3353 .new_transaction(
3354 lock_keys![LockKey::object(
3355 store.store_object_id(),
3356 store.root_directory_object_id()
3357 )],
3358 Options::default(),
3359 )
3360 .await
3361 .expect("new transaction failed");
3362 let root_directory =
3363 Directory::open(&store, store.root_directory_object_id()).await.expect("open failed");
3364 let symlink_id = root_directory
3365 .create_symlink(&mut transaction, b"somewhere/else", "foo")
3366 .await
3367 .expect("create_symlink failed");
3368 transaction.commit().await.expect("commit failed");
3369
3370 let symlink = StoreObjectHandle::new(
3371 store.clone(),
3372 symlink_id,
3373 false,
3374 HandleOptions::default(),
3375 false,
3376 );
3377
3378 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3379 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3380 .await
3381 .unwrap();
3382
3383 let test_small_name = b"security.selinux".to_vec();
3384 let test_small_value = b"foo".to_vec();
3385 let test_large_name = b"large.attribute".to_vec();
3386 let test_large_value = vec![1u8; 500];
3387
3388 symlink
3389 .set_extended_attribute(
3390 test_small_name.clone(),
3391 test_small_value.clone(),
3392 SetExtendedAttributeMode::Set,
3393 )
3394 .await
3395 .unwrap();
3396 symlink
3397 .set_extended_attribute(
3398 test_large_name.clone(),
3399 test_large_value.clone(),
3400 SetExtendedAttributeMode::Set,
3401 )
3402 .await
3403 .unwrap();
3404
3405 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3406 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3407 .await
3408 .unwrap();
3409
3410 let mut transaction = filesystem
3411 .clone()
3412 .new_transaction(
3413 lock_keys![
3414 LockKey::object(store.store_object_id(), root_directory.object_id()),
3415 LockKey::object(store.store_object_id(), symlink.object_id()),
3416 ],
3417 Options::default(),
3418 )
3419 .await
3420 .expect("new_transaction failed");
3421 replace_child(&mut transaction, None, (&root_directory, "foo"))
3422 .await
3423 .expect("replace_child failed");
3424 transaction.commit().await.unwrap();
3425
3426 crate::fsck::fsck(filesystem.clone()).await.unwrap();
3427 crate::fsck::fsck_volume(filesystem.as_ref(), store.store_object_id(), Some(crypt.clone()))
3428 .await
3429 .unwrap();
3430
3431 filesystem.close().await.expect("close failed");
3432 }
3433
3434 #[fuchsia::test]
3435 async fn test_update_timestamps() {
3436 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3437 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3438 let dir;
3439 let mut transaction = fs
3440 .clone()
3441 .new_transaction(lock_keys![], Options::default())
3442 .await
3443 .expect("new_transaction failed");
3444
3445 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3448 .await
3449 .expect("create failed");
3450 transaction.commit().await.expect("commit failed");
3451 let mut properties = dir.get_properties().await.expect("get_properties failed");
3452 let starting_time = properties.creation_time;
3453 assert_eq!(properties.creation_time, starting_time);
3454 assert_eq!(properties.modification_time, starting_time);
3455 assert_eq!(properties.change_time, starting_time);
3456 assert_eq!(properties.access_time, starting_time);
3457
3458 transaction = fs
3460 .clone()
3461 .new_transaction(
3462 lock_keys![LockKey::object(fs.root_store().store_object_id(), dir.object_id())],
3463 Options::default(),
3464 )
3465 .await
3466 .expect("new_transaction failed");
3467 let update1_time = Timestamp::now();
3468 dir.update_attributes(
3469 transaction,
3470 Some(&fio::MutableNodeAttributes {
3471 modification_time: Some(update1_time.as_nanos()),
3472 ..Default::default()
3473 }),
3474 0,
3475 Some(update1_time),
3476 )
3477 .await
3478 .expect("update_attributes failed");
3479 properties = dir.get_properties().await.expect("get_properties failed");
3480 assert_eq!(properties.modification_time, update1_time);
3481 assert_eq!(properties.access_time, starting_time);
3482 assert_eq!(properties.creation_time, starting_time);
3483 assert_eq!(properties.change_time, update1_time);
3484 }
3485
3486 #[fuchsia::test]
3487 async fn test_move_dir_timestamps() {
3488 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3489 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3490 let dir;
3491 let child1;
3492 let child2;
3493 let mut transaction = fs
3494 .clone()
3495 .new_transaction(lock_keys![], Options::default())
3496 .await
3497 .expect("new_transaction failed");
3498 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3499 .await
3500 .expect("create failed");
3501 child1 = dir
3502 .create_child_dir(&mut transaction, "child1")
3503 .await
3504 .expect("create_child_dir failed");
3505 child2 = dir
3506 .create_child_dir(&mut transaction, "child2")
3507 .await
3508 .expect("create_child_dir failed");
3509 transaction.commit().await.expect("commit failed");
3510 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3511 let child2_properties = child2.get_properties().await.expect("get_properties failed");
3512
3513 transaction = fs
3515 .clone()
3516 .new_transaction(
3517 lock_keys![
3518 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3519 LockKey::object(fs.root_store().store_object_id(), child1.object_id()),
3520 LockKey::object(fs.root_store().store_object_id(), child2.object_id()),
3521 ],
3522 Options::default(),
3523 )
3524 .await
3525 .expect("new_transaction failed");
3526 assert_matches!(
3527 replace_child(&mut transaction, Some((&dir, "child2")), (&child1, "child2"))
3528 .await
3529 .expect("replace_child failed"),
3530 ReplacedChild::None
3531 );
3532 transaction.commit().await.expect("commit failed");
3533 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
3535 let time_of_replacement = new_dir_properties.change_time;
3536 assert!(new_dir_properties.change_time > dir_properties.change_time);
3537 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
3538 let new_child1_properties = child1.get_properties().await.expect("get_properties failed");
3540 assert_eq!(new_child1_properties.modification_time, time_of_replacement);
3541 assert_eq!(new_child1_properties.change_time, time_of_replacement);
3542 let moved_child2_properties = child2.get_properties().await.expect("get_properties failed");
3544 assert_eq!(moved_child2_properties.change_time, time_of_replacement);
3545 assert_eq!(moved_child2_properties.creation_time, child2_properties.creation_time);
3546 assert_eq!(moved_child2_properties.access_time, child2_properties.access_time);
3547 assert_eq!(moved_child2_properties.modification_time, child2_properties.modification_time);
3548 fs.close().await.expect("Close failed");
3549 }
3550
3551 #[fuchsia::test]
3552 async fn test_unlink_timestamps() {
3553 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3554 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3555 let dir;
3556 let foo;
3557 let mut transaction = fs
3558 .clone()
3559 .new_transaction(lock_keys![], Options::default())
3560 .await
3561 .expect("new_transaction failed");
3562 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3563 .await
3564 .expect("create failed");
3565 foo =
3566 dir.create_child_file(&mut transaction, "foo").await.expect("create_child_dir failed");
3567
3568 transaction.commit().await.expect("commit failed");
3569 let dir_properties = dir.get_properties().await.expect("get_properties failed");
3570 let foo_properties = foo.get_properties().await.expect("get_properties failed");
3571
3572 transaction = fs
3573 .clone()
3574 .new_transaction(
3575 lock_keys![
3576 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3577 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3578 ],
3579 Options::default(),
3580 )
3581 .await
3582 .expect("new_transaction failed");
3583 assert_matches!(
3584 replace_child(&mut transaction, None, (&dir, "foo"))
3585 .await
3586 .expect("replace_child failed"),
3587 ReplacedChild::Object(_)
3588 );
3589 transaction.commit().await.expect("commit failed");
3590 let new_dir_properties = dir.get_properties().await.expect("get_properties failed");
3592 let time_of_replacement = new_dir_properties.change_time;
3593 assert!(new_dir_properties.change_time > dir_properties.change_time);
3594 assert_eq!(new_dir_properties.modification_time, time_of_replacement);
3595 let moved_foo_properties = foo.get_properties().await.expect("get_properties failed");
3597 assert_eq!(moved_foo_properties.change_time, time_of_replacement);
3598 assert_eq!(moved_foo_properties.creation_time, foo_properties.creation_time);
3599 assert_eq!(moved_foo_properties.access_time, foo_properties.access_time);
3600 assert_eq!(moved_foo_properties.modification_time, foo_properties.modification_time);
3601 fs.close().await.expect("Close failed");
3602 }
3603
3604 #[fuchsia::test]
3605 async fn test_replace_dir_timestamps() {
3606 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3607 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3608 let dir;
3609 let child_dir1;
3610 let child_dir2;
3611 let foo;
3612 let mut transaction = fs
3613 .clone()
3614 .new_transaction(lock_keys![], Options::default())
3615 .await
3616 .expect("new_transaction failed");
3617 dir = Directory::create(&mut transaction, &fs.root_store(), None)
3618 .await
3619 .expect("create failed");
3620 child_dir1 =
3621 dir.create_child_dir(&mut transaction, "dir1").await.expect("create_child_dir failed");
3622 child_dir2 =
3623 dir.create_child_dir(&mut transaction, "dir2").await.expect("create_child_dir failed");
3624 foo = child_dir1
3625 .create_child_dir(&mut transaction, "foo")
3626 .await
3627 .expect("create_child_dir failed");
3628 transaction.commit().await.expect("commit failed");
3629 let dir_props = dir.get_properties().await.expect("get_properties failed");
3630 let foo_props = foo.get_properties().await.expect("get_properties failed");
3631
3632 transaction = fs
3633 .clone()
3634 .new_transaction(
3635 lock_keys![
3636 LockKey::object(fs.root_store().store_object_id(), dir.object_id()),
3637 LockKey::object(fs.root_store().store_object_id(), child_dir1.object_id()),
3638 LockKey::object(fs.root_store().store_object_id(), child_dir2.object_id()),
3639 LockKey::object(fs.root_store().store_object_id(), foo.object_id()),
3640 ],
3641 Options::default(),
3642 )
3643 .await
3644 .expect("new_transaction failed");
3645 assert_matches!(
3646 replace_child(&mut transaction, Some((&child_dir1, "foo")), (&dir, "dir2"))
3647 .await
3648 .expect("replace_child failed"),
3649 ReplacedChild::Directory(_)
3650 );
3651 transaction.commit().await.expect("commit failed");
3652 let new_dir_props = dir.get_properties().await.expect("get_properties failed");
3654 let time_of_replacement = new_dir_props.change_time;
3655 assert!(new_dir_props.change_time > dir_props.change_time);
3656 assert_eq!(new_dir_props.modification_time, time_of_replacement);
3657 let new_dir1_props = child_dir1.get_properties().await.expect("get_properties failed");
3659 let time_of_replacement = new_dir1_props.change_time;
3660 assert_eq!(new_dir1_props.change_time, time_of_replacement);
3661 assert_eq!(new_dir1_props.modification_time, time_of_replacement);
3662 let moved_foo_props = foo.get_properties().await.expect("get_properties failed");
3664 assert_eq!(moved_foo_props.change_time, time_of_replacement);
3665 assert_eq!(moved_foo_props.creation_time, foo_props.creation_time);
3666 assert_eq!(moved_foo_props.access_time, foo_props.access_time);
3667 assert_eq!(moved_foo_props.modification_time, foo_props.modification_time);
3668 fs.close().await.expect("Close failed");
3669 }
3670
3671 #[fuchsia::test]
3672 async fn test_create_casefold_directory() {
3673 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3674 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3675 let object_id = {
3676 let mut transaction = fs
3677 .clone()
3678 .new_transaction(lock_keys![], Options::default())
3679 .await
3680 .expect("new_transaction failed");
3681 let dir = Directory::create(&mut transaction, &fs.root_store(), None)
3682 .await
3683 .expect("create failed");
3684
3685 let child_dir = dir
3686 .create_child_dir(&mut transaction, "foo")
3687 .await
3688 .expect("create_child_dir failed");
3689 let _child_dir_file = child_dir
3690 .create_child_file(&mut transaction, "bAr")
3691 .await
3692 .expect("create_child_file failed");
3693 transaction.commit().await.expect("commit failed");
3694 dir.object_id()
3695 };
3696 fs.close().await.expect("Close failed");
3697 let device = fs.take_device().await;
3698
3699 device.reopen(false);
3702 let fs = FxFilesystem::open(device).await.expect("open failed");
3703 {
3704 let dir = Directory::open(&fs.root_store(), object_id).await.expect("open failed");
3705 let (object_id, object_descriptor) =
3706 dir.lookup("foo").await.expect("lookup failed").expect("not found");
3707 assert_eq!(object_descriptor, ObjectDescriptor::Directory);
3708 let child_dir =
3709 Directory::open(&fs.root_store(), object_id).await.expect("open failed");
3710 assert!(!child_dir.casefold());
3711 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_none());
3712 let (object_id, descriptor) =
3713 child_dir.lookup("bAr").await.expect("lookup failed").unwrap();
3714 assert_eq!(descriptor, ObjectDescriptor::File);
3715
3716 child_dir.set_casefold(true).await.expect_err("not empty");
3718
3719 let mut transaction = fs
3721 .clone()
3722 .new_transaction(
3723 lock_keys![
3724 LockKey::object(fs.root_store().store_object_id(), child_dir.object_id()),
3725 LockKey::object(fs.root_store().store_object_id(), object_id),
3726 ],
3727 Options::default(),
3728 )
3729 .await
3730 .expect("new_transaction failed");
3731 assert_matches!(
3732 replace_child(&mut transaction, None, (&child_dir, "bAr"))
3733 .await
3734 .expect("replace_child failed"),
3735 ReplacedChild::Object(..)
3736 );
3737 transaction.commit().await.expect("commit failed");
3738
3739 child_dir.set_casefold(true).await.expect("set casefold");
3741
3742 assert!(child_dir.casefold());
3743
3744 let mut transaction = fs
3746 .clone()
3747 .new_transaction(
3748 lock_keys![LockKey::object(
3749 fs.root_store().store_object_id(),
3750 child_dir.object_id()
3751 ),],
3752 Options::default(),
3753 )
3754 .await
3755 .expect("new_transaction failed");
3756 let _child_dir_file = child_dir
3757 .create_child_file(&mut transaction, "bAr")
3758 .await
3759 .expect("create_child_file failed");
3760 transaction.commit().await.expect("commit failed");
3761
3762 assert!(child_dir.lookup("BAR").await.expect("lookup failed").is_some());
3764 assert!(child_dir.lookup("bAr").await.expect("lookup failed").is_some());
3765
3766 child_dir.set_casefold(true).await.expect_err("set casefold");
3768 assert!(child_dir.casefold());
3769
3770 let mut transaction = fs
3772 .clone()
3773 .new_transaction(
3774 lock_keys![LockKey::object(
3775 fs.root_store().store_object_id(),
3776 child_dir.object_id()
3777 ),],
3778 Options::default(),
3779 )
3780 .await
3781 .expect("new_transaction failed");
3782 let sub_dir = child_dir
3783 .create_child_dir(&mut transaction, "sub")
3784 .await
3785 .expect("create_sub_dir failed");
3786 transaction.commit().await.expect("commit failed");
3787 assert!(sub_dir.casefold());
3788 };
3789 fs.close().await.expect("Close failed");
3790 }
3791
3792 #[fuchsia::test]
3793 async fn test_create_casefold_encrypted_directory() {
3794 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3795 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3796 let synthetic_filename: SyntheticFilename;
3797 let object_id;
3798 {
3799 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3800 let root_volume = root_volume(fs.clone()).await.unwrap();
3801 let store = root_volume.new_volume("vol", NO_OWNER, Some(crypt.clone())).await.unwrap();
3802
3803 let wrapping_key_id = 2;
3805 crypt.add_wrapping_key(wrapping_key_id, [1; 32]);
3806
3807 object_id = {
3808 let mut transaction = fs
3809 .clone()
3810 .new_transaction(
3811 lock_keys![LockKey::object(
3812 fs.root_store().store_object_id(),
3813 store.store_object_id()
3814 ),],
3815 Options::default(),
3816 )
3817 .await
3818 .expect("new_transaction failed");
3819 let dir = Directory::create(&mut transaction, &store, Some(wrapping_key_id))
3820 .await
3821 .expect("create failed");
3822
3823 transaction.commit().await.expect("commit");
3824 dir.object_id()
3825 };
3826 let dir = Directory::open(&store, object_id).await.expect("open failed");
3827
3828 dir.set_casefold(true).await.expect("set casefold");
3829 assert!(dir.casefold());
3830
3831 let mut transaction = fs
3832 .clone()
3833 .new_transaction(
3834 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
3835 Options::default(),
3836 )
3837 .await
3838 .expect("new_transaction failed");
3839 let _file = dir
3840 .create_child_file(&mut transaction, "bAr")
3841 .await
3842 .expect("create_child_file failed");
3843 transaction.commit().await.expect("commit failed");
3844
3845 assert!(dir.lookup("bAr").await.expect("original lookup failed").is_some());
3847
3848 let key = dir.get_fscrypt_key().await.expect("key").unwrap();
3851 let casefold_hash = get_casefold_hash(Some(&key), "bAr", true);
3852 let encrypted_name =
3853 encrypt_filename(&key, dir.object_id(), "bAr").expect("encrypt_filename");
3854 synthetic_filename = SyntheticFilename::from_object_key(casefold_hash, &encrypted_name);
3855
3856 assert!(dir.lookup("BAR").await.expect("casefold lookup failed").is_some());
3858
3859 assert_eq!(get_casefold_hash(Some(&key), "bar", true), 3080479075);
3862 assert_eq!(get_casefold_hash(Some(&key), "BaR", true), 3080479075);
3863
3864 let mut count = 0;
3867 let layer_set = dir.store().tree().layer_set();
3868 let mut merger = layer_set.merger();
3869 let mut iter = dir.iter_from(&mut merger, "").await.expect("iter");
3870 while let Some(_entry) = iter.get() {
3871 count += 1;
3872 iter.advance().await.expect("advance");
3873 }
3874 assert_eq!(1, count, "unexpected number of entries.");
3875
3876 fs.close().await.expect("Close failed");
3877 }
3878
3879 let device = fs.take_device().await;
3880
3881 device.reopen(false);
3884 let fs = FxFilesystem::open(device).await.expect("open failed");
3885 {
3886 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3887 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
3888 let store = root_volume
3889 .volume("vol", NO_OWNER, Some(crypt.clone()))
3890 .await
3891 .expect("volume failed");
3892 let dir = Directory::open(&store, object_id).await.expect("open failed");
3893 assert!(dir.casefold());
3894
3895 assert!(dir.lookup("bAr").await.expect("lookup failed").is_none());
3897 assert!(dir
3899 .lookup(&synthetic_filename.encode())
3900 .await
3901 .expect("lookup failed")
3902 .is_some());
3903
3904 let layer_set = dir.store().tree().layer_set();
3905 let mut merger = layer_set.merger();
3906 let mut iter = dir.iter_from(&mut merger, "").await.expect("iter");
3907 let item = iter.get().expect("expect item");
3908 assert_eq!(item.0, synthetic_filename.encode().as_str());
3909 iter.advance().await.expect("advance");
3910 assert_eq!(None, iter.get());
3911
3912 crate::fsck::fsck(fs.clone()).await.unwrap();
3913 crate::fsck::fsck_volume(fs.as_ref(), store.store_object_id(), Some(crypt.clone()))
3914 .await
3915 .unwrap();
3916
3917 fs.close().await.expect("Close failed");
3918 }
3919 }
3920
3921 #[allow(dead_code)]
3932 fn find_out_of_order_raw_hash_long_prefix_pair(
3933 object_id: u64,
3934 key: &fxfs_crypto::Key,
3935 ) -> Option<[String; 2]> {
3936 let mut collision_map: std::collections::HashMap<u32, (usize, SyntheticFilename, Vec<u8>)> =
3937 std::collections::HashMap::new();
3938 for i in 0..(1usize << 32) {
3939 let filename = format!("0123456789abcdef0123456789abcdef0123456789abcdef_{i}");
3940 let casefold_hash = get_casefold_hash(Some(&key), &filename, true);
3941 let encrypted_name =
3942 encrypt_filename(&key, object_id, &filename).expect("encrypt_filename");
3943 let a = SyntheticFilename::from_object_key(casefold_hash, &encrypted_name);
3944 let casefold_hash = a.casefold_hash;
3945 if let Some((j, b, b_encrypted_name)) = collision_map.get(&casefold_hash) {
3946 assert_eq!(a.raw_prefix, b.raw_prefix);
3947 if encrypted_name.cmp(b_encrypted_name) != a.raw_hash.cmp(&b.raw_hash) {
3948 return Some([
3949 format!("0123456789abcdef0123456789abcdef0123456789abcdef_{i}"),
3950 format!("0123456789abcdef0123456789abcdef0123456789abcdef_{j}"),
3951 ]);
3952 }
3953 } else {
3954 collision_map.insert(casefold_hash, (i, a, encrypted_name));
3955 }
3956 }
3957 None
3958 }
3959
3960 #[fuchsia::test]
3961 async fn test_synthetic_filenames() {
3962 let device = DeviceHolder::new(FakeDevice::new(8192, TEST_DEVICE_BLOCK_SIZE));
3963 let fs = FxFilesystem::new_empty(device).await.expect("new_empty failed");
3964 let mut filenames = Vec::new();
3965 let object_id;
3966 {
3967 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
3968 let root_volume = root_volume(fs.clone()).await.unwrap();
3969 let store = root_volume.new_volume("vol", NO_OWNER, Some(crypt.clone())).await.unwrap();
3970
3971 let wrapping_key_id = 2;
3973 crypt.add_wrapping_key(wrapping_key_id, [1; 32]);
3974
3975 object_id = {
3976 let mut transaction = fs
3977 .clone()
3978 .new_transaction(
3979 lock_keys![LockKey::object(
3980 fs.root_store().store_object_id(),
3981 store.store_object_id()
3982 ),],
3983 Options::default(),
3984 )
3985 .await
3986 .expect("new_transaction failed");
3987 let dir = Directory::create(&mut transaction, &store, Some(wrapping_key_id))
3988 .await
3989 .expect("create failed");
3990
3991 transaction.commit().await.expect("commit");
3992 dir.object_id()
3993 };
3994 let dir = Directory::open(&store, object_id).await.expect("open failed");
3995
3996 dir.set_casefold(true).await.expect("set casefold");
3997 assert!(dir.casefold());
3998
3999 let mut transaction = fs
4000 .clone()
4001 .new_transaction(
4002 lock_keys![LockKey::object(store.store_object_id(), dir.object_id()),],
4003 Options::default(),
4004 )
4005 .await
4006 .expect("new_transaction failed");
4007 let key = dir.get_fscrypt_key().await.expect("key").unwrap();
4008
4009 let collision_pair = [
4019 "0123456789abcdef0123456789abcdef0123456789abcdef_4704261".to_string(),
4020 "0123456789abcdef0123456789abcdef0123456789abcdef_27996".to_string(),
4021 ];
4022 for filename in (0..64)
4025 .into_iter()
4026 .map(|i| format!("0123456789abcdef0123456789abcdef0123456789abcdef_{i}"))
4027 .chain(collision_pair.into_iter())
4028 {
4029 let casefold_hash = get_casefold_hash(Some(&key), &filename, true);
4030 let encrypted_name =
4031 encrypt_filename(&key, dir.object_id(), &filename).expect("encrypt_filename");
4032 let synthetic = SyntheticFilename::from_object_key(casefold_hash, &encrypted_name);
4033 let file = dir
4034 .create_child_file(&mut transaction, &filename)
4035 .await
4036 .expect("create_child_file failed");
4037 filenames.push((synthetic, file.object_id()));
4038 }
4039 transaction.commit().await.expect("commit failed");
4040
4041 fs.close().await.expect("Close failed");
4042 }
4043
4044 let device = fs.take_device().await;
4045
4046 device.reopen(false);
4048 let fs = FxFilesystem::open(device).await.expect("open failed");
4049 {
4050 let crypt: Arc<InsecureCrypt> = Arc::new(InsecureCrypt::new());
4051 let root_volume = root_volume(fs.clone()).await.expect("root_volume failed");
4052 let store = root_volume
4053 .volume("vol", NO_OWNER, Some(crypt.clone()))
4054 .await
4055 .expect("volume failed");
4056 let dir = Directory::open(&store, object_id).await.expect("open failed");
4057 assert!(dir.casefold());
4058
4059 assert_eq!(
4061 filenames.iter().map(|(name, _)| name.encode()).collect::<HashSet<_>>().len(),
4062 filenames.len()
4063 );
4064
4065 let raw_prefix = filenames[0].0.raw_prefix.clone();
4066 for (synthetic_filename, object_id) in &filenames {
4067 assert_eq!(raw_prefix, synthetic_filename.raw_prefix);
4069
4070 let item = dir
4071 .lookup(&synthetic_filename.encode())
4072 .await
4073 .expect("lookup failed")
4074 .expect("lookup is not None");
4075 assert_eq!(item.0, *object_id, "Mismatch for filename '{synthetic_filename:?}'");
4076
4077 let layer_set = dir.store().tree().layer_set();
4079 let mut merger = layer_set.merger();
4080 let iter =
4081 dir.iter_from(&mut merger, &synthetic_filename.encode()).await.expect("iter");
4082 let item = iter.get().expect("expect item");
4083 assert_eq!(item.0, synthetic_filename.encode().as_str());
4084 assert_eq!(item.1, *object_id);
4085 }
4086
4087 fs.close().await.expect("Close failed");
4088 }
4089 }
4090}