fxfs/object_store/
directory.rs

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