Skip to main content

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