vfs/directory/
helper.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use crate::directory::entry::DirectoryEntry;
use crate::directory::entry_container::Directory;
use crate::name::Name;
use std::sync::Arc;
use thiserror::Error;
use zx_status::Status;

/// An entry with the same name already exists in the directory.
#[derive(Error, Debug)]
#[error("An entry with the same name already exists in the directory")]
pub struct AlreadyExists;

impl Into<Status> for AlreadyExists {
    fn into(self) -> Status {
        Status::ALREADY_EXISTS
    }
}

/// The entry identified by `name` is not a directory.
#[derive(Error, Debug)]
#[error("The specified entry is not a directory")]
pub struct NotDirectory;

impl Into<Status> for NotDirectory {
    fn into(self) -> Status {
        Status::NOT_DIR
    }
}

/// `DirectlyMutable` is a superset of `MutableDirectory` which also allows server-side management
/// of directory entries (via `add_entry` and `remove_entry`).
pub trait DirectlyMutable: Directory + Send + Sync {
    /// Adds a child entry to this directory.
    ///
    /// Possible errors are:
    ///   * `ZX_ERR_INVALID_ARGS` or `ZX_ERR_BAD_PATH` if `name` is not a valid [`Name`].
    ///   * `ZX_ERR_ALREADY_EXISTS` if an entry with the same name is already present in the
    ///     directory.
    fn add_entry<NameT>(&self, name: NameT, entry: Arc<dyn DirectoryEntry>) -> Result<(), Status>
    where
        NameT: Into<String>,
        Self: Sized,
    {
        self.add_entry_may_overwrite(name, entry, false)
    }

    /// Adds a child entry to this directory. If `overwrite` is true, this function may overwrite
    /// an existing entry.
    ///
    /// Possible errors are:
    ///   * `ZX_ERR_INVALID_ARGS` or `ZX_ERR_BAD_PATH` if `name` is not a valid [`Name`].
    ///   * `ZX_ERR_ALREADY_EXISTS` if an entry with the same name is already present in the
    ///     directory and `overwrite` is false.
    fn add_entry_may_overwrite<NameT>(
        &self,
        name: NameT,
        entry: Arc<dyn DirectoryEntry>,
        overwrite: bool,
    ) -> Result<(), Status>
    where
        NameT: Into<String>,
        Self: Sized,
    {
        let name: String = name.into();
        let name: Name = name.try_into()?;
        self.add_entry_impl(name, entry, overwrite)
            .map_err(|_: AlreadyExists| Status::ALREADY_EXISTS)
    }

    /// Adds a child entry to this directory.
    fn add_entry_impl(
        &self,
        name: Name,
        entry: Arc<dyn DirectoryEntry>,
        overwrite: bool,
    ) -> Result<(), AlreadyExists>;

    /// Removes a child entry from this directory.  In case an entry with the matching name was
    /// found, the entry will be returned to the caller.  If `must_be_directory` is true, an error
    /// is returned if the entry is not a directory.
    ///
    /// Possible errors are:
    ///   * `ZX_ERR_INVALID_ARGS` or `ZX_ERR_BAD_PATH` if `name` is not a valid [`Name`].
    ///   * `ZX_ERR_NOT_DIR` if the entry identified by `name` is not a directory and
    ///     `must_be_directory` is true.
    fn remove_entry<NameT>(
        &self,
        name: NameT,
        must_be_directory: bool,
    ) -> Result<Option<Arc<dyn DirectoryEntry>>, Status>
    where
        NameT: Into<String>,
        Self: Sized,
    {
        let name: String = name.into();
        let name: Name = name.try_into()?;
        let entry = self
            .remove_entry_impl(name, must_be_directory)
            .map_err(|_: NotDirectory| Status::NOT_DIR)?;
        Ok(entry)
    }

    /// Removes a child entry from this directory.  In case an entry with the matching name was
    /// found, the entry will be returned to the caller.
    fn remove_entry_impl(
        &self,
        name: Name,
        must_be_directory: bool,
    ) -> Result<Option<Arc<dyn DirectoryEntry>>, NotDirectory>;
}