1 //! Types for working with [`File`]. 2 //! 3 //! [`File`]: File 4 5 use self::State::*; 6 use crate::fs::{asyncify, OpenOptions}; 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 /// # Errors 128 /// 129 /// This function will return an error if called from outside of the Tokio 130 /// runtime or if path does not already exist. Other errors may also be 131 /// returned according to OpenOptions::open. 132 /// 133 /// # Examples 134 /// 135 /// ```no_run 136 /// use tokio::fs::File; 137 /// use tokio::io::AsyncReadExt; 138 /// 139 /// # async fn dox() -> std::io::Result<()> { 140 /// let mut file = File::open("foo.txt").await?; 141 /// 142 /// let mut contents = vec![]; 143 /// file.read_to_end(&mut contents).await?; 144 /// 145 /// println!("len = {}", contents.len()); 146 /// # Ok(()) 147 /// # } 148 /// ``` 149 /// 150 /// The [`read_to_end`] method is defined on the [`AsyncReadExt`] trait. 151 /// 152 /// [`read_to_end`]: fn@crate::io::AsyncReadExt::read_to_end 153 /// [`AsyncReadExt`]: trait@crate::io::AsyncReadExt open(path: impl AsRef<Path>) -> io::Result<File>154 pub async fn open(path: impl AsRef<Path>) -> io::Result<File> { 155 let path = path.as_ref().to_owned(); 156 let std = asyncify(|| StdFile::open(path)).await?; 157 158 Ok(File::from_std(std)) 159 } 160 161 /// Opens a file in write-only mode. 162 /// 163 /// This function will create a file if it does not exist, and will truncate 164 /// it if it does. 165 /// 166 /// See [`OpenOptions`] for more details. 167 /// 168 /// # Errors 169 /// 170 /// Results in an error if called from outside of the Tokio runtime or if 171 /// the underlying [`create`] call results in an error. 172 /// 173 /// [`create`]: std::fs::File::create 174 /// 175 /// # Examples 176 /// 177 /// ```no_run 178 /// use tokio::fs::File; 179 /// use tokio::io::AsyncWriteExt; 180 /// 181 /// # async fn dox() -> std::io::Result<()> { 182 /// let mut file = File::create("foo.txt").await?; 183 /// file.write_all(b"hello, world!").await?; 184 /// # Ok(()) 185 /// # } 186 /// ``` 187 /// 188 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 189 /// 190 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 191 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt create(path: impl AsRef<Path>) -> io::Result<File>192 pub async fn create(path: impl AsRef<Path>) -> io::Result<File> { 193 let path = path.as_ref().to_owned(); 194 let std_file = asyncify(move || StdFile::create(path)).await?; 195 Ok(File::from_std(std_file)) 196 } 197 198 /// Returns a new [`OpenOptions`] object. 199 /// 200 /// This function returns a new `OpenOptions` object that you can use to 201 /// open or create a file with specific options if `open()` or `create()` 202 /// are not appropriate. 203 /// 204 /// It is equivalent to `OpenOptions::new()`, but allows you to write more 205 /// readable code. Instead of 206 /// `OpenOptions::new().append(true).open("example.log")`, 207 /// you can write `File::options().append(true).open("example.log")`. This 208 /// also avoids the need to import `OpenOptions`. 209 /// 210 /// See the [`OpenOptions::new`] function for more details. 211 /// 212 /// # Examples 213 /// 214 /// ```no_run 215 /// use tokio::fs::File; 216 /// use tokio::io::AsyncWriteExt; 217 /// 218 /// # async fn dox() -> std::io::Result<()> { 219 /// let mut f = File::options().append(true).open("example.log").await?; 220 /// f.write_all(b"new line\n").await?; 221 /// # Ok(()) 222 /// # } 223 /// ``` 224 #[must_use] options() -> OpenOptions225 pub fn options() -> OpenOptions { 226 OpenOptions::new() 227 } 228 229 /// Converts a [`std::fs::File`][std] to a [`tokio::fs::File`][file]. 230 /// 231 /// [std]: std::fs::File 232 /// [file]: File 233 /// 234 /// # Examples 235 /// 236 /// ```no_run 237 /// // This line could block. It is not recommended to do this on the Tokio 238 /// // runtime. 239 /// let std_file = std::fs::File::open("foo.txt").unwrap(); 240 /// let file = tokio::fs::File::from_std(std_file); 241 /// ``` from_std(std: StdFile) -> File242 pub fn from_std(std: StdFile) -> File { 243 File { 244 std: Arc::new(std), 245 inner: Mutex::new(Inner { 246 state: State::Idle(Some(Buf::with_capacity(0))), 247 last_write_err: None, 248 pos: 0, 249 }), 250 } 251 } 252 253 /// Attempts to sync all OS-internal metadata to disk. 254 /// 255 /// This function will attempt to ensure that all in-core data reaches the 256 /// filesystem before returning. 257 /// 258 /// # Examples 259 /// 260 /// ```no_run 261 /// use tokio::fs::File; 262 /// use tokio::io::AsyncWriteExt; 263 /// 264 /// # async fn dox() -> std::io::Result<()> { 265 /// let mut file = File::create("foo.txt").await?; 266 /// file.write_all(b"hello, world!").await?; 267 /// file.sync_all().await?; 268 /// # Ok(()) 269 /// # } 270 /// ``` 271 /// 272 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 273 /// 274 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 275 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt sync_all(&self) -> io::Result<()>276 pub async fn sync_all(&self) -> io::Result<()> { 277 let mut inner = self.inner.lock().await; 278 inner.complete_inflight().await; 279 280 let std = self.std.clone(); 281 asyncify(move || std.sync_all()).await 282 } 283 284 /// This function is similar to `sync_all`, except that it may not 285 /// synchronize file metadata to the filesystem. 286 /// 287 /// This is intended for use cases that must synchronize content, but don't 288 /// need the metadata on disk. The goal of this method is to reduce disk 289 /// operations. 290 /// 291 /// Note that some platforms may simply implement this in terms of `sync_all`. 292 /// 293 /// # Examples 294 /// 295 /// ```no_run 296 /// use tokio::fs::File; 297 /// use tokio::io::AsyncWriteExt; 298 /// 299 /// # async fn dox() -> std::io::Result<()> { 300 /// let mut file = File::create("foo.txt").await?; 301 /// file.write_all(b"hello, world!").await?; 302 /// file.sync_data().await?; 303 /// # Ok(()) 304 /// # } 305 /// ``` 306 /// 307 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 308 /// 309 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 310 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt sync_data(&self) -> io::Result<()>311 pub async fn sync_data(&self) -> io::Result<()> { 312 let mut inner = self.inner.lock().await; 313 inner.complete_inflight().await; 314 315 let std = self.std.clone(); 316 asyncify(move || std.sync_data()).await 317 } 318 319 /// Truncates or extends the underlying file, updating the size of this file to become size. 320 /// 321 /// If the size is less than the current file's size, then the file will be 322 /// shrunk. If it is greater than the current file's size, then the file 323 /// will be extended to size and have all of the intermediate data filled in 324 /// with 0s. 325 /// 326 /// # Errors 327 /// 328 /// This function will return an error if the file is not opened for 329 /// writing. 330 /// 331 /// # Examples 332 /// 333 /// ```no_run 334 /// use tokio::fs::File; 335 /// use tokio::io::AsyncWriteExt; 336 /// 337 /// # async fn dox() -> std::io::Result<()> { 338 /// let mut file = File::create("foo.txt").await?; 339 /// file.write_all(b"hello, world!").await?; 340 /// file.set_len(10).await?; 341 /// # Ok(()) 342 /// # } 343 /// ``` 344 /// 345 /// The [`write_all`] method is defined on the [`AsyncWriteExt`] trait. 346 /// 347 /// [`write_all`]: fn@crate::io::AsyncWriteExt::write_all 348 /// [`AsyncWriteExt`]: trait@crate::io::AsyncWriteExt set_len(&self, size: u64) -> io::Result<()>349 pub async fn set_len(&self, size: u64) -> io::Result<()> { 350 let mut inner = self.inner.lock().await; 351 inner.complete_inflight().await; 352 353 let mut buf = match inner.state { 354 Idle(ref mut buf_cell) => buf_cell.take().unwrap(), 355 _ => unreachable!(), 356 }; 357 358 let seek = if !buf.is_empty() { 359 Some(SeekFrom::Current(buf.discard_read())) 360 } else { 361 None 362 }; 363 364 let std = self.std.clone(); 365 366 inner.state = Busy(spawn_blocking(move || { 367 let res = if let Some(seek) = seek { 368 (&*std).seek(seek).and_then(|_| std.set_len(size)) 369 } else { 370 std.set_len(size) 371 } 372 .map(|_| 0); // the value is discarded later 373 374 // Return the result as a seek 375 (Operation::Seek(res), buf) 376 })); 377 378 let (op, buf) = match inner.state { 379 Idle(_) => unreachable!(), 380 Busy(ref mut rx) => rx.await?, 381 }; 382 383 inner.state = Idle(Some(buf)); 384 385 match op { 386 Operation::Seek(res) => res.map(|pos| { 387 inner.pos = pos; 388 }), 389 _ => unreachable!(), 390 } 391 } 392 393 /// Queries metadata about the underlying file. 394 /// 395 /// # Examples 396 /// 397 /// ```no_run 398 /// use tokio::fs::File; 399 /// 400 /// # async fn dox() -> std::io::Result<()> { 401 /// let file = File::open("foo.txt").await?; 402 /// let metadata = file.metadata().await?; 403 /// 404 /// println!("{:?}", metadata); 405 /// # Ok(()) 406 /// # } 407 /// ``` metadata(&self) -> io::Result<Metadata>408 pub async fn metadata(&self) -> io::Result<Metadata> { 409 let std = self.std.clone(); 410 asyncify(move || std.metadata()).await 411 } 412 413 /// Creates a new `File` instance that shares the same underlying file handle 414 /// as the existing `File` instance. Reads, writes, and seeks will affect both 415 /// File instances simultaneously. 416 /// 417 /// # Examples 418 /// 419 /// ```no_run 420 /// use tokio::fs::File; 421 /// 422 /// # async fn dox() -> std::io::Result<()> { 423 /// let file = File::open("foo.txt").await?; 424 /// let file_clone = file.try_clone().await?; 425 /// # Ok(()) 426 /// # } 427 /// ``` try_clone(&self) -> io::Result<File>428 pub async fn try_clone(&self) -> io::Result<File> { 429 self.inner.lock().await.complete_inflight().await; 430 let std = self.std.clone(); 431 let std_file = asyncify(move || std.try_clone()).await?; 432 Ok(File::from_std(std_file)) 433 } 434 435 /// Destructures `File` into a [`std::fs::File`][std]. This function is 436 /// async to allow any in-flight operations to complete. 437 /// 438 /// Use `File::try_into_std` to attempt conversion immediately. 439 /// 440 /// [std]: std::fs::File 441 /// 442 /// # Examples 443 /// 444 /// ```no_run 445 /// use tokio::fs::File; 446 /// 447 /// # async fn dox() -> std::io::Result<()> { 448 /// let tokio_file = File::open("foo.txt").await?; 449 /// let std_file = tokio_file.into_std().await; 450 /// # Ok(()) 451 /// # } 452 /// ``` into_std(mut self) -> StdFile453 pub async fn into_std(mut self) -> StdFile { 454 self.inner.get_mut().complete_inflight().await; 455 Arc::try_unwrap(self.std).expect("Arc::try_unwrap failed") 456 } 457 458 /// Tries to immediately destructure `File` into a [`std::fs::File`][std]. 459 /// 460 /// [std]: std::fs::File 461 /// 462 /// # Errors 463 /// 464 /// This function will return an error containing the file if some 465 /// operation is in-flight. 466 /// 467 /// # Examples 468 /// 469 /// ```no_run 470 /// use tokio::fs::File; 471 /// 472 /// # async fn dox() -> std::io::Result<()> { 473 /// let tokio_file = File::open("foo.txt").await?; 474 /// let std_file = tokio_file.try_into_std().unwrap(); 475 /// # Ok(()) 476 /// # } 477 /// ``` try_into_std(mut self) -> Result<StdFile, Self>478 pub fn try_into_std(mut self) -> Result<StdFile, Self> { 479 match Arc::try_unwrap(self.std) { 480 Ok(file) => Ok(file), 481 Err(std_file_arc) => { 482 self.std = std_file_arc; 483 Err(self) 484 } 485 } 486 } 487 488 /// Changes the permissions on the underlying file. 489 /// 490 /// # Platform-specific behavior 491 /// 492 /// This function currently corresponds to the `fchmod` function on Unix and 493 /// the `SetFileInformationByHandle` function on Windows. Note that, this 494 /// [may change in the future][changes]. 495 /// 496 /// [changes]: https://doc.rust-lang.org/std/io/index.html#platform-specific-behavior 497 /// 498 /// # Errors 499 /// 500 /// This function will return an error if the user lacks permission change 501 /// attributes on the underlying file. It may also return an error in other 502 /// os-specific unspecified cases. 503 /// 504 /// # Examples 505 /// 506 /// ```no_run 507 /// use tokio::fs::File; 508 /// 509 /// # async fn dox() -> std::io::Result<()> { 510 /// let file = File::open("foo.txt").await?; 511 /// let mut perms = file.metadata().await?.permissions(); 512 /// perms.set_readonly(true); 513 /// file.set_permissions(perms).await?; 514 /// # Ok(()) 515 /// # } 516 /// ``` set_permissions(&self, perm: Permissions) -> io::Result<()>517 pub async fn set_permissions(&self, perm: Permissions) -> io::Result<()> { 518 let std = self.std.clone(); 519 asyncify(move || std.set_permissions(perm)).await 520 } 521 } 522 523 impl AsyncRead for File { poll_read( self: Pin<&mut Self>, cx: &mut Context<'_>, dst: &mut ReadBuf<'_>, ) -> Poll<io::Result<()>>524 fn poll_read( 525 self: Pin<&mut Self>, 526 cx: &mut Context<'_>, 527 dst: &mut ReadBuf<'_>, 528 ) -> Poll<io::Result<()>> { 529 ready!(crate::trace::trace_leaf(cx)); 530 let me = self.get_mut(); 531 let inner = me.inner.get_mut(); 532 533 loop { 534 match inner.state { 535 Idle(ref mut buf_cell) => { 536 let mut buf = buf_cell.take().unwrap(); 537 538 if !buf.is_empty() { 539 buf.copy_to(dst); 540 *buf_cell = Some(buf); 541 return Ready(Ok(())); 542 } 543 544 buf.ensure_capacity_for(dst); 545 let std = me.std.clone(); 546 547 inner.state = Busy(spawn_blocking(move || { 548 let res = buf.read_from(&mut &*std); 549 (Operation::Read(res), buf) 550 })); 551 } 552 Busy(ref mut rx) => { 553 let (op, mut buf) = ready!(Pin::new(rx).poll(cx))?; 554 555 match op { 556 Operation::Read(Ok(_)) => { 557 buf.copy_to(dst); 558 inner.state = Idle(Some(buf)); 559 return Ready(Ok(())); 560 } 561 Operation::Read(Err(e)) => { 562 assert!(buf.is_empty()); 563 564 inner.state = Idle(Some(buf)); 565 return Ready(Err(e)); 566 } 567 Operation::Write(Ok(_)) => { 568 assert!(buf.is_empty()); 569 inner.state = Idle(Some(buf)); 570 continue; 571 } 572 Operation::Write(Err(e)) => { 573 assert!(inner.last_write_err.is_none()); 574 inner.last_write_err = Some(e.kind()); 575 inner.state = Idle(Some(buf)); 576 } 577 Operation::Seek(result) => { 578 assert!(buf.is_empty()); 579 inner.state = Idle(Some(buf)); 580 if let Ok(pos) = result { 581 inner.pos = pos; 582 } 583 continue; 584 } 585 } 586 } 587 } 588 } 589 } 590 } 591 592 impl AsyncSeek for File { start_seek(self: Pin<&mut Self>, mut pos: SeekFrom) -> io::Result<()>593 fn start_seek(self: Pin<&mut Self>, mut pos: SeekFrom) -> io::Result<()> { 594 let me = self.get_mut(); 595 let inner = me.inner.get_mut(); 596 597 match inner.state { 598 Busy(_) => Err(io::Error::new( 599 io::ErrorKind::Other, 600 "other file operation is pending, call poll_complete before start_seek", 601 )), 602 Idle(ref mut buf_cell) => { 603 let mut buf = buf_cell.take().unwrap(); 604 605 // Factor in any unread data from the buf 606 if !buf.is_empty() { 607 let n = buf.discard_read(); 608 609 if let SeekFrom::Current(ref mut offset) = pos { 610 *offset += n; 611 } 612 } 613 614 let std = me.std.clone(); 615 616 inner.state = Busy(spawn_blocking(move || { 617 let res = (&*std).seek(pos); 618 (Operation::Seek(res), buf) 619 })); 620 Ok(()) 621 } 622 } 623 } 624 poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>625 fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> { 626 ready!(crate::trace::trace_leaf(cx)); 627 let inner = self.inner.get_mut(); 628 629 loop { 630 match inner.state { 631 Idle(_) => return Poll::Ready(Ok(inner.pos)), 632 Busy(ref mut rx) => { 633 let (op, buf) = ready!(Pin::new(rx).poll(cx))?; 634 inner.state = Idle(Some(buf)); 635 636 match op { 637 Operation::Read(_) => {} 638 Operation::Write(Err(e)) => { 639 assert!(inner.last_write_err.is_none()); 640 inner.last_write_err = Some(e.kind()); 641 } 642 Operation::Write(_) => {} 643 Operation::Seek(res) => { 644 if let Ok(pos) = res { 645 inner.pos = pos; 646 } 647 return Ready(res); 648 } 649 } 650 } 651 } 652 } 653 } 654 } 655 656 impl AsyncWrite for File { poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, src: &[u8], ) -> Poll<io::Result<usize>>657 fn poll_write( 658 self: Pin<&mut Self>, 659 cx: &mut Context<'_>, 660 src: &[u8], 661 ) -> Poll<io::Result<usize>> { 662 ready!(crate::trace::trace_leaf(cx)); 663 let me = self.get_mut(); 664 let inner = me.inner.get_mut(); 665 666 if let Some(e) = inner.last_write_err.take() { 667 return Ready(Err(e.into())); 668 } 669 670 loop { 671 match inner.state { 672 Idle(ref mut buf_cell) => { 673 let mut buf = buf_cell.take().unwrap(); 674 675 let seek = if !buf.is_empty() { 676 Some(SeekFrom::Current(buf.discard_read())) 677 } else { 678 None 679 }; 680 681 let n = buf.copy_from(src); 682 let std = me.std.clone(); 683 684 let blocking_task_join_handle = spawn_mandatory_blocking(move || { 685 let res = if let Some(seek) = seek { 686 (&*std).seek(seek).and_then(|_| buf.write_to(&mut &*std)) 687 } else { 688 buf.write_to(&mut &*std) 689 }; 690 691 (Operation::Write(res), buf) 692 }) 693 .ok_or_else(|| { 694 io::Error::new(io::ErrorKind::Other, "background task failed") 695 })?; 696 697 inner.state = Busy(blocking_task_join_handle); 698 699 return Ready(Ok(n)); 700 } 701 Busy(ref mut rx) => { 702 let (op, buf) = ready!(Pin::new(rx).poll(cx))?; 703 inner.state = Idle(Some(buf)); 704 705 match op { 706 Operation::Read(_) => { 707 // We don't care about the result here. The fact 708 // that the cursor has advanced will be reflected in 709 // the next iteration of the loop 710 continue; 711 } 712 Operation::Write(res) => { 713 // If the previous write was successful, continue. 714 // Otherwise, error. 715 res?; 716 continue; 717 } 718 Operation::Seek(_) => { 719 // Ignore the seek 720 continue; 721 } 722 } 723 } 724 } 725 } 726 } 727 poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>728 fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 729 ready!(crate::trace::trace_leaf(cx)); 730 let inner = self.inner.get_mut(); 731 inner.poll_flush(cx) 732 } 733 poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>734 fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 735 ready!(crate::trace::trace_leaf(cx)); 736 self.poll_flush(cx) 737 } 738 } 739 740 impl From<StdFile> for File { from(std: StdFile) -> Self741 fn from(std: StdFile) -> Self { 742 Self::from_std(std) 743 } 744 } 745 746 impl fmt::Debug for File { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result747 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 748 fmt.debug_struct("tokio::fs::File") 749 .field("std", &self.std) 750 .finish() 751 } 752 } 753 754 #[cfg(unix)] 755 impl std::os::unix::io::AsRawFd for File { as_raw_fd(&self) -> std::os::unix::io::RawFd756 fn as_raw_fd(&self) -> std::os::unix::io::RawFd { 757 self.std.as_raw_fd() 758 } 759 } 760 761 #[cfg(unix)] 762 impl std::os::unix::io::AsFd for File { as_fd(&self) -> std::os::unix::io::BorrowedFd<'_>763 fn as_fd(&self) -> std::os::unix::io::BorrowedFd<'_> { 764 unsafe { 765 std::os::unix::io::BorrowedFd::borrow_raw(std::os::unix::io::AsRawFd::as_raw_fd(self)) 766 } 767 } 768 } 769 770 #[cfg(unix)] 771 impl std::os::unix::io::FromRawFd for File { from_raw_fd(fd: std::os::unix::io::RawFd) -> Self772 unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> Self { 773 StdFile::from_raw_fd(fd).into() 774 } 775 } 776 777 cfg_windows! { 778 use crate::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle, AsHandle, BorrowedHandle}; 779 780 impl AsRawHandle for File { 781 fn as_raw_handle(&self) -> RawHandle { 782 self.std.as_raw_handle() 783 } 784 } 785 786 impl AsHandle for File { 787 fn as_handle(&self) -> BorrowedHandle<'_> { 788 unsafe { 789 BorrowedHandle::borrow_raw( 790 AsRawHandle::as_raw_handle(self), 791 ) 792 } 793 } 794 } 795 796 impl FromRawHandle for File { 797 unsafe fn from_raw_handle(handle: RawHandle) -> Self { 798 StdFile::from_raw_handle(handle).into() 799 } 800 } 801 } 802 803 impl Inner { complete_inflight(&mut self)804 async fn complete_inflight(&mut self) { 805 use crate::future::poll_fn; 806 807 poll_fn(|cx| self.poll_complete_inflight(cx)).await 808 } 809 poll_complete_inflight(&mut self, cx: &mut Context<'_>) -> Poll<()>810 fn poll_complete_inflight(&mut self, cx: &mut Context<'_>) -> Poll<()> { 811 ready!(crate::trace::trace_leaf(cx)); 812 match self.poll_flush(cx) { 813 Poll::Ready(Err(e)) => { 814 self.last_write_err = Some(e.kind()); 815 Poll::Ready(()) 816 } 817 Poll::Ready(Ok(())) => Poll::Ready(()), 818 Poll::Pending => Poll::Pending, 819 } 820 } 821 poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>822 fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> { 823 if let Some(e) = self.last_write_err.take() { 824 return Ready(Err(e.into())); 825 } 826 827 let (op, buf) = match self.state { 828 Idle(_) => return Ready(Ok(())), 829 Busy(ref mut rx) => ready!(Pin::new(rx).poll(cx))?, 830 }; 831 832 // The buffer is not used here 833 self.state = Idle(Some(buf)); 834 835 match op { 836 Operation::Read(_) => Ready(Ok(())), 837 Operation::Write(res) => Ready(res), 838 Operation::Seek(_) => Ready(Ok(())), 839 } 840 } 841 } 842 843 #[cfg(test)] 844 mod tests; 845