From d3ed9a9e3bbcbdb6b098f8b7c8edc283f317cd30 Mon Sep 17 00:00:00 2001 From: Jeff Olson Date: Mon, 16 Sep 2013 23:10:03 -0700 Subject: [PATCH] std: lots of docs for std::rt::io::file i hope they don't bitrot --- src/libstd/rt/io/file.rs | 350 +++++++++++++++++++++++++++++++++------ 1 file changed, 298 insertions(+), 52 deletions(-) diff --git a/src/libstd/rt/io/file.rs b/src/libstd/rt/io/file.rs index ee96583206a..8227f3a1cb5 100644 --- a/src/libstd/rt/io/file.rs +++ b/src/libstd/rt/io/file.rs @@ -23,7 +23,73 @@ use option::{Some, None}; use path::Path; use super::super::test::*; -/// Open a file for reading/writing, as indicated by `path`. +/*! Synchronous File I/O + +This module provides a set of functions and traits for working +with regular files & directories on a filesystem. + +At the top-level of the module are a set of freestanding functions, +associated with various filesystem operations. They all operate +on a `PathLike` object. + +All operations in this module, including those as part of `FileStream` et al +block the task during execution. Most will raise `std::rt::io::{io_error,read_error}` +conditions in the event of failure. + +Also included in this module are the `FileInfo` and `DirectoryInfo` traits. When +`use`'d alongside a value whose type implements them (A `std::path::Path` impl is +a part of this module), they expose a set of functions for operations against +a given file location, depending on whether the path already exists. Whenever +possible, the `{FileInfo, DirectoryInfo}` preserve the same semantics as their +free function counterparts. +*/ + +/*! Open a file for reading/writing, as indicated by `path`. + +# Example + + use std; + use std::path::Path; + use std::rt::io::support::PathLike; + use std::rt::io::file::open; + use std::rt::io::{FileMode, FileAccess}; + + let p = &Path("/some/file/path.txt"); + + do io_error::cond.trap(|_| { + // hoo-boy... + }).inside { + let stream = match open(p, Create, ReadWrite) { + Some(s) => s, + None => fail!("whoops! I'm sure this raised, anyways.."); + } + // do some stuff with that stream + + // the file stream will be closed at the end of this block + } + // .. + +`FileMode` and `FileAccess` provide information about the permissions +context in which a given stream is created. More information about them +can be found in `std::rt::io`'s docs. + +Note that, with this function, a `FileStream` is returned regardless of +the access-limitations indicated by `FileAccess` (e.g. calling `write` on a +`FileStream` opened as `ReadOnly` will raise an `io_error` condition at runtime). If you +desire a more-correctly-constrained interface to files, use the +`{open_stream, open_reader, open_writer}` methods that are a part of `FileInfo` + +# Errors + +This function will raise an `io_error` condition under a number of different circumstances, +to include but not limited to: + +* Opening a file that already exists with `FileMode` of `Create` or vice versa (e.g. + opening a non-existant file with `FileMode` or `Open`) +* Attempting to open a file with a `FileAccess` that the user lacks permissions + for +* Filesystem-level errors (full disk, etc) +*/ pub fn open(path: &P, mode: FileMode, access: FileAccess @@ -44,8 +110,29 @@ pub fn open(path: &P, } } -/// Unlink (remove) a file from the filesystem, as indicated -/// by `path`. +/*! Unlink a file from the underlying filesystem. + +# Example + + use std; + use std::path::Path; + use std::rt::io::support::PathLike; + use std::rt::io::file::unlink; + + let p = &Path("/some/file/path.txt"); + unlink(p); + // if we made it here without failing, then the + // unlink operation was successful + +Note that, just because an unlink call was successful, it is not +guaranteed that a file is immediately deleted (e.g. depending on +platform, other open file descriptors may prevent immediate removal) + +# Errors + +This function will raise an `io_error` condition if the user lacks permissions to +remove the file or if some other filesystem-level error occurs +*/ pub fn unlink(path: &P) { let unlink_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); @@ -59,8 +146,24 @@ pub fn unlink(path: &P) { } } -/// Create a new directory with default permissions (process user -/// has read/write privs) +/*! Create a new, empty directory at the provided path + +# Example + + use std; + use std::path::Path; + use std::rt::io::support::PathLike; + use std::rt::io::file::mkdir; + + let p = &Path("/some/dir"); + mkdir(p); + // If we got here, our directory exists! Horray! + +# Errors + +This call will raise an `io_error` condition if the user lacks permissions to make a +new directory at the provided path, or if the directory already exists +*/ pub fn mkdir(path: &P) { let mkdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); @@ -73,7 +176,25 @@ pub fn mkdir(path: &P) { } } } -/// Removes a directory + +/*! Remove an existing, empty directory + +# Example + + use std; + use std::path::Path; + use std::rt::io::support::PathLike; + use std::rt::io::file::rmdir; + + let p = &Path("/some/dir"); + rmdir(p); + // good riddance, you mean ol' directory + +# Errors + +This call will raise an `io_error` condition if the user lacks permissions to remove the +directory at the provided path, or if the directory isn't empty +*/ pub fn rmdir(path: &P) { let rmdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); @@ -87,11 +208,43 @@ pub fn rmdir(path: &P) { } } -/// Given a `rt::io::support::PathLike`, query the file system to get -/// information about a file, directory, etc. -/// -/// Returns a `Some(PathInfo)` on success, and raises a `rt::io::IoError` condition -/// on failure and returns `None`. +/*! Get information on the file, directory, etc at the provided path + +Given a `rt::io::support::PathLike`, query the file system to get +information about a file, directory, etc. + +Returns a `Some(std::rt::io::PathInfo)` on success + +# Example + + use std; + use std::path::Path; + use std::rt::io::support::PathLike; + use std::rt::io::file::stat; + + let p = &Path("/some/file/path.txt"); + + do io_error::cond.trap(|_| { + // hoo-boy... + }).inside { + let info = match stat(p) { + Some(s) => s, + None => fail!("whoops! I'm sure this raised, anyways.."); + } + if stat.is_file { + // just imagine the possibilities ... + } + + // the file stream will be closed at the end of this block + } + // .. + +# Errors + +This call will raise an `io_error` condition if the user lacks the requisite +permissions to perform a `stat` call on the given path or if there is no +entry in the filesystem at the provided path. +*/ pub fn stat(path: &P) -> Option { let open_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); @@ -108,6 +261,8 @@ pub fn stat(path: &P) -> Option { } } +/*! Retrieve a vector containing all entries within a provided directory +*/ pub fn readdir(path: &P) -> Option<~[Path]> { let readdir_result = unsafe { let io: *mut IoFactoryObject = Local::unsafe_borrow(); @@ -124,9 +279,13 @@ pub fn readdir(path: &P) -> Option<~[Path]> { } } -/// Read-only view of file +/*! Constrained version of `FileStream` that only exposes read-specific operations. + +Can be retreived via `FileInfo.open_reader()`. +*/ pub struct FileReader { priv stream: FileStream } +/// a `std::rt::io::Reader` trait impl for file I/O. impl Reader for FileReader { fn read(&mut self, buf: &mut [u8]) -> Option { self.stream.read(buf) @@ -137,6 +296,7 @@ impl Reader for FileReader { } } +/// a `std::rt::io::Seek` trait impl for file I/O. impl Seek for FileReader { fn tell(&self) -> u64 { self.stream.tell() @@ -147,9 +307,13 @@ impl Seek for FileReader { } } -/// Write-only view of a file +/*! Constrained version of `FileStream` that only exposes write-specific operations. + +Can be retreived via `FileInfo.open_writer()`. +*/ pub struct FileWriter { priv stream: FileStream } +/// a `std::rt::io::Writer` trait impl for file I/O. impl Writer for FileWriter { fn write(&mut self, buf: &[u8]) { self.stream.write(buf); @@ -160,6 +324,7 @@ impl Writer for FileWriter { } } +/// a `std::rt::io::Seek` trait impl for file I/O. impl Seek for FileWriter { fn tell(&self) -> u64 { self.stream.tell() @@ -170,13 +335,25 @@ impl Seek for FileWriter { } } -/// Internal representation of a FileStream, used to consolidate functionality -/// exposed in the public API +/*! Unconstrained file access type that exposes read and write operations + +Can be retreived via `file::open()` and `FileInfo.open_stream()`. + +# Errors + +This type will raise an io_error condition if operations are attempted against +it for which its underlying file descriptor was not configured at creation +time, via the `FileAccess` parameter to `file::open()`. + +For this reason, it is best to use the access-constrained wrappers that are +exposed via `FileInfo.open_reader()` and `FileInfo.open_writer()`. +*/ pub struct FileStream { fd: ~RtioFileStream, last_nread: int, } +/// a `std::rt::io::Reader` trait impl for file I/O. impl Reader for FileStream { fn read(&mut self, buf: &mut [u8]) -> Option { match self.fd.read(buf) { @@ -202,6 +379,7 @@ impl Reader for FileStream { } } +/// a `std::rt::io::Writer` trait impl for file I/O. impl Writer for FileStream { fn write(&mut self, buf: &[u8]) { match self.fd.write(buf) { @@ -222,6 +400,7 @@ impl Writer for FileStream { } } +/// a `std::rt::io:Seek` trait impl for file I/O. impl Seek for FileStream { fn tell(&self) -> u64 { let res = self.fd.tell(); @@ -256,14 +435,21 @@ pub trait FileSystemInfo { /// later creates fn get_path<'a>(&'a self) -> &'a Path; - /// Ask the operating system for information about the path, - /// will raise a condition if an error occurs during the process + /*! Get information on the file, directory, etc at the provided path + + Consult the `file::stat` documentation for more info. + + This call preserves identical runtime/error semantics + */ fn stat(&self) -> Option { stat(self.get_path()) } - /// returns `true` if the location pointed at by the enclosing - /// exists on the filesystem + /// Boolean value indicator whether the underlying file exists on the filesystem + /// + /// # Errors + /// + /// Will not raise a condition fn exists(&self) -> bool { match ignore_io_error(|| self.stat()) { Some(_) => true, @@ -273,21 +459,32 @@ pub trait FileSystemInfo { } -/// Represents passive information about a file (primarily exposed -/// via the `stat()` method. Also provides methods for opening -/// a file in various modes/permissions. -/// -/// # Example -/// -/// * Check if a file exists, reading from it if so -/// -/// let f = &Path("/some/file/path.txt"); -/// if f.exists() { -/// let reader = f.open_reader(Open); -/// let mut mem = [0u8, 8*64000]; -/// reader.read(mem); -/// // ... -/// } +/*! Represents a file, whose underlying path may or may not be valid + +# Example + +* Check if a file exists, reading from it if so + + use std; + use std::path::Path; + use std::rt::io::file::{FileInfo, FileReader}; + + let f = &Path("/some/file/path.txt"); + if f.exists() { + let reader = f.open_reader(Open); + let mut mem = [0u8, 8*64000]; + reader.read(mem); + // ... + } + +* Is the given path a file? + + let f = get_file_path_from_wherever(); + match f.is_file() { + true => doing_something_with_a_file(f), + _ => {} + } +*/ pub trait FileInfo : FileSystemInfo { /// Whether the underlying implemention (be it a file path, /// or something else) points at a "regular file" on the FS. Will return @@ -302,6 +499,8 @@ pub trait FileInfo : FileSystemInfo { /// Attempts to open a regular file for reading/writing based /// on provided inputs + /// + /// See `file::open` for more information on runtime semantics and error conditions fn open_stream(&self, mode: FileMode, access: FileAccess) -> Option { match ignore_io_error(|| self.stat()) { Some(s) => match s.is_file { @@ -311,8 +510,11 @@ pub trait FileInfo : FileSystemInfo { None => open(self.get_path(), mode, access) } } - /// Attempts to open a regular file for reading-only based + + /// Attempts to open a regular file in read-only mode, based /// on provided inputs + /// + /// See `file::open` for more information on runtime semantics and error conditions fn open_reader(&self, mode: FileMode) -> Option { match self.open_stream(mode, Read) { Some(s) => Some(FileReader { stream: s}), @@ -320,8 +522,10 @@ pub trait FileInfo : FileSystemInfo { } } - /// Attempts to open a regular file for writing-only based + /// Attempts to open a regular file in write-only mode, based /// on provided inputs + /// + /// See `file::open` for more information on runtime semantics and error conditions fn open_writer(&self, mode: FileMode) -> Option { match self.open_stream(mode, Write) { Some(s) => Some(FileWriter { stream: s}), @@ -329,8 +533,9 @@ pub trait FileInfo : FileSystemInfo { } } - /// Attempt to remove a file from the filesystem, pending the closing - /// of any open file descriptors pointing to the file + /// Attempt to remove a file from the filesystem + /// + /// See `file::unlink` for more information on runtime semantics and error conditions fn unlink(&self) { unlink(self.get_path()); } @@ -340,16 +545,42 @@ pub trait FileInfo : FileSystemInfo { impl FileSystemInfo for Path { fn get_path<'a>(&'a self) -> &'a Path { self } } + /// `FileInfo` implementation for `Path`s impl FileInfo for Path { } -/// Passive information about a directory on the filesystem. Includes -/// Convenience methods to iterate over a directory's contents (via `readdir`, as -/// as `mkdir` and `rmdir` operations. +/*! Represents a directory, whose underlying path may or may not be valid + +# Example + +* Check if a directory exists, `mkdir`'ing it if not + + use std; + use std::path::Path; + use std::rt::io::file::{DirectoryInfo}; + + let dir = &Path("/some/dir"); + if !dir.exists() { + dir.mkdir(); + } + +* Is the given path a directory? If so, iterate on its contents + + fn visit_dirs(dir: &Path, cb: &fn(&Path)) { + if dir.is_dir() { + let contents = dir.readdir(); + for entry in contents.iter() { + if entry.is_dir() { visit_dirs(entry, cb); } + else { cb(entry); } + } + } + else { fail!("nope"); } + } +*/ trait DirectoryInfo : FileSystemInfo { /// Whether the underlying implemention (be it a file path, - /// or something else) points at a directory file" on the FS. Will return - /// false for paths to non-existent locations or if the item is + /// or something else) is pointing at a directory in the underlying FS. + /// Will return false for paths to non-existent locations or if the item is /// not a directory (eg files, named pipes, links, etc) fn is_dir(&self) -> bool { match ignore_io_error(|| self.stat()) { @@ -357,11 +588,16 @@ trait DirectoryInfo : FileSystemInfo { None => false } } + /// Create a directory at the location pointed to by the - /// type underlying the given `DirectoryInfo`. Raises a - /// condition if a file, directory, etc already exists - /// at that location or if some other error occurs during - /// the mkdir operation + /// type underlying the given `DirectoryInfo`. + /// + /// # Errors + /// + /// This method will raise a `PathAlreadyExists` kind of `io_error` condition + /// if the provided path exists + /// + /// See `file::mkdir` for more information on runtime semantics and error conditions fn mkdir(&self) { match ignore_io_error(|| self.stat()) { Some(_) => { @@ -375,9 +611,17 @@ trait DirectoryInfo : FileSystemInfo { None => mkdir(self.get_path()) } } - /// Remove a directory at the given location pointed to by - /// the type underlying the given `DirectoryInfo`. Will fail - /// if there is no directory at the given location or if + + /// Remove a directory at the given location. + /// + /// # Errors + /// + /// This method will raise a `PathDoesntExist` kind of `io_error` condition + /// if the provided path exists. It will raise a `MismatchedFileTypeForOperation` + /// kind of `io_error` condition if the provided path points at any + /// non-directory file type + /// + /// See `file::rmdir` for more information on runtime semantics and error conditions fn rmdir(&self) { match ignore_io_error(|| self.stat()) { Some(s) => { @@ -403,13 +647,15 @@ trait DirectoryInfo : FileSystemInfo { }) } } + + // Get a collection of all entries at the given + // directory fn readdir(&self) -> Option<~[Path]> { readdir(self.get_path()) } - //fn get_subdirs(&self, filter: &str) -> ~[Path]; - //fn get_files(&self, filter: &str) -> ~[Path]; } +/// `DirectoryInfo` impl for `path::Path` impl DirectoryInfo for Path { } fn file_test_smoke_test_impl() {