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