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