blob: 2c6e229d2f8d60bb422c8b98911bc62ab9468ede [file] [log] [blame]
// Copyright (C) 2017-2018 Baidu, Inc. All Rights Reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in
// the documentation and/or other materials provided with the
// distribution.
// * Neither the name of Baidu, Inc., nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
use sgx_trts::libc;
#[cfg(feature = "untrusted_fs")]
use fs::{self, Permissions, OpenOptions};
#[cfg(not(feature = "untrusted_fs"))]
use untrusted::fs::{self, Permissions, OpenOptions};
use io;
use path::Path;
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
use os::fs::MetadataExt as UnixMetadataExt;
/// Unix-specific extensions to `File`
pub trait FileExt {
/// Reads a number of bytes starting from a given offset.
///
/// Returns the number of bytes read.
///
/// The offset is relative to the start of the file and thus independent
/// from the current cursor.
///
/// The current file cursor is not affected by this function.
///
/// Note that similar to `File::read`, it is not an error to return with a
/// short read.
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
/// Writes a number of bytes starting from a given offset.
///
/// Returns the number of bytes written.
///
/// The offset is relative to the start of the file and thus independent
/// from the current cursor.
///
/// The current file cursor is not affected by this function.
///
/// When writing beyond the end of the file, the file is appropriately
/// extended and the intermediate bytes are initialized with the value 0.
///
/// Note that similar to `File::write`, it is not an error to return a
/// short write.
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
}
impl FileExt for fs::File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_inner().read_at(buf, offset)
}
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_inner().write_at(buf, offset)
}
}
/// Unix-specific extensions to `Permissions`
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
/// Unix permissions for this file.
///
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
///
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Unix
/// permission bits.
///
fn from_mode(mode: u32) -> Self;
}
impl PermissionsExt for Permissions {
fn mode(&self) -> u32 {
self.as_inner().mode()
}
fn set_mode(&mut self, mode: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mode));
}
fn from_mode(mode: u32) -> Permissions {
Permissions::from_inner(FromInner::from_inner(mode))
}
}
/// Unix-specific extensions to `OpenOptions`
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
///
fn mode(&mut self, mode: u32) -> &mut Self;
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
///
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags); self
}
}
// Hm, why are there casts here to the returned type, shouldn't the types always
// be the same? Right you are! Turns out, however, on android at least the types
// in the raw `stat` structure are not the same as the types being returned. Who
// knew!
//
// As a result to make sure this compiles for all platforms we do the manual
// casts and rely on manual lowering to `stat` if the raw type is desired.
pub trait MetadataExt {
/// Returns the ID of the device containing the file.
///
fn dev(&self) -> u64;
/// Returns the inode number.
///
fn ino(&self) -> u64;
/// Returns the rights applied to this file.
///
fn mode(&self) -> u32;
/// Returns the number of hard links pointing to this file.
///
fn nlink(&self) -> u64;
/// Returns the user ID of the owner of this file.
///
fn uid(&self) -> u32;
/// Returns the group ID of the owner of this file.
///
fn gid(&self) -> u32;
/// Returns the device ID of this file (if it is a special one).
///
fn rdev(&self) -> u64;
/// Returns the total size of this file in bytes.
///
fn size(&self) -> u64;
/// Returns the time of the last access to the file.
///
fn atime(&self) -> i64;
/// Returns the time of the last access to the file in nanoseconds.
///
fn atime_nsec(&self) -> i64;
/// Returns the time of the last modification of the file.
///
fn mtime(&self) -> i64;
/// Returns the time of the last modification of the file in nanoseconds.
///
fn mtime_nsec(&self) -> i64;
/// Returns the time of the last status change of the file.
///
fn ctime(&self) -> i64;
/// Returns the time of the last status change of the file in nanoseconds.
///
fn ctime_nsec(&self) -> i64;
/// Returns the blocksize for filesystem I/O.
///
fn blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, in 512-byte units.
///
/// Please note that this may be smaller than `st_size / 512` when the file has holes.
///
fn blocks(&self) -> u64;
}
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 { self.st_dev() }
fn ino(&self) -> u64 { self.st_ino() }
fn mode(&self) -> u32 { self.st_mode() }
fn nlink(&self) -> u64 { self.st_nlink() }
fn uid(&self) -> u32 { self.st_uid() }
fn gid(&self) -> u32 { self.st_gid() }
fn rdev(&self) -> u64 { self.st_rdev() }
fn size(&self) -> u64 { self.st_size() }
fn atime(&self) -> i64 { self.st_atime() }
fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
fn mtime(&self) -> i64 { self.st_mtime() }
fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
fn ctime(&self) -> i64 { self.st_ctime() }
fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
fn blksize(&self) -> u64 { self.st_blksize() }
fn blocks(&self) -> u64 { self.st_blocks() }
}
/// Add support for special unix types (block/char device, fifo and socket).
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
///
fn is_block_device(&self) -> bool;
/// Returns whether this file type is a char device.
///
fn is_char_device(&self) -> bool;
/// Returns whether this file type is a fifo.
///
fn is_fifo(&self) -> bool;
/// Returns whether this file type is a socket.
///
fn is_socket(&self) -> bool;
}
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
}
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory. Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory. Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs::symlink(src.as_ref(), dst.as_ref())
}