1 //! Types for working with [`File`]. 2 //! 3 //! [`File`]: File 4 5 use self::State::*; 6 use crate::fs::asyncify; 7 use crate::io::blocking::Buf; 8 use crate::io::{AsyncRead, AsyncSeek, AsyncWrite, ReadBuf}; 9 use crate::sync::Mutex; 10 11 use std::fmt; 12 use std::fs::{Metadata, Permissions}; 13 use std::future::Future; 14 use std::io::{self, Seek, SeekFrom}; 15 use std::path::Path; 16 use std::pin::Pin; 17 use std::sync::Arc; 18 use std::task::Context; 19 use std::task::Poll; 20 use std::task::Poll::*; 21 22 #[cfg(test)] 23 use super::mocks::JoinHandle; 24 #[cfg(test)] 25 use super::mocks::MockFile as StdFile; 26 #[cfg(test)] 27 use super::mocks::{spawn_blocking, spawn_mandatory_blocking}; 28 #[cfg(not(test))] 29 use crate::blocking::JoinHandle; 30 #[cfg(not(test))] 31 use crate::blocking::{spawn_blocking, spawn_mandatory_blocking}; 32 #[cfg(not(test))] 33 use std::fs::File as StdFile; 34 35 /// A reference to an open file on the filesystem. 36 /// 37 /// This is a specialized version of [`std::fs::File`][std] for usage from the 38 /// Tokio runtime. 39 /// 40 /// An instance of a `File` can be read and/or written depending on what options 41 /// it was opened with. Files also implement [`AsyncSeek`] to alter the logical 42 /// cursor that the file contains internally. 43 /// 44 /// A file will not be closed immediately when it goes out of scope if there 45 /// are any IO operations that have not yet completed. To ensure that a file is 46 /// closed immediately when it is dropped, you should call [`flush`] before 47 /// dropping it. Note that this does not ensure that the file has been fully 48 /// written to disk; the operating system might keep the changes around in an 49 /// in-memory buffer. See the [`sync_all`] method for telling the OS to write 50 /// the data to disk. 51 /// 52 /// Reading and writing to a `File` is usually done using the convenience 53 /// methods found on the [`AsyncReadExt`] and [`AsyncWriteExt`] traits. 54 /// 55 /// [std]: struct@std::fs::File 56 /// [`AsyncSeek`]: trait@crate::io::AsyncSeek 57 /// [`flush`]: fn@crate::io::AsyncWriteExt::flush 58 /// [`sync_all`]: fn@crate::fs::File::sync_all 59 /// [`AsyncReadExt`]: trait@crate::io::AsyncReadExt 60 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt 61 /// 62 /// # Examples 63 /// 64 /// Create a new file and asynchronously write bytes to it: 65 /// 66 /// ```no_run 67 /// use tokio::fs::File; 68 /// use tokio::io::AsyncWriteExt; // for write_all() 69 /// 70 /// # async fn dox() -> std::io::Result<()> { 71 /// let mut file = File::create("foo.txt").await?; 72 /// file.write_all(b"hello, world!").await?; 73 /// # Ok(()) 74 /// # } 75 /// ``` 76 /// 77 /// Read the contents of a file into a buffer: 78 /// 79 /// ```no_run 80 /// use tokio::fs::File; 81 /// use tokio::io::AsyncReadExt; // for read_to_end() 82 /// 83 /// # async fn dox() -> std::io::Result<()> { 84 /// let mut file = File::open("foo.txt").await?; 85 /// 86 /// let mut contents = vec![]; 87 /// file.read_to_end(&mut contents).await?; 88 /// 89 /// println!("len = {}", contents.len()); 90 /// # Ok(()) 91 /// # } 92 /// ``` 93 pub struct File { 94 std: Arc<StdFile>, 95 inner: Mutex<Inner>, 96 } 97 98 struct Inner { 99 state: State, 100 101 /// Errors from writes/flushes are returned in write/flush calls. If a write 102 /// error is observed while performing a read, it is saved until the next 103 /// write / flush call. 104 last_write_err: Option<io::ErrorKind>, 105 106 pos: u64, 107 } 108 109 #[derive(Debug)] 110 enum State { 111 Idle(Option<Buf>), 112 Busy(JoinHandle<(Operation, Buf)>), 113 } 114 115 #[derive(Debug)] 116 enum Operation { 117 Read(io::Result<usize>), 118 Write(io::Result<()>), 119 Seek(io::Result<u64>), 120 } 121 122 impl File { 123 /// Attempts to open a file in read-only mode. 124 /// 125 /// See [`OpenOptions`] for more details. 126 /// 127 /// [`OpenOptions`]: super::OpenOptions 128 /// 129 /// # Errors 130 /// 131 /// This function will return an error if called from outside of the Tokio 132 /// runtime or if path does not already exist. Other errors may also be 133 /// returned according to OpenOptions::open. 134 /// 135 /// # Examples 136 /// 137 /// ```no_run 138 /// use tokio::fs::File; 139 /// use tokio::io::AsyncReadExt; 140 /// 141 /// # async fn dox() -> std::io::Result<()> { 142 /// let mut file = File::open("foo.txt").await?; 143 /// 144 /// let mut contents = vec![]; 145 /// file.read_to_end(&mut contents).await?; 146 /// 147 /// println!("len = {}", contents.len()); 148 /// # Ok(()) 149 /// # } 150 /// ``` 151 /// 152 /// The [`read_to_end`] method is defined on the [`AsyncReadExt`] trait. 153 /// 154 /// [`read_to_end`]: fn@crate::io::AsyncReadExt::read_to_end 155 /// [`AsyncReadExt`]: trait@crate::io::AsyncReadExt open(path: impl AsRef<Path>) -> io::Result<File>156 pub async fn open(path: impl AsRef<Path>) -> io::Result<File> { 157 let path = path.as_ref().to_owned(); 158 let std = asyncify(|| StdFile::open(path)).await?; 159 160 Ok(File::from_std(std)) 161 } 162 163 /// Opens a file in write-only mode. 164 /// 165 /// This function will create a file if it does not exist, and will truncate 166 /// it if it does. 167 /// 168 /// See [`OpenOptions`] for more details. 169 /// 170 /// [`OpenOptions`]: super::OpenOptions 171 /// 172 /// # Errors 173 /// 174 /// Results in an error if called from outside of the Tokio runtime or if 175 /// the underlying [`create`] call results in an error. 176 /// 177 /// [`create`]: std::fs::File::create 178 /// 179 /// # Examples 180 /// 181 /// ```no_run 182 /// use tokio::fs::File; 183 /// use tokio::io::AsyncWriteExt; 184 /// 185 /// # async fn dox() -> std::io::Result<()> { 186 /// let mut file = File::create("foo.txt").await?; 187 /// file.write_all(b"hello, world!").await?; 188 /// # Ok(()) 189 /// # } 190 /// ``` 191 /// 192 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 193 /// 194 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 195 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt create(path: impl AsRef<Path>) -> io::Result<File>196 pub async fn create(path: impl AsRef<Path>) -> io::Result<File> { 197 let path = path.as_ref().to_owned(); 198 let std_file = asyncify(move || StdFile::create(path)).await?; 199 Ok(File::from_std(std_file)) 200 } 201 202 /// Converts a [`std::fs::File`][std] to a [`tokio::fs::File`][file]. 203 /// 204 /// [std]: std::fs::File 205 /// [file]: File 206 /// 207 /// # Examples 208 /// 209 /// ```no_run 210 /// // This line could block. It is not recommended to do this on the Tokio 211 /// // runtime. 212 /// let std_file = std::fs::File::open("foo.txt").unwrap(); 213 /// let file = tokio::fs::File::from_std(std_file); 214 /// ``` from_std(std: StdFile) -> File215 pub fn from_std(std: StdFile) -> File { 216 File { 217 std: Arc::new(std), 218 inner: Mutex::new(Inner { 219 state: State::Idle(Some(Buf::with_capacity(0))), 220 last_write_err: None, 221 pos: 0, 222 }), 223 } 224 } 225 226 /// Attempts to sync all OS-internal metadata to disk. 227 /// 228 /// This function will attempt to ensure that all in-core data reaches the 229 /// filesystem before returning. 230 /// 231 /// # Examples 232 /// 233 /// ```no_run 234 /// use tokio::fs::File; 235 /// use tokio::io::AsyncWriteExt; 236 /// 237 /// # async fn dox() -> std::io::Result<()> { 238 /// let mut file = File::create("foo.txt").await?; 239 /// file.write_all(b"hello, world!").await?; 240 /// file.sync_all().await?; 241 /// # Ok(()) 242 /// # } 243 /// ``` 244 /// 245 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 246 /// 247 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 248 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt sync_all(&self) -> io::Result<()>249 pub async fn sync_all(&self) -> io::Result<()> { 250 let mut inner = self.inner.lock().await; 251 inner.complete_inflight().await; 252 253 let std = self.std.clone(); 254 asyncify(move || std.sync_all()).await 255 } 256 257 /// This function is similar to `sync_all`, except that it may not 258 /// synchronize file metadata to the filesystem. 259 /// 260 /// This is intended for use cases that must synchronize content, but don't 261 /// need the metadata on disk. The goal of this method is to reduce disk 262 /// operations. 263 /// 264 /// Note that some platforms may simply implement this in terms of `sync_all`. 265 /// 266 /// # Examples 267 /// 268 /// ```no_run 269 /// use tokio::fs::File; 270 /// use tokio::io::AsyncWriteExt; 271 /// 272 /// # async fn dox() -> std::io::Result<()> { 273 /// let mut file = File::create("foo.txt").await?; 274 /// file.write_all(b"hello, world!").await?; 275 /// file.sync_data().await?; 276 /// # Ok(()) 277 /// # } 278 /// ``` 279 /// 280 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 281 /// 282 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 283 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt sync_data(&self) -> io::Result<()>284 pub async fn sync_data(&self) -> io::Result<()> { 285 let mut inner = self.inner.lock().await; 286 inner.complete_inflight().await; 287 288 let std = self.std.clone(); 289 asyncify(move || std.sync_data()).await 290 } 291 292 /// Truncates or extends the underlying file, updating the size of this file to become size. 293 /// 294 /// If the size is less than the current file's size, then the file will be 295 /// shrunk. If it is greater than the current file's size, then the file 296 /// will be extended to size and have all of the intermediate data filled in 297 /// with 0s. 298 /// 299 /// # Errors 300 /// 301 /// This function will return an error if the file is not opened for 302 /// writing. 303 /// 304 /// # Examples 305 /// 306 /// ```no_run 307 /// use tokio::fs::File; 308 /// use tokio::io::AsyncWriteExt; 309 /// 310 /// # async fn dox() -> std::io::Result<()> { 311 /// let mut file = File::create("foo.txt").await?; 312 /// file.write_all(b"hello, world!").await?; 313 /// file.set_len(10).await?; 314 /// # Ok(()) 315 /// # } 316 /// ``` 317 /// 318 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 319 /// 320 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 321 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt set_len(&self, size: u64) -> io::Result<()>322 pub async fn set_len(&self, size: u64) -> io::Result<()> { 323 let mut inner = self.inner.lock().await; 324 inner.complete_inflight().await; 325 326 let mut buf = match inner.state { 327 Idle(ref mut buf_cell) => buf_cell.take().unwrap(), 328 _ => unreachable!(), 329 }; 330 331 let seek = if !buf.is_empty() { 332 Some(SeekFrom::Current(buf.discard_read())) 333 } else { 334 None 335 }; 336 337 let std = self.std.clone(); 338 339 inner.state = Busy(spawn_blocking(move || { 340 let res = if let Some(seek) = seek { 341 (&*std).seek(seek).and_then(|_| std.set_len(size)) 342 } else { 343 std.set_len(size) 344 } 345 .map(|_| 0); // the value is discarded later 346 347 // Return the result as a seek 348 (Operation::Seek(res), buf) 349 })); 350 351 let (op, buf) = match inner.state { 352 Idle(_) => unreachable!(), 353 Busy(ref mut rx) => rx.await?, 354 }; 355 356 inner.state = Idle(Some(buf)); 357 358 match op { 359 Operation::Seek(res) => res.map(|pos| { 360 inner.pos = pos; 361 }), 362 _ => unreachable!(), 363 } 364 } 365 366 /// Queries metadata about the underlying file. 367 /// 368 /// # Examples 369 /// 370 /// ```no_run 371 /// use tokio::fs::File; 372 /// 373 /// # async fn dox() -> std::io::Result<()> { 374 /// let file = File::open("foo.txt").await?; 375 /// let metadata = file.metadata().await?; 376 /// 377 /// println!("{:?}", metadata); 378 /// # Ok(()) 379 /// # } 380 /// ``` metadata(&self) -> io::Result<Metadata>381 pub async fn metadata(&self) -> io::Result<Metadata> { 382 let std = self.std.clone(); 383 asyncify(move || std.metadata()).await 384 } 385 386 /// Creates a new `File` instance that shares the same underlying file handle 387 /// as the existing `File` instance. Reads, writes, and seeks will affect both 388 /// File instances simultaneously. 389 /// 390 /// # Examples 391 /// 392 /// ```no_run 393 /// use tokio::fs::File; 394 /// 395 /// # async fn dox() -> std::io::Result<()> { 396 /// let file = File::open("foo.txt").await?; 397 /// let file_clone = file.try_clone().await?; 398 /// # Ok(()) 399 /// # } 400 /// ``` try_clone(&self) -> io::Result<File>401 pub async fn try_clone(&self) -> io::Result<File> { 402 let std = self.std.clone(); 403 let std_file = asyncify(move || std.try_clone()).await?; 404 Ok(File::from_std(std_file)) 405 } 406 407 /// Destructures `File` into a [`std::fs::File`][std]. This function is 408 /// async to allow any in-flight operations to complete. 409 /// 410 /// Use `File::try_into_std` to attempt conversion immediately. 411 /// 412 /// [std]: std::fs::File 413 /// 414 /// # Examples 415 /// 416 /// ```no_run 417 /// use tokio::fs::File; 418 /// 419 /// # async fn dox() -> std::io::Result<()> { 420 /// let tokio_file = File::open("foo.txt").await?; 421 /// let std_file = tokio_file.into_std().await; 422 /// # Ok(()) 423 /// # } 424 /// ``` into_std(mut self) -> StdFile425 pub async fn into_std(mut self) -> StdFile { 426 self.inner.get_mut().complete_inflight().await; 427 Arc::try_unwrap(self.std).expect("Arc::try_unwrap failed") 428 } 429 430 /// Tries to immediately destructure `File` into a [`std::fs::File`][std]. 431 /// 432 /// [std]: std::fs::File 433 /// 434 /// # Errors 435 /// 436 /// This function will return an error containing the file if some 437 /// operation is in-flight. 438 /// 439 /// # Examples 440 /// 441 /// ```no_run 442 /// use tokio::fs::File; 443 /// 444 /// # async fn dox() -> std::io::Result<()> { 445 /// let tokio_file = File::open("foo.txt").await?; 446 /// let std_file = tokio_file.try_into_std().unwrap(); 447 /// # Ok(()) 448 /// # } 449 /// ``` try_into_std(mut self) -> Result<StdFile, Self>450 pub fn try_into_std(mut self) -> Result<StdFile, Self> { 451 match Arc::try_unwrap(self.std) { 452 Ok(file) => Ok(file), 453 Err(std_file_arc) => { 454 self.std = std_file_arc; 455 Err(self) 456 } 457 } 458 } 459 460 /// Changes the permissions on the underlying file. 461 /// 462 /// # Platform-specific behavior 463 /// 464 /// This function currently corresponds to the `fchmod` function on Unix and 465 /// the `SetFileInformationByHandle` function on Windows. Note that, this 466 /// [may change in the future][changes]. 467 /// 468 /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior 469 /// 470 /// # Errors 471 /// 472 /// This function will return an error if the user lacks permission change 473 /// attributes on the underlying file. It may also return an error in other 474 /// os-specific unspecified cases. 475 /// 476 /// # Examples 477 /// 478 /// ```no_run 479 /// use tokio::fs::File; 480 /// 481 /// # async fn dox() -> std::io::Result<()> { 482 /// let file = File::open("foo.txt").await?; 483 /// let mut perms = file.metadata().await?.permissions(); 484 /// perms.set_readonly(true); 485 /// file.set_permissions(perms).await?; 486 /// # Ok(()) 487 /// # } 488 /// ``` set_permissions(&self, perm: Permissions) -> io::Result<()>489 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { 490 let std = self.std.clone(); 491 asyncify(move || std.set_permissions(perm)).await 492 } 493 } 494 495 impl AsyncRead for File { poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, dst: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>496 fn poll_read( 497 self: Pin<&mut Self>, 498 cx: &mut Context<'_>, 499 dst: &mut ReadBuf<'_>, 500 ) -> Poll<io::Result<()>> { 501 let me = self.get_mut(); 502 let inner = me.inner.get_mut(); 503 504 loop { 505 match inner.state { 506 Idle(ref mut buf_cell) => { 507 let mut buf = buf_cell.take().unwrap(); 508 509 if !buf.is_empty() { 510 buf.copy_to(dst); 511 *buf_cell = Some(buf); 512 return Ready(Ok(())); 513 } 514 515 buf.ensure_capacity_for(dst); 516 let std = me.std.clone(); 517 518 inner.state = Busy(spawn_blocking(move || { 519 let res = buf.read_from(&mut &*std); 520 (Operation::Read(res), buf) 521 })); 522 } 523 Busy(ref mut rx) => { 524 let (op, mut buf) = ready!(Pin::new(rx).poll(cx))?; 525 526 match op { 527 Operation::Read(Ok(_)) => { 528 buf.copy_to(dst); 529 inner.state = Idle(Some(buf)); 530 return Ready(Ok(())); 531 } 532 Operation::Read(Err(e)) => { 533 assert!(buf.is_empty()); 534 535 inner.state = Idle(Some(buf)); 536 return Ready(Err(e)); 537 } 538 Operation::Write(Ok(_)) => { 539 assert!(buf.is_empty()); 540 inner.state = Idle(Some(buf)); 541 continue; 542 } 543 Operation::Write(Err(e)) => { 544 assert!(inner.last_write_err.is_none()); 545 inner.last_write_err = Some(e.kind()); 546 inner.state = Idle(Some(buf)); 547 } 548 Operation::Seek(result) => { 549 assert!(buf.is_empty()); 550 inner.state = Idle(Some(buf)); 551 if let Ok(pos) = result { 552 inner.pos = pos; 553 } 554 continue; 555 } 556 } 557 } 558 } 559 } 560 } 561 } 562 563 impl AsyncSeek for File { start_seek(self: Pin<&mut Self>, mut pos: SeekFrom) -> io::Result<()>564 fn start_seek(self: Pin<&mut Self>, mut pos: SeekFrom) -> io::Result<()> { 565 let me = self.get_mut(); 566 let inner = me.inner.get_mut(); 567 568 match inner.state { 569 Busy(_) => Err(io::Error::new( 570 io::ErrorKind::Other, 571 "other file operation is pending, call poll_complete before start_seek", 572 )), 573 Idle(ref mut buf_cell) => { 574 let mut buf = buf_cell.take().unwrap(); 575 576 // Factor in any unread data from the buf 577 if !buf.is_empty() { 578 let n = buf.discard_read(); 579 580 if let SeekFrom::Current(ref mut offset) = pos { 581 *offset += n; 582 } 583 } 584 585 let std = me.std.clone(); 586 587 inner.state = Busy(spawn_blocking(move || { 588 let res = (&*std).seek(pos); 589 (Operation::Seek(res), buf) 590 })); 591 Ok(()) 592 } 593 } 594 } 595 poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>596 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> { 597 let inner = self.inner.get_mut(); 598 599 loop { 600 match inner.state { 601 Idle(_) => return Poll::Ready(Ok(inner.pos)), 602 Busy(ref mut rx) => { 603 let (op, buf) = ready!(Pin::new(rx).poll(cx))?; 604 inner.state = Idle(Some(buf)); 605 606 match op { 607 Operation::Read(_) => {} 608 Operation::Write(Err(e)) => { 609 assert!(inner.last_write_err.is_none()); 610 inner.last_write_err = Some(e.kind()); 611 } 612 Operation::Write(_) => {} 613 Operation::Seek(res) => { 614 if let Ok(pos) = res { 615 inner.pos = pos; 616 } 617 return Ready(res); 618 } 619 } 620 } 621 } 622 } 623 } 624 } 625 626 impl AsyncWrite for File { poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, src: &[u8], ) -> Poll<io::Result<usize>>627 fn poll_write( 628 self: Pin<&mut Self>, 629 cx: &mut Context<'_>, 630 src: &[u8], 631 ) -> Poll<io::Result<usize>> { 632 let me = self.get_mut(); 633 let inner = me.inner.get_mut(); 634 635 if let Some(e) = inner.last_write_err.take() { 636 return Ready(Err(e.into())); 637 } 638 639 loop { 640 match inner.state { 641 Idle(ref mut buf_cell) => { 642 let mut buf = buf_cell.take().unwrap(); 643 644 let seek = if !buf.is_empty() { 645 Some(SeekFrom::Current(buf.discard_read())) 646 } else { 647 None 648 }; 649 650 let n = buf.copy_from(src); 651 let std = me.std.clone(); 652 653 let blocking_task_join_handle = spawn_mandatory_blocking(move || { 654 let res = if let Some(seek) = seek { 655 (&*std).seek(seek).and_then(|_| buf.write_to(&mut &*std)) 656 } else { 657 buf.write_to(&mut &*std) 658 }; 659 660 (Operation::Write(res), buf) 661 }) 662 .ok_or_else(|| { 663 io::Error::new(io::ErrorKind::Other, "background task failed") 664 })?; 665 666 inner.state = Busy(blocking_task_join_handle); 667 668 return Ready(Ok(n)); 669 } 670 Busy(ref mut rx) => { 671 let (op, buf) = ready!(Pin::new(rx).poll(cx))?; 672 inner.state = Idle(Some(buf)); 673 674 match op { 675 Operation::Read(_) => { 676 // We don't care about the result here. The fact 677 // that the cursor has advanced will be reflected in 678 // the next iteration of the loop 679 continue; 680 } 681 Operation::Write(res) => { 682 // If the previous write was successful, continue. 683 // Otherwise, error. 684 res?; 685 continue; 686 } 687 Operation::Seek(_) => { 688 // Ignore the seek 689 continue; 690 } 691 } 692 } 693 } 694 } 695 } 696 poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>697 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 698 let inner = self.inner.get_mut(); 699 inner.poll_flush(cx) 700 } 701 poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>702 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 703 self.poll_flush(cx) 704 } 705 } 706 707 impl From<StdFile> for File { from(std: StdFile) -> Self708 fn from(std: StdFile) -> Self { 709 Self::from_std(std) 710 } 711 } 712 713 impl fmt::Debug for File { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result714 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 715 fmt.debug_struct("tokio::fs::File") 716 .field("std", &self.std) 717 .finish() 718 } 719 } 720 721 #[cfg(unix)] 722 impl std::os::unix::io::AsRawFd for File { as_raw_fd(&self) -> std::os::unix::io::RawFd723 fn as_raw_fd(&self) -> std::os::unix::io::RawFd { 724 self.std.as_raw_fd() 725 } 726 } 727 728 #[cfg(unix)] 729 impl std::os::unix::io::FromRawFd for File { from_raw_fd(fd: std::os::unix::io::RawFd) -> Self730 unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> Self { 731 StdFile::from_raw_fd(fd).into() 732 } 733 } 734 735 #[cfg(windows)] 736 impl std::os::windows::io::AsRawHandle for File { as_raw_handle(&self) -> std::os::windows::io::RawHandle737 fn as_raw_handle(&self) -> std::os::windows::io::RawHandle { 738 self.std.as_raw_handle() 739 } 740 } 741 742 #[cfg(windows)] 743 impl std::os::windows::io::FromRawHandle for File { from_raw_handle(handle: std::os::windows::io::RawHandle) -> Self744 unsafe fn from_raw_handle(handle: std::os::windows::io::RawHandle) -> Self { 745 StdFile::from_raw_handle(handle).into() 746 } 747 } 748 749 impl Inner { complete_inflight(&mut self)750 async fn complete_inflight(&mut self) { 751 use crate::future::poll_fn; 752 753 if let Err(e) = poll_fn(|cx| Pin::new(&mut *self).poll_flush(cx)).await { 754 self.last_write_err = Some(e.kind()); 755 } 756 } 757 poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>758 fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 759 if let Some(e) = self.last_write_err.take() { 760 return Ready(Err(e.into())); 761 } 762 763 let (op, buf) = match self.state { 764 Idle(_) => return Ready(Ok(())), 765 Busy(ref mut rx) => ready!(Pin::new(rx).poll(cx))?, 766 }; 767 768 // The buffer is not used here 769 self.state = Idle(Some(buf)); 770 771 match op { 772 Operation::Read(_) => Ready(Ok(())), 773 Operation::Write(res) => Ready(res), 774 Operation::Seek(_) => Ready(Ok(())), 775 } 776 } 777 } 778 779 #[cfg(test)] 780 mod tests; 781