Do some copy-paste docs

This commit is contained in:
asonix 2020-06-19 12:38:02 -05:00
parent 460259dda6
commit e6407c4cb3
2 changed files with 914 additions and 25 deletions

View file

@ -1,3 +1,8 @@
//! File-specific operations
//!
//! This module provides methods analogous to the std::fs::File struct, but as free functions due
//! to the ownership requirements of threaded interaction.
use crate::Error;
use actix_threadpool::{run, BlockingError};
use bytes::{Bytes, BytesMut};
@ -16,6 +21,7 @@ use std::{
task::{Context, Poll},
};
/// A stream of bytes from a file on the filesystem
pub struct FileStream {
chunk_size: u64,
size: u64,
@ -31,6 +37,24 @@ struct FileSink<E> {
_error: PhantomData<E>,
}
/// Opens a file in write-only mode.
///
/// This function will create a file if it does not exist,
/// and will truncate it if it does.
///
/// See the [`OpenOptions::open`] function for more details.
///
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::create("foo.txt").await?;
/// Ok(())
/// }
/// ```
pub async fn create<P>(path: P) -> Result<File, Error>
where
P: AsRef<Path> + Send + 'static,
@ -40,6 +64,18 @@ where
Ok(file)
}
/// Queries metadata about the underlying file.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
/// let (f, metadata) = actix_fs::file::metadata(f).await?;
/// Ok(())
/// }
/// ```
pub async fn metadata(file: File) -> Result<(File, Metadata), Error> {
let tup = run(move || {
let metadata = file.metadata()?;
@ -51,6 +87,26 @@ pub async fn metadata(file: File) -> Result<(File, Metadata), Error> {
Ok(tup)
}
/// Attempts to open a file in read-only mode.
///
/// See the [`OpenOptions::open`] method for more details.
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
/// Ok(())
/// }
/// ```
pub async fn open<P>(path: P) -> Result<File, Error>
where
P: AsRef<Path> + Send + 'static,
@ -60,16 +116,66 @@ where
Ok(file)
}
/// Changes the permissions on the underlying file.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `fchmod` function on Unix and
/// the `SetFileInformationByHandle` function on Windows. Note that, this
/// [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error if the user lacks permission change
/// attributes on the underlying file. It may also return an error in other
/// os-specific unspecified cases.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let file = actix_fs::file::open("foo.txt").await?;
/// let (file, meta) = actix_fs::file::metadata(file).await?;
/// let perms = meta.permissions();
/// perms.set_readonly(true);
/// actix_fs::file::set_permissions(file, perms).await?;
/// Ok(())
/// }
/// ```
pub async fn set_permissions(file: File, perm: Permissions) -> Result<File, Error> {
let file = run(move || {
file.set_permissions(perm)?;
Ok(file) as Result<_, io::Error>
Ok(file) as io::Result<_>
})
.await?;
Ok(file)
}
/// Attempts to sync all OS-internal metadata to disk.
///
/// This function will attempt to ensure that all in-memory data reaches the
/// filesystem before returning.
///
/// This can be used to handle errors that would otherwise only be caught
/// when the `File` is closed. Dropping a file will ignore errors in
/// synchronizing this in-memory data.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::create("foo.txt").await?;
/// let f = actix_fs::file::write(f, b"Hello, world!").await?;
///
/// actix_fs::file::sync_all(f).await?;
/// Ok(())
/// }
/// ```
pub async fn sync_all(file: File) -> Result<File, Error> {
let file = run(move || {
file.sync_all()?;
@ -80,6 +186,30 @@ pub async fn sync_all(file: File) -> Result<File, Error> {
Ok(file)
}
/// This function is similar to [`sync_all`], except that it may not
/// synchronize file metadata to the filesystem.
///
/// This is intended for use cases that must synchronize content, but don't
/// need the metadata on disk. The goal of this method is to reduce disk
/// operations.
///
/// Note that some platforms may simply implement this in terms of
/// [`sync_all`].
///
/// [`sync_all`]: struct.File.html#method.sync_all
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::create("foo.txt").await?;
/// let f = actix_fs::file::write_all(f, b"Hello, world!").await?;
///
/// actix_fs::file::sync_data(f).await?;
/// Ok(())
/// }
/// ```
pub async fn sync_data(file: File) -> Result<File, Error> {
let file = run(move || {
file.sync_data()?;
@ -90,6 +220,34 @@ pub async fn sync_data(file: File) -> Result<File, Error> {
Ok(file)
}
/// Truncates or extends the underlying file, updating the size of
/// this file to become `size`.
///
/// If the `size` is less than the current file's size, then the file will
/// be shrunk. If it is greater than the current file's size, then the file
/// will be extended to `size` and have all of the intermediate data filled
/// in with 0s.
///
/// The file's cursor isn't changed. In particular, if the cursor was at the
/// end and the file is shrunk using this operation, the cursor will now be
/// past the end.
///
/// # Errors
///
/// This function will return an error if the file is not opened for writing.
/// Also, std::io::ErrorKind::InvalidInput will be returned if the desired
/// length would cause an overflow due to the implementation specifics.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::create("foo.txt").await?;
/// actix_fs::file::set_len(f, 10).await?;
/// Ok(())
/// }
/// ```
pub async fn set_len(file: File, size: u64) -> Result<File, Error> {
let file = run(move || {
file.set_len(size)?;
@ -100,16 +258,66 @@ pub async fn set_len(file: File, size: u64) -> Result<File, Error> {
Ok(file)
}
/// Seek to an offset, in bytes, in a file.
///
/// If the seek operation completed successfully,
/// this method returns the new position from the start of the stream.
/// That position can be used later with [`SeekFrom::Start`].
///
/// # Errors
///
/// Seeking to a negative offset is considered an error.
///
/// [`SeekFrom::Start`]: enum.SeekFrom.html#variant.Start
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
/// let (f, pos) = actix_fs::file::seek(f, std::io::SeekFrom::Start(8)).await?;
/// }
/// ```
pub async fn seek(mut file: File, seek: io::SeekFrom) -> Result<(File, u64), Error> {
let tup = run(move || {
let pos = file.seek(seek)?;
Ok((file, pos)) as Result<_, io::Error>
Ok((file, pos)) as io::Result<_>
})
.await?;
Ok(tup)
}
/// Pull all bytes from this file.
///
/// # Errors
///
/// If this function encounters any form of I/O or other error, an error
/// variant will be returned. If an error is returned then it must be
/// guaranteed that no bytes were read.
///
/// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the read
/// operation should be retried if there is nothing else to do.
///
/// # Examples
///
/// [`File`]s implement `Read`:
///
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
/// [`Ok(n)`]: ../../std/result/enum.Result.html#variant.Ok
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
/// [`File`]: ../fs/struct.File.html
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
///
/// let bytes = actix_fs::file::read(f).await?;
///
/// println!("The bytes: {:?}", bytes;
/// Ok(())
/// }
/// ```
pub async fn read(file: File) -> Result<Bytes, Error> {
let mut stream = FileStream::new(file).await?;
let mut bytes_mut = BytesMut::with_capacity(stream.size() as usize);
@ -121,10 +329,55 @@ pub async fn read(file: File) -> Result<Bytes, Error> {
Ok(bytes_mut.freeze())
}
/// Produce a new stream of bytes from this File
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
/// let mut stream = actix_fs::file::read_to_stream(f).await?;
///
/// while let Some(res) = stream.next().await {
/// println!("bytes: {:?}", res?);
/// }
///
/// Ok(())
/// }
/// ```
pub async fn read_to_stream(file: File) -> Result<FileStream, Error> {
FileStream::new(file).await
}
/// Read all bytes until EOF in this source.
///
/// # Errors
///
/// If the data in this stream is *not* valid UTF-8 then an error is
/// returned and `buf` is unchanged.
///
/// See [`read_to_end`][readtoend] for other error semantics.
///
/// [readtoend]: #method.read_to_end
///
/// # Examples
///
/// [`File`][file]s implement `Read`:
///
/// [file]: ../fs/struct.File.html
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let f = actix_fs::file::open("foo.txt").await?;
/// let s = actix_fs::file::read_to_string(f).await?;
/// Ok(())
/// }
/// ```
///
/// (See also the [`std::fs::read_to_string`] convenience function for
/// reading from a file.)
///
/// [`std::fs::read_to_string`]: ../fs/fn.read_to_string.html
pub async fn read_to_string(file: File) -> Result<String, Error> {
let mut stream = read_to_stream(file).await?;
@ -139,14 +392,68 @@ pub async fn read_to_string(file: File) -> Result<String, Error> {
Ok(string)
}
pub async fn write(file: File, bytes: Bytes) -> Result<(), Error> {
/// Write bytes into this writer.
///
/// # Errors
///
/// Each call to `write` may generate an I/O error indicating that the
/// operation could not be completed. If an error is returned then no bytes
/// in the buffer were written to this writer.
///
/// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
/// write operation should be retried if there is nothing else to do.
///
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let file = actix_fs::file::create("foo.txt").await?;
///
/// actix_fs::file::write(file, b"some bytes").await?;
/// Ok(())
/// }
/// ```
pub async fn write<B>(file: File, bytes: B) -> Result<(), Error>
where
B: Into<Bytes>,
{
let mut sink = FileSink::<Error>::new(file);
sink.send(bytes).await?;
sink.send(bytes.into()).await?;
sink.close().await?;
Ok(())
}
/// Write a stream of bytes into this writer.
///
/// # Errors
///
/// Each call to `write` may generate an I/O error indicating that the
/// operation could not be completed. If an error is returned then no bytes
/// in the buffer were written to this writer.
///
/// An error of the [`ErrorKind::Interrupted`] kind is non-fatal and the
/// write operation should be retried if there is nothing else to do.
///
/// [`Err`]: ../../std/result/enum.Result.html#variant.Err
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let file = actix_fs::file::create("foo.txt").await?;
/// let stream = actix_fs::read_to_stream("bar.txt").await?;
///
/// actix_fs::file::write(file, stream).await?;
/// Ok(())
/// }
/// ```
pub async fn write_stream<S, E>(file: File, mut stream: S) -> Result<(), E>
where
S: Stream<Item = Result<Bytes, E>> + Unpin,

View file

@ -1,3 +1,5 @@
#![deny(missing_docs)]
//! # Actix FS
//! _Asyncronous filesystem operations for actix-based systems_
//!
@ -7,7 +9,7 @@
//! use std::io::SeekFrom;
//!
//! #[actix_rt::main]
//! async fn main() -> Result<(), anyhow::Error> {
//! async fn main() -> Result<()> {
//! let file = actix_fs::file::open("tests/read.txt").await?;
//! let (file, position) = actix_fs::file::seek(file, SeekFrom::Start(7)).await?;
//! let bytes = actix_fs::file::read(file).await?;
@ -46,15 +48,24 @@ use std::{
pub mod file;
#[derive(Debug, thiserror::Error)]
/// Possible errors produced by Actix FS
pub enum Error {
/// IO Error
#[error("{0}")]
Io(#[from] io::Error),
/// Task canceled (due to panic)
#[error("Task canceled")]
Canceled,
}
/// Actix FS Result type
pub type Result<T> = std::result::Result<T, Error>;
impl Error {
/// Get the io::ErrorKind from the error if present
///
/// This method returns None if the IO operation panicked.
pub fn kind(&self) -> Option<io::ErrorKind> {
match self {
Error::Io(ref io) => Some(io.kind()),
@ -69,7 +80,42 @@ impl From<std::str::Utf8Error> for Error {
}
}
pub async fn canonicalize<P>(path: P) -> Result<PathBuf, Error>
/// Returns the canonical, absolute form of a path with all intermediate
/// components normalized and symbolic links resolved.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `realpath` function on Unix
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes].
///
/// On Windows, this converts the path to use [extended length path][path]
/// syntax, which allows your program to use longer path names, but means you
/// can only join backslash-delimited paths to it, and it may be incompatible
/// with other applications (if passed to the application on the command-line,
/// or written to a file another application may read).
///
/// [changes]: ../io/index.html#platform-specific-behavior
/// [path]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * `path` does not exist.
/// * A non-final component in path is not a directory.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let path = actix_fs::canonicalize("../a/../foo.txt").await?;
/// Ok(())
/// }
/// ```
pub async fn canonicalize<P>(path: P) -> Result<PathBuf>
where
P: AsRef<Path> + Send + 'static,
{
@ -78,7 +124,56 @@ where
Ok(path)
}
pub async fn copy<P, Q>(from: P, to: Q) -> Result<u64, Error>
/// Copies the contents of one file to another. This function will also
/// copy the permission bits of the original file to the destination file.
///
/// This function will **overwrite** the contents of `to`.
///
/// Note that if `from` and `to` both point to the same file, then the file
/// will likely get truncated by this operation.
///
/// On success, the total number of bytes copied is returned and it is equal to
/// the length of the `to` file as reported by `metadata`.
///
/// If youre wanting to copy the contents of one file to another and youre
/// working with [`File`]s, see the [`io::copy`] function.
///
/// [`io::copy`]: ../io/fn.copy.html
/// [`File`]: ./struct.File.html
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `open` function in Unix
/// with `O_RDONLY` for `from` and `O_WRONLY`, `O_CREAT`, and `O_TRUNC` for `to`.
/// `O_CLOEXEC` is set for returned file descriptors.
/// On Windows, this function currently corresponds to `CopyFileEx`. Alternate
/// NTFS streams are copied but only the size of the main stream is returned by
/// this function. On MacOS, this function corresponds to `fclonefileat` and
/// `fcopyfile`.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * The `from` path is not a file.
/// * The `from` file does not exist.
/// * The current process does not have the permission rights to access
/// `from` or write `to`.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// fn main() -> actix_fs::Result<()> {
/// actix_fs::copy("foo.txt", "bar.txt").await?; // Copy foo.txt to bar.txt
/// Ok(())
/// }
/// ```
pub async fn copy<P, Q>(from: P, to: Q) -> Result<u64>
where
P: AsRef<Path> + Send + 'static,
Q: AsRef<Path> + Send + 'static,
@ -88,7 +183,43 @@ where
Ok(bytes)
}
pub async fn create_dir<P>(path: P) -> Result<(), Error>
/// Creates a new, empty directory at the provided path
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// **NOTE**: If a parent of the given path doesn't exist, this function will
/// return an error. To create a directory and all its missing parents at the
/// same time, use the [`create_dir_all`] function.
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * User lacks permissions to create directory at `path`.
/// * A parent of the given path doesn't exist. (To create a directory and all
/// its missing parents at the same time, use the [`create_dir_all`]
/// function.)
/// * `path` already exists.
///
/// [`create_dir_all`]: fn.create_dir_all.html
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::create_dir("/some/dir").await?;
/// Ok(())
/// }
/// ```
pub async fn create_dir<P>(path: P) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -97,7 +228,45 @@ where
Ok(())
}
pub async fn create_dir_all<P>(path: P) -> Result<(), Error>
/// Recursively create a directory and all of its parent components if they
/// are missing.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `mkdir` function on Unix
/// and the `CreateDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * If any directory in the path specified by `path`
/// does not already exist and it could not be created otherwise. The specific
/// error conditions for when a directory is being created (after it is
/// determined to not exist) are outlined by [`fs::create_dir`].
///
/// Notable exception is made for situations where any of the directories
/// specified in the `path` could not be created as it was being created concurrently.
/// Such cases are considered to be successful. That is, calling `create_dir_all`
/// concurrently from multiple threads or processes is guaranteed not to fail
/// due to a race condition with itself.
///
/// [`fs::create_dir`]: fn.create_dir.html
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::create_dir_all("/some/dir").await?;
/// Ok(())
/// }
/// ```
pub async fn create_dir_all<P>(path: P) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -106,7 +275,36 @@ where
Ok(())
}
pub async fn hard_link<P, Q>(src: P, dst: Q) -> Result<(), Error>
/// Creates a new hard link on the filesystem.
///
/// The `dst` path will be a link pointing to the `src` path. Note that systems
/// often require these two paths to both be located on the same filesystem.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `link` function on Unix
/// and the `CreateHardLink` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * The `src` path is not a file or doesn't exist.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::hard_link("a.txt", "b.txt").await?; // Hard link a.txt to b.txt
/// Ok(())
/// }
/// ```
pub async fn hard_link<P, Q>(src: P, dst: Q) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
Q: AsRef<Path> + Send + 'static,
@ -116,7 +314,39 @@ where
Ok(())
}
pub async fn metadata<P>(path: P) -> Result<fs::Metadata, Error>
/// Given a path, query the file system to get information about a file,
/// directory, etc.
///
/// This function will traverse symbolic links to query information about the
/// destination file.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `stat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * The user lacks permissions to perform `metadata` call on `path`.
/// * `path` does not exist.
///
/// # Examples
///
/// ```rust,no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let attr = actix_fs::metadata("/some/file/path.txt").await?;
/// // inspect attr ...
/// Ok(())
/// }
/// ```
pub async fn metadata<P>(path: P) -> Result<fs::Metadata>
where
P: AsRef<Path> + Send + 'static,
{
@ -125,7 +355,40 @@ where
Ok(metadata)
}
pub async fn read<P>(path: P) -> Result<Bytes, Error>
/// Read the entire contents of a file into a bytes vector.
///
/// This is a convenience function for using [`File::open`] and [`read_to_end`]
/// with fewer imports and without an intermediate variable. It pre-allocates a
/// buffer based on the file size when available, so it is generally faster than
/// reading into a vector created with `Vec::new()`.
///
/// [`file::open`]: struct.File.html#method.open
/// [`read_to_end`]: ../io/trait.Read.html#method.read_to_end
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// It will also return an error if it encounters while reading an error
/// of a kind other than [`ErrorKind::Interrupted`].
///
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
///
/// # Examples
///
/// ```no_run
/// use std::net::SocketAddr;
///
/// #[actix_rt::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
/// let foo: SocketAddr = String::from_utf8_lossy(&actix_fs::read("address.txt").await?).parse()?;
/// Ok(())
/// }
/// ```
pub async fn read<P>(path: P) -> Result<Bytes>
where
P: AsRef<Path> + Send + 'static,
{
@ -134,7 +397,35 @@ where
file::read(f).await
}
pub async fn read_link<P>(path: P) -> Result<PathBuf, Error>
/// Reads a symbolic link, returning the file that the link points to.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `readlink` function on Unix
/// and the `CreateFile` function with `FILE_FLAG_OPEN_REPARSE_POINT` and
/// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * `path` is not a symbolic link.
/// * `path` does not exist.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let path = actix_fs::read_link("a.txt").await?;
/// Ok(())
/// }
/// ```
pub async fn read_link<P>(path: P) -> Result<PathBuf>
where
P: AsRef<Path> + Send + 'static,
{
@ -143,7 +434,37 @@ where
Ok(path)
}
pub async fn read_to_stream<P>(path: P) -> Result<file::FileStream, Error>
/// Read the contents of a file stream of bytes.
///
/// This is a convenience function for using [`file::open`] and [`read_to_stream`]
/// with fewer imports and without an intermediate variable.
///
/// [`file::open`]: struct.File.html#method.open
/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// # Examples
///
/// ```no_run
/// use std::net::SocketAddr;
///
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let mut stream = actix_fs::read_to_stream("some.txt").await?;
///
/// while let Some(res) = stream.next().await {
/// println!("bytes: {:?}", res?);
/// }
/// Ok(())
/// }
/// ```
pub async fn read_to_stream<P>(path: P) -> Result<file::FileStream>
where
P: AsRef<Path> + Send + 'static,
{
@ -152,7 +473,41 @@ where
file::read_to_stream(f).await
}
pub async fn read_to_string<P>(path: P) -> Result<String, Error>
/// Read the entire contents of a file into a string.
///
/// This is a convenience function for using [`File::open`] and [`read_to_string`]
/// with fewer imports and without an intermediate variable. It pre-allocates a
/// buffer based on the file size when available, so it is generally faster than
/// reading into a string created with `String::new()`.
///
/// [`file::open`]: struct.File.html#method.open
/// [`read_to_string`]: ../io/trait.Read.html#method.read_to_string
///
/// # Errors
///
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
/// [`OpenOptions::open`]: struct.OpenOptions.html#method.open
///
/// It will also return an error if it encounters while reading an error
/// of a kind other than [`ErrorKind::Interrupted`],
/// or if the contents of the file are not valid UTF-8.
///
/// [`ErrorKind::Interrupted`]: ../../std/io/enum.ErrorKind.html#variant.Interrupted
///
/// # Examples
///
/// ```no_run
/// use std::net::SocketAddr;
///
/// #[actix_rt::main]
/// async fn main() -> Result<(), Box<dyn std::error::Error + 'static>> {
/// let foo: SocketAddr = actix_fs::read_to_string("address.txt").await?.parse()?;
/// Ok(())
/// }
/// ```
pub async fn read_to_string<P>(path: P) -> Result<String>
where
P: AsRef<Path> + Send + 'static,
{
@ -161,7 +516,34 @@ where
file::read_to_string(f).await
}
pub async fn remove_dir<P>(path: P) -> Result<(), Error>
/// Removes an existing, empty directory.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `rmdir` function on Unix
/// and the `RemoveDirectory` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * The user lacks permissions to remove the directory at the provided `path`.
/// * The directory isn't empty.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::remove_dir("/some/dir").await?;
/// Ok(())
/// }
/// ```
pub async fn remove_dir<P>(path: P) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -170,7 +552,38 @@ where
Ok(())
}
pub async fn remove_dir_all<P>(path: P) -> Result<(), Error>
/// Removes a directory at this path, after removing all its contents. Use
/// carefully!
///
/// This function does **not** follow symbolic links and it will simply remove the
/// symbolic link itself.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix
/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions
/// on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// See [`actix_fs::remove_file`] and [`actix_fs::remove_dir`].
///
/// [`actix_fs::remove_file`]: fn.remove_file.html
/// [`actix_fs::remove_dir`]: fn.remove_dir.html
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::remove_dir_all("/some/dir").await?;
/// Ok(())
/// }
/// ```
pub async fn remove_dir_all<P>(path: P) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -179,7 +592,38 @@ where
Ok(())
}
pub async fn remove_file<P>(path: P) -> Result<(), Error>
/// Removes a file from the filesystem.
///
/// Note that there is no
/// guarantee that the file is immediately deleted (e.g., depending on
/// platform, other open file descriptors may prevent immediate removal).
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `unlink` function on Unix
/// and the `DeleteFile` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * `path` points to a directory.
/// * The user lacks permissions to remove the file.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::remove_file("a.txt").await?;
/// Ok(())
/// }
/// ```
pub async fn remove_file<P>(path: P) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -188,7 +632,44 @@ where
Ok(())
}
pub async fn rename<P, Q>(from: P, to: Q) -> Result<(), Error>
/// Rename a file or directory to a new name, replacing the original file if
/// `to` already exists.
///
/// This will not work if the new name is on a different mount point.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `rename` function on Unix
/// and the `MoveFileEx` function with the `MOVEFILE_REPLACE_EXISTING` flag on Windows.
///
/// Because of this, the behavior when both `from` and `to` exist differs. On
/// Unix, if `from` is a directory, `to` must also be an (empty) directory. If
/// `from` is not a directory, `to` must also be not a directory. In contrast,
/// on Windows, `from` can be anything, but `to` must *not* be a directory.
///
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * `from` does not exist.
/// * The user lacks permissions to view contents.
/// * `from` and `to` are on separate filesystems.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::rename("a.txt", "b.txt").await?; // Rename a.txt to b.txt
/// Ok(())
/// }
/// ```
pub async fn rename<P, Q>(from: P, to: Q) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
Q: AsRef<Path> + Send + 'static,
@ -198,7 +679,36 @@ where
Ok(())
}
pub async fn set_permissions<P>(path: P, permissions: fs::Permissions) -> Result<(), Error>
/// Changes the permissions found on a file or a directory.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `chmod` function on Unix
/// and the `SetFileAttributes` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * `path` does not exist.
/// * The user lacks the permission to change attributes of the file.
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let mut perms = actix_fs::metadata("foo.txt").await?.permissions();
/// perms.set_readonly(true);
/// actix_fs::set_permissions("foo.txt", perms).await?;
/// Ok(())
/// }
/// ```
pub async fn set_permissions<P>(path: P, permissions: fs::Permissions) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
{
@ -207,7 +717,35 @@ where
Ok(())
}
pub async fn symlink_metadata<P>(path: P) -> Result<fs::Metadata, Error>
/// Query the metadata about a file without following symlinks.
///
/// # Platform-specific behavior
///
/// This function currently corresponds to the `lstat` function on Unix
/// and the `GetFileAttributesEx` function on Windows.
/// Note that, this [may change in the future][changes].
///
/// [changes]: ../io/index.html#platform-specific-behavior
///
/// # Errors
///
/// This function will return an error in the following situations, but is not
/// limited to just these cases:
///
/// * The user lacks permissions to perform `metadata` call on `path`.
/// * `path` does not exist.
///
/// # Examples
///
/// ```rust,no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let attr = actix_fs::symlink_metadata("/some/file/path.txt").await?;
/// // inspect attr ...
/// Ok(())
/// }
/// ```
pub async fn symlink_metadata<P>(path: P) -> Result<fs::Metadata>
where
P: AsRef<Path> + Send + 'static,
{
@ -216,19 +754,63 @@ where
Ok(metadata)
}
pub async fn write<P>(path: P, contents: Bytes) -> Result<(), Error>
/// Write bytes as the entire contents of a file.
///
/// This function will create a file if it does not exist,
/// and will entirely replace its contents if it does.
///
/// This is a convenience function for using [`File::create`] and [`write_all`]
/// with fewer imports.
///
/// [`file::create`]: struct.File.html#method.create
/// [`write_all`]: ../io/trait.Write.html#method.write_all
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// actix_fs::write("foo.txt", b"Lorem ipsum").await?;
/// actix_fs::write("bar.txt", "dolor sit").await?;
/// Ok(())
/// }
/// ```
pub async fn write<P, B>(path: P, contents: B) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
B: Into<Bytes>,
{
let f = file::create(path).await?;
file::write(f, contents).await
file::write(f, contents.into()).await
}
pub async fn write_stream<P, S, E>(path: P, stream: S) -> Result<(), E>
/// Write the bytes stream as the entire contents of a file.
///
/// This function will create a file if it does not exist,
/// and will entirely replace its contents if it does.
///
/// This is a convenience function for using [`File::create`] and [`write_all`]
/// with fewer imports.
///
/// [`file::create`]: struct.File.html#method.create
/// [`write_all`]: ../io/trait.Write.html#method.write_all
///
/// # Examples
///
/// ```no_run
/// #[actix_rt::main]
/// async fn main() -> actix_fs::Result<()> {
/// let mut stream = actix_fs::read_to_stream("foo.txt").await?;
///
/// actix_fs::write_stream("bar.txt", stream).await?;
/// Ok(())
/// }
/// ```
pub async fn write_stream<P, S, E>(path: P, stream: S) -> Result<()>
where
P: AsRef<Path> + Send + 'static,
S: Stream<Item = Result<Bytes, E>> + Unpin,
S: Stream<Item = Result<Bytes>> + Unpin,
E: From<Error> + Unpin,
{
let f = file::create(path).await?;