fxfs/object_store/
directory.rs

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