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