1 // Copyright 2018 Google Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License.  You may obtain a copy
5 // of the License at:
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
12 // License for the specific language governing permissions and limitations
13 // under the License.
14 
15 extern crate fuse;
16 
17 use failure::Fallible;
18 use nix::errno;
19 use nodes::{
20     ArcHandle, ArcNode, AttrDelta, Cache, Handle, KernelError, Node, NodeResult, conv, setattr};
21 use std::ffi::OsStr;
22 use std::fs;
23 use std::os::unix::fs::FileExt;
24 use std::path::{Path, PathBuf};
25 use std::sync::{Arc, Mutex};
26 
27 /// Handle for an open file.
28 struct OpenFile {
29     /// Reference to the node's state for this file.  Needed to update attributes on writes.
30     state: Arc<Mutex<MutableFile>>,
31 
32     /// Handle for the open file descriptor.
33     file: fs::File,
34 }
35 
36 impl OpenFile {
37     /// Creates a new handle that references the given node's `state` and the already-open `file`.
from(state: Arc<Mutex<MutableFile>>, file: fs::File) -> OpenFile38     fn from(state: Arc<Mutex<MutableFile>>, file: fs::File) -> OpenFile {
39         Self { state, file }
40     }
41 }
42 
43 impl Handle for OpenFile {
read(&self, offset: i64, size: u32) -> NodeResult<Vec<u8>>44     fn read(&self, offset: i64, size: u32) -> NodeResult<Vec<u8>> {
45         let mut buffer = vec![0; size as usize];
46         let n = self.file.read_at(&mut buffer[..size as usize], offset as u64)?;
47         buffer.truncate(n);
48         Ok(buffer)
49     }
50 
write(&self, offset: i64, mut data: &[u8]) -> NodeResult<u32>51     fn write(&self, offset: i64, mut data: &[u8]) -> NodeResult<u32> {
52         const MAX_WRITE: usize = std::u32::MAX as usize;
53         if data.len() > MAX_WRITE {
54             // We only do this check because FUSE wants an u32 as the return value but data could
55             // theoretically be bigger.
56             // TODO(jmmv): Should fix the FUSE libraries to just expose Rust API-friendly quantities
57             // (usize in this case) and handle the kernel/Rust boundary internally.
58             warn!("Truncating too-long write to {} (asked for {} bytes)", MAX_WRITE, data.len());
59             data = &data[..MAX_WRITE];
60         }
61 
62         let mut state = self.state.lock().unwrap();
63 
64         let n = self.file.write_at(data, offset as u64)?;
65         debug_assert!(n <= MAX_WRITE, "Size bounds checked above");
66 
67         let new_size = (offset as u64) + (n as u64);
68         if state.attr.size < new_size {
69             state.attr.size = new_size;
70         }
71 
72         Ok(n as u32)
73     }
74 }
75 
76 /// Representation of a file node.
77 ///
78 /// File nodes represent all kinds of files (except for directories and symlinks), not just regular
79 /// files, because the set of node operations required by them is the same.
80 pub struct File {
81     inode: u64,
82     writable: bool,
83     state: Arc<Mutex<MutableFile>>,
84 }
85 
86 /// Holds the mutable data of a file node.
87 struct MutableFile {
88     underlying_path: Option<PathBuf>,
89     attr: fuse::FileAttr,
90 }
91 
92 impl File {
93     /// Returns true if this node can represent the given file type.
supports_type(t: fs::FileType) -> bool94     fn supports_type(t: fs::FileType) -> bool {
95         !t.is_dir() && !t.is_symlink()
96     }
97 
98     /// Creates a new file backed by a file on an underlying file system.
99     ///
100     /// `inode` is the node number to assign to the created in-memory file and has no relation
101     /// to the underlying file.  `underlying_path` indicates the path to the file outside
102     /// of the sandbox that backs this one.  `fs_attr` contains the stat data for the given path.
103     ///
104     /// `fs_attr` is an input parameter because, by the time we decide to instantiate a file
105     /// node (e.g. as we discover directory entries during readdir or lookup), we have already
106     /// issued a stat on the underlying file system and we cannot re-do it for efficiency reasons.
new_mapped(inode: u64, underlying_path: &Path, fs_attr: &fs::Metadata, writable: bool) -> ArcNode107     pub fn new_mapped(inode: u64, underlying_path: &Path, fs_attr: &fs::Metadata, writable: bool)
108         -> ArcNode {
109         if !File::supports_type(fs_attr.file_type()) {
110             panic!("Can only construct based on non-directories / non-symlinks");
111         }
112         let attr = conv::attr_fs_to_fuse(underlying_path, inode, 1, &fs_attr);
113 
114         let state = MutableFile {
115             underlying_path: Some(PathBuf::from(underlying_path)),
116             attr: attr,
117         };
118 
119         Arc::new(File { inode, writable, state: Arc::from(Mutex::from(state)) })
120     }
121 
122     /// Same as `getattr` but with the node already locked.
getattr_locked(inode: u64, state: &mut MutableFile) -> NodeResult<fuse::FileAttr>123     fn getattr_locked(inode: u64, state: &mut MutableFile) -> NodeResult<fuse::FileAttr> {
124         if let Some(path) = &state.underlying_path {
125             let fs_attr = fs::symlink_metadata(path)?;
126             if !File::supports_type(fs_attr.file_type()) {
127                 warn!("Path {} backing a file node is no longer a file; got {:?}",
128                     path.display(), fs_attr.file_type());
129                 return Err(KernelError::from_errno(errno::Errno::EIO));
130             }
131             state.attr = conv::attr_fs_to_fuse(path, inode, state.attr.nlink, &fs_attr);
132         }
133 
134         Ok(state.attr)
135     }
136 }
137 
138 impl Node for File {
inode(&self) -> u64139     fn inode(&self) -> u64 {
140         self.inode
141     }
142 
writable(&self) -> bool143     fn writable(&self) -> bool {
144         self.writable
145     }
146 
file_type_cached(&self) -> fuse::FileType147     fn file_type_cached(&self) -> fuse::FileType {
148         let state = self.state.lock().unwrap();
149         state.attr.kind
150     }
151 
delete(&self, cache: &dyn Cache)152     fn delete(&self, cache: &dyn Cache) {
153         let mut state = self.state.lock().unwrap();
154         assert!(
155             state.underlying_path.is_some(),
156             "Delete already called or trying to delete an explicit mapping");
157         cache.delete(state.underlying_path.as_ref().unwrap(), state.attr.kind);
158         state.underlying_path = None;
159         debug_assert!(state.attr.nlink >= 1);
160         state.attr.nlink -= 1;
161     }
162 
set_underlying_path(&self, path: &Path, cache: &dyn Cache)163     fn set_underlying_path(&self, path: &Path, cache: &dyn Cache) {
164         let mut state = self.state.lock().unwrap();
165         debug_assert!(state.underlying_path.is_some(),
166             "Renames should not have been allowed in scaffold or deleted nodes");
167         cache.rename(
168             state.underlying_path.as_ref().unwrap(), path.to_owned(), state.attr.kind);
169         state.underlying_path = Some(PathBuf::from(path));
170     }
171 
unmap(&self, inodes: &mut Vec<u64>) -> Fallible<()>172     fn unmap(&self, inodes: &mut Vec<u64>) -> Fallible<()> {
173         inodes.push(self.inode);
174         Ok(())
175     }
176 
getattr(&self) -> NodeResult<fuse::FileAttr>177     fn getattr(&self) -> NodeResult<fuse::FileAttr> {
178         let mut state = self.state.lock().unwrap();
179         File::getattr_locked(self.inode, &mut state)
180     }
181 
getxattr(&self, name: &OsStr) -> NodeResult<Option<Vec<u8>>>182     fn getxattr(&self, name: &OsStr) -> NodeResult<Option<Vec<u8>>> {
183         let state = self.state.lock().unwrap();
184         match &state.underlying_path {
185             Some(path) => Ok(xattr::get(path, name)?),
186             None => Ok(None),
187         }
188     }
189 
handle_from(&self, file: fs::File) -> ArcHandle190     fn handle_from(&self, file: fs::File) -> ArcHandle {
191         Arc::from(OpenFile::from(self.state.clone(), file))
192     }
193 
listxattr(&self) -> NodeResult<Option<xattr::XAttrs>>194     fn listxattr(&self) -> NodeResult<Option<xattr::XAttrs>> {
195         let state = self.state.lock().unwrap();
196         match &state.underlying_path {
197             Some(path) => Ok(Some(xattr::list(path)?)),
198             None => Ok(None),
199         }
200     }
201 
open(&self, flags: u32) -> NodeResult<ArcHandle>202     fn open(&self, flags: u32) -> NodeResult<ArcHandle> {
203         let state = self.state.lock().unwrap();
204 
205         let options = conv::flags_to_openoptions(flags, self.writable)?;
206         let path = state.underlying_path.as_ref().expect(
207             "Don't know how to handle a request to reopen a deleted file");
208         let file = options.open(&path)?;
209         Ok(Arc::from(OpenFile::from(self.state.clone(), file)))
210     }
211 
removexattr(&self, name: &OsStr) -> NodeResult<()>212     fn removexattr(&self, name: &OsStr) -> NodeResult<()> {
213         let state = self.state.lock().unwrap();
214         match &state.underlying_path {
215             Some(path) => Ok(xattr::remove(path, name)?),
216             None => Err(KernelError::from_errno(errno::Errno::EACCES)),
217         }
218     }
219 
setattr(&self, delta: &AttrDelta) -> NodeResult<fuse::FileAttr>220     fn setattr(&self, delta: &AttrDelta) -> NodeResult<fuse::FileAttr> {
221         let mut state = self.state.lock().unwrap();
222         state.attr = setattr(state.underlying_path.as_ref(), &state.attr, delta)?;
223         Ok(state.attr)
224     }
225 
setxattr(&self, name: &OsStr, value: &[u8]) -> NodeResult<()>226     fn setxattr(&self, name: &OsStr, value: &[u8]) -> NodeResult<()> {
227         let state = self.state.lock().unwrap();
228         match &state.underlying_path {
229             Some(path) => Ok(xattr::set(path, name, value)?),
230             None => Err(KernelError::from_errno(errno::Errno::EACCES)),
231         }
232     }
233 }
234