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         loop {
569             match inner.state {
570                 Busy(_) => panic!("must wait for poll_complete before calling start_seek"),
571                 Idle(ref mut buf_cell) => {
572                     let mut buf = buf_cell.take().unwrap();
573 
574                     // Factor in any unread data from the buf
575                     if !buf.is_empty() {
576                         let n = buf.discard_read();
577 
578                         if let SeekFrom::Current(ref mut offset) = pos {
579                             *offset += n;
580                         }
581                     }
582 
583                     let std = me.std.clone();
584 
585                     inner.state = Busy(spawn_blocking(move || {
586                         let res = (&*std).seek(pos);
587                         (Operation::Seek(res), buf)
588                     }));
589                     return Ok(());
590                 }
591             }
592         }
593     }
594 
poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>>595     fn poll_complete(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<u64>> {
596         let inner = self.inner.get_mut();
597 
598         loop {
599             match inner.state {
600                 Idle(_) => return Poll::Ready(Ok(inner.pos)),
601                 Busy(ref mut rx) => {
602                     let (op, buf) = ready!(Pin::new(rx).poll(cx))?;
603                     inner.state = Idle(Some(buf));
604 
605                     match op {
606                         Operation::Read(_) => {}
607                         Operation::Write(Err(e)) => {
608                             assert!(inner.last_write_err.is_none());
609                             inner.last_write_err = Some(e.kind());
610                         }
611                         Operation::Write(_) => {}
612                         Operation::Seek(res) => {
613                             if let Ok(pos) = res {
614                                 inner.pos = pos;
615                             }
616                             return Ready(res);
617                         }
618                     }
619                 }
620             }
621         }
622     }
623 }
624 
625 impl AsyncWrite for File {
poll_write( self: Pin<&mut Self>, cx: &mut Context<'_>, src: &[u8], ) -> Poll<io::Result<usize>>626     fn poll_write(
627         self: Pin<&mut Self>,
628         cx: &mut Context<'_>,
629         src: &[u8],
630     ) -> Poll<io::Result<usize>> {
631         let me = self.get_mut();
632         let inner = me.inner.get_mut();
633 
634         if let Some(e) = inner.last_write_err.take() {
635             return Ready(Err(e.into()));
636         }
637 
638         loop {
639             match inner.state {
640                 Idle(ref mut buf_cell) => {
641                     let mut buf = buf_cell.take().unwrap();
642 
643                     let seek = if !buf.is_empty() {
644                         Some(SeekFrom::Current(buf.discard_read()))
645                     } else {
646                         None
647                     };
648 
649                     let n = buf.copy_from(src);
650                     let std = me.std.clone();
651 
652                     let blocking_task_join_handle = spawn_mandatory_blocking(move || {
653                         let res = if let Some(seek) = seek {
654                             (&*std).seek(seek).and_then(|_| buf.write_to(&mut &*std))
655                         } else {
656                             buf.write_to(&mut &*std)
657                         };
658 
659                         (Operation::Write(res), buf)
660                     })
661                     .ok_or_else(|| {
662                         io::Error::new(io::ErrorKind::Other, "background task failed")
663                     })?;
664 
665                     inner.state = Busy(blocking_task_join_handle);
666 
667                     return Ready(Ok(n));
668                 }
669                 Busy(ref mut rx) => {
670                     let (op, buf) = ready!(Pin::new(rx).poll(cx))?;
671                     inner.state = Idle(Some(buf));
672 
673                     match op {
674                         Operation::Read(_) => {
675                             // We don't care about the result here. The fact
676                             // that the cursor has advanced will be reflected in
677                             // the next iteration of the loop
678                             continue;
679                         }
680                         Operation::Write(res) => {
681                             // If the previous write was successful, continue.
682                             // Otherwise, error.
683                             res?;
684                             continue;
685                         }
686                         Operation::Seek(_) => {
687                             // Ignore the seek
688                             continue;
689                         }
690                     }
691                 }
692             }
693         }
694     }
695 
poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>696     fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
697         let inner = self.inner.get_mut();
698         inner.poll_flush(cx)
699     }
700 
poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>701     fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
702         self.poll_flush(cx)
703     }
704 }
705 
706 impl From<StdFile> for File {
from(std: StdFile) -> Self707     fn from(std: StdFile) -> Self {
708         Self::from_std(std)
709     }
710 }
711 
712 impl fmt::Debug for File {
fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result713     fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
714         fmt.debug_struct("tokio::fs::File")
715             .field("std", &self.std)
716             .finish()
717     }
718 }
719 
720 #[cfg(unix)]
721 impl std::os::unix::io::AsRawFd for File {
as_raw_fd(&self) -> std::os::unix::io::RawFd722     fn as_raw_fd(&self) -> std::os::unix::io::RawFd {
723         self.std.as_raw_fd()
724     }
725 }
726 
727 #[cfg(unix)]
728 impl std::os::unix::io::FromRawFd for File {
from_raw_fd(fd: std::os::unix::io::RawFd) -> Self729     unsafe fn from_raw_fd(fd: std::os::unix::io::RawFd) -> Self {
730         StdFile::from_raw_fd(fd).into()
731     }
732 }
733 
734 #[cfg(windows)]
735 impl std::os::windows::io::AsRawHandle for File {
as_raw_handle(&self) -> std::os::windows::io::RawHandle736     fn as_raw_handle(&self) -> std::os::windows::io::RawHandle {
737         self.std.as_raw_handle()
738     }
739 }
740 
741 #[cfg(windows)]
742 impl std::os::windows::io::FromRawHandle for File {
from_raw_handle(handle: std::os::windows::io::RawHandle) -> Self743     unsafe fn from_raw_handle(handle: std::os::windows::io::RawHandle) -> Self {
744         StdFile::from_raw_handle(handle).into()
745     }
746 }
747 
748 impl Inner {
complete_inflight(&mut self)749     async fn complete_inflight(&mut self) {
750         use crate::future::poll_fn;
751 
752         if let Err(e) = poll_fn(|cx| Pin::new(&mut *self).poll_flush(cx)).await {
753             self.last_write_err = Some(e.kind());
754         }
755     }
756 
poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>>757     fn poll_flush(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
758         if let Some(e) = self.last_write_err.take() {
759             return Ready(Err(e.into()));
760         }
761 
762         let (op, buf) = match self.state {
763             Idle(_) => return Ready(Ok(())),
764             Busy(ref mut rx) => ready!(Pin::new(rx).poll(cx))?,
765         };
766 
767         // The buffer is not used here
768         self.state = Idle(Some(buf));
769 
770         match op {
771             Operation::Read(_) => Ready(Ok(())),
772             Operation::Write(res) => Ready(res),
773             Operation::Seek(_) => Ready(Ok(())),
774         }
775     }
776 }
777 
778 #[cfg(test)]
779 mod tests;
780