fxfs/object_store/
directory.rs

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