• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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