1 //! Types for working with [`File`]. 2 //! 3 //! [`File`]: file/struct.File.html 4 5 mod create; 6 mod metadata; 7 mod open; 8 mod open_options; 9 mod seek; 10 11 pub use self::create::CreateFuture; 12 pub use self::metadata::MetadataFuture; 13 pub use self::open::OpenFuture; 14 pub use self::open_options::OpenOptions; 15 pub use self::seek::SeekFuture; 16 17 use tokio_io::{AsyncRead, AsyncWrite}; 18 19 use futures::Poll; 20 21 use std::fs::{File as StdFile, Metadata, Permissions}; 22 use std::io::{self, Read, Write, Seek}; 23 use std::path::Path; 24 25 /// A reference to an open file on the filesystem. 26 /// 27 /// This is a specialized version of [`std::fs::File`][std] for usage from the 28 /// Tokio runtime. 29 /// 30 /// An instance of a `File` can be read and/or written depending on what options 31 /// it was opened with. Files also implement Seek to alter the logical cursor 32 /// that the file contains internally. 33 /// 34 /// Files are automatically closed when they go out of scope. 35 /// 36 /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html 37 #[derive(Debug)] 38 pub struct File { 39 std: Option<StdFile>, 40 } 41 42 impl File { 43 /// Attempts to open a file in read-only mode. 44 /// 45 /// See [`OpenOptions`] for more details. 46 /// 47 /// [`OpenOptions`]: struct.OpenOptions.html 48 /// 49 /// # Errors 50 /// 51 /// `OpenFuture` results in an error if called from outside of the Tokio 52 /// runtime or if the underlying [`open`] call results in an error. 53 /// 54 /// [`open`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.open open<P>(path: P) -> OpenFuture<P> where P: AsRef<Path> + Send + 'static,55 pub fn open<P>(path: P) -> OpenFuture<P> 56 where P: AsRef<Path> + Send + 'static, 57 { 58 OpenOptions::new().read(true).open(path) 59 } 60 61 /// Opens a file in write-only mode. 62 /// 63 /// This function will create a file if it does not exist, and will truncate 64 /// it if it does. 65 /// 66 /// See [`OpenOptions`] for more details. 67 /// 68 /// [`OpenOptions`]: struct.OpenOptions.html 69 /// 70 /// # Errors 71 /// 72 /// `CreateFuture` results in an error if called from outside of the Tokio 73 /// runtime or if the underlying [`create`] call results in an error. 74 /// 75 /// [`create`]: https://doc.rust-lang.org/std/fs/struct.File.html#method.create create<P>(path: P) -> CreateFuture<P> where P: AsRef<Path> + Send + 'static,76 pub fn create<P>(path: P) -> CreateFuture<P> 77 where P: AsRef<Path> + Send + 'static, 78 { 79 CreateFuture::new(path) 80 } 81 82 /// Convert a [`std::fs::File`][std] to a `tokio_fs::File`. 83 /// 84 /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html from_std(std: StdFile) -> File85 pub(crate) fn from_std(std: StdFile) -> File { 86 File { std: Some(std) } 87 } 88 89 /// Seek to an offset, in bytes, in a stream. 90 /// 91 /// A seek beyond the end of a stream is allowed, but implementation 92 /// defined. 93 /// 94 /// If the seek operation completed successfully, this method returns the 95 /// new position from the start of the stream. That position can be used 96 /// later with `SeekFrom::Start`. 97 /// 98 /// # Errors 99 /// 100 /// Seeking to a negative offset is considered an error. poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error>101 pub fn poll_seek(&mut self, pos: io::SeekFrom) -> Poll<u64, io::Error> { 102 ::blocking_io(|| self.std().seek(pos)) 103 } 104 105 /// Seek to an offset, in bytes, in a stream. 106 /// 107 /// Similar to `poll_seek`, but returning a `Future`. 108 /// 109 /// This method consumes the `File` and returns it back when the future 110 /// completes. seek(self, pos: io::SeekFrom) -> SeekFuture111 pub fn seek(self, pos: io::SeekFrom) -> SeekFuture { 112 SeekFuture::new(self, pos) 113 } 114 115 /// Attempts to sync all OS-internal metadata to disk. 116 /// 117 /// This function will attempt to ensure that all in-core data reaches the 118 /// filesystem before returning. poll_sync_all(&mut self) -> Poll<(), io::Error>119 pub fn poll_sync_all(&mut self) -> Poll<(), io::Error> { 120 ::blocking_io(|| self.std().sync_all()) 121 } 122 123 /// This function is similar to `poll_sync_all`, except that it may not 124 /// synchronize file metadata to the filesystem. 125 /// 126 /// This is intended for use cases that must synchronize content, but don't 127 /// need the metadata on disk. The goal of this method is to reduce disk 128 /// operations. 129 /// 130 /// Note that some platforms may simply implement this in terms of `poll_sync_all`. poll_sync_data(&mut self) -> Poll<(), io::Error>131 pub fn poll_sync_data(&mut self) -> Poll<(), io::Error> { 132 ::blocking_io(|| self.std().sync_data()) 133 } 134 135 /// Truncates or extends the underlying file, updating the size of this file to become size. 136 /// 137 /// If the size is less than the current file's size, then the file will be 138 /// shrunk. If it is greater than the current file's size, then the file 139 /// will be extended to size and have all of the intermediate data filled in 140 /// with 0s. 141 /// 142 /// # Errors 143 /// 144 /// This function will return an error if the file is not opened for 145 /// writing. poll_set_len(&mut self, size: u64) -> Poll<(), io::Error>146 pub fn poll_set_len(&mut self, size: u64) -> Poll<(), io::Error> { 147 ::blocking_io(|| self.std().set_len(size)) 148 } 149 150 /// Queries metadata about the underlying file. metadata(self) -> MetadataFuture151 pub fn metadata(self) -> MetadataFuture { 152 MetadataFuture::new(self) 153 } 154 155 /// Queries metadata about the underlying file. poll_metadata(&mut self) -> Poll<Metadata, io::Error>156 pub fn poll_metadata(&mut self) -> Poll<Metadata, io::Error> { 157 ::blocking_io(|| self.std().metadata()) 158 } 159 160 /// Create a new `File` instance that shares the same underlying file handle 161 /// as the existing `File` instance. Reads, writes, and seeks will affect both 162 /// File instances simultaneously. poll_try_clone(&mut self) -> Poll<File, io::Error>163 pub fn poll_try_clone(&mut self) -> Poll<File, io::Error> { 164 ::blocking_io(|| { 165 let std = self.std().try_clone()?; 166 Ok(File::from_std(std)) 167 }) 168 } 169 170 /// Changes the permissions on the underlying file. 171 /// 172 /// # Platform-specific behavior 173 /// 174 /// This function currently corresponds to the `fchmod` function on Unix and 175 /// the `SetFileInformationByHandle` function on Windows. Note that, this 176 /// [may change in the future][changes]. 177 /// 178 /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior 179 /// 180 /// # Errors 181 /// 182 /// This function will return an error if the user lacks permission change 183 /// attributes on the underlying file. It may also return an error in other 184 /// os-specific unspecified cases. poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error>185 pub fn poll_set_permissions(&mut self, perm: Permissions) -> Poll<(), io::Error> { 186 ::blocking_io(|| self.std().set_permissions(perm)) 187 } 188 189 /// Destructures the `tokio_fs::File` into a [`std::fs::File`][std]. 190 /// 191 /// # Panics 192 /// 193 /// This function will panic if `shutdown` has been called. 194 /// 195 /// [std]: https://doc.rust-lang.org/std/fs/struct.File.html into_std(mut self) -> StdFile196 pub fn into_std(mut self) -> StdFile { 197 self.std.take().expect("`File` instance already shutdown") 198 } 199 std(&mut self) -> &mut StdFile200 fn std(&mut self) -> &mut StdFile { 201 self.std.as_mut().expect("`File` instance already shutdown") 202 } 203 } 204 205 impl Read for File { read(&mut self, buf: &mut [u8]) -> io::Result<usize>206 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { 207 ::would_block(|| self.std().read(buf)) 208 } 209 } 210 211 impl AsyncRead for File { prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool212 unsafe fn prepare_uninitialized_buffer(&self, _: &mut [u8]) -> bool { 213 false 214 } 215 } 216 217 impl Write for File { write(&mut self, buf: &[u8]) -> io::Result<usize>218 fn write(&mut self, buf: &[u8]) -> io::Result<usize> { 219 ::would_block(|| self.std().write(buf)) 220 } 221 flush(&mut self) -> io::Result<()>222 fn flush(&mut self) -> io::Result<()> { 223 ::would_block(|| self.std().flush()) 224 } 225 } 226 227 impl AsyncWrite for File { shutdown(&mut self) -> Poll<(), io::Error>228 fn shutdown(&mut self) -> Poll<(), io::Error> { 229 ::blocking_io(|| { 230 self.std = None; 231 Ok(()) 232 }) 233 } 234 } 235 236 impl Drop for File { drop(&mut self)237 fn drop(&mut self) { 238 if let Some(_std) = self.std.take() { 239 // This is probably fine as closing a file *shouldn't* be a blocking 240 // operation. That said, ideally `shutdown` is called first. 241 } 242 } 243 } 244