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