Skip to main content

starnix_core/vfs/
anon_node.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::security;
6use crate::task::{CurrentTask, Kernel};
7use crate::vfs::{
8    CacheMode, FileHandle, FileObject, FileOps, FileSystem, FileSystemHandle, FileSystemOps,
9    FileSystemOptions, FsNode, FsNodeInfo, FsNodeOps, FsStr, FsString, fs_node_impl_not_dir,
10};
11use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked};
12use starnix_types::vfs::default_statfs;
13use starnix_uapi::errors::Errno;
14use starnix_uapi::file_mode::FileMode;
15use starnix_uapi::open_flags::OpenFlags;
16use starnix_uapi::{ANON_INODE_FS_MAGIC, error, statfs};
17
18pub struct Anon {
19    /// If this instance represents an `anon_inode` then `name` holds the type-name of the node,
20    /// e.g. "inotify", "sync_file", "[usereventfd]", etc.
21    name: Option<&'static str>,
22
23    is_private: bool,
24}
25
26impl FsNodeOps for Anon {
27    fs_node_impl_not_dir!();
28
29    fn create_file_ops(
30        &self,
31        _locked: &mut Locked<FileOpsCore>,
32        _node: &FsNode,
33        _current_task: &CurrentTask,
34        _flags: OpenFlags,
35    ) -> Result<Box<dyn FileOps>, Errno> {
36        error!(ENOSYS)
37    }
38
39    fn internal_name(&self, _node: &FsNode) -> Option<FsString> {
40        self.name.map(|name| format!("anon_inode:{}", name).into())
41    }
42
43    fn is_private(&self) -> bool {
44        self.is_private
45    }
46}
47
48impl Anon {
49    /// Returns a new `Anon` instance for use in a binder device FD.
50    pub fn new_for_binder_device() -> Self {
51        Self { name: None, is_private: false }
52    }
53
54    /// Returns a new `Anon` instance for use as the `FsNodeOps` of a socket.
55    pub fn new_for_socket(kernel_private: bool) -> Self {
56        Self { name: None, is_private: kernel_private }
57    }
58
59    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
60    pub fn new_file_extended<L>(
61        locked: &mut Locked<L>,
62        current_task: &CurrentTask,
63        ops: Box<dyn FileOps>,
64        flags: OpenFlags,
65        name: &'static str,
66        info: FsNodeInfo,
67    ) -> Result<FileHandle, Errno>
68    where
69        L: LockEqualOrBefore<FileOpsCore>,
70    {
71        let fs = anon_fs(locked, current_task.kernel());
72        let node =
73            fs.create_node_and_allocate_node_id(Anon { name: Some(name), is_private: false }, info);
74        security::fs_node_init_anon(current_task, &node, name)?;
75        Ok(FileObject::new_anonymous(locked, current_task, ops, node, flags))
76    }
77
78    /// Returns a new anonymous file with the specified properties, and a unique `FsNode`.
79    pub fn new_file<L>(
80        locked: &mut Locked<L>,
81        current_task: &CurrentTask,
82        ops: Box<dyn FileOps>,
83        flags: OpenFlags,
84        name: &'static str,
85    ) -> Result<FileHandle, Errno>
86    where
87        L: LockEqualOrBefore<FileOpsCore>,
88    {
89        Self::new_file_extended(
90            locked,
91            current_task,
92            ops,
93            flags,
94            name,
95            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
96        )
97    }
98
99    /// Returns a new anonymous file backed by a single "private" `FsNode`, to which no security
100    /// labeling nor access-checks will be applied.
101    pub fn new_private_file<L>(
102        locked: &mut Locked<L>,
103        current_task: &CurrentTask,
104        ops: Box<dyn FileOps>,
105        flags: OpenFlags,
106        name: &'static str,
107    ) -> FileHandle
108    where
109        L: LockEqualOrBefore<FileOpsCore>,
110    {
111        Self::new_private_file_extended(
112            locked,
113            current_task,
114            ops,
115            flags,
116            name,
117            FsNodeInfo::new(FileMode::from_bits(0o600), current_task.current_fscred()),
118        )
119    }
120
121    /// Returns a new private anonymous file, applying caller-supplied `info`.
122    pub fn new_private_file_extended<L>(
123        locked: &mut Locked<L>,
124        current_task: &CurrentTask,
125        ops: Box<dyn FileOps>,
126        flags: OpenFlags,
127        name: &'static str,
128        info: FsNodeInfo,
129    ) -> FileHandle
130    where
131        L: LockEqualOrBefore<FileOpsCore>,
132    {
133        let fs = anon_fs(locked, current_task.kernel());
134        let node =
135            fs.create_node_and_allocate_node_id(Anon { name: Some(name), is_private: true }, info);
136        security::fs_node_init_anon(current_task, &node, name)
137            .expect("Private anon_inode creation cannot fail");
138        FileObject::new_anonymous(locked, current_task, ops, node, flags)
139    }
140}
141
142struct AnonFs;
143impl FileSystemOps for AnonFs {
144    fn statfs(
145        &self,
146        _locked: &mut Locked<FileOpsCore>,
147        _fs: &FileSystem,
148        _current_task: &CurrentTask,
149    ) -> Result<statfs, Errno> {
150        Ok(default_statfs(ANON_INODE_FS_MAGIC))
151    }
152    fn name(&self) -> &'static FsStr {
153        "anon_inodefs".into()
154    }
155}
156pub fn anon_fs<L>(locked: &mut Locked<L>, kernel: &Kernel) -> FileSystemHandle
157where
158    L: LockEqualOrBefore<FileOpsCore>,
159{
160    struct AnonFsHandle(FileSystemHandle);
161
162    kernel
163        .expando
164        .get_or_init(|| {
165            let fs = FileSystem::new(
166                locked,
167                kernel,
168                CacheMode::Uncached,
169                AnonFs,
170                FileSystemOptions::default(),
171            )
172            .expect("anonfs constructed with valid options");
173            AnonFsHandle(fs)
174        })
175        .0
176        .clone()
177}