diff options
| author | Fenrir <[email protected]> | 2018-01-21 14:06:28 -0700 |
|---|---|---|
| committer | FenrirWolf <[email protected]> | 2018-01-21 19:16:33 -0700 |
| commit | 23be3f4885688e5e0011005e2295c75168854c0a (patch) | |
| tree | dd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/sys/unix/fs.rs | |
| parent | Update CI for Rust nightly-2017-12-01 + other fixes (diff) | |
| download | ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip | |
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/sys/unix/fs.rs')
| -rw-r--r-- | ctr-std/src/sys/unix/fs.rs | 131 |
1 files changed, 114 insertions, 17 deletions
diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs index 06413c3..f30b270 100644 --- a/ctr-std/src/sys/unix/fs.rs +++ b/ctr-std/src/sys/unix/fs.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(dead_code)] + use os::unix::prelude::*; use ffi::{CString, CStr, OsString, OsStr}; @@ -23,8 +25,8 @@ use sys::time::SystemTime; use sys::{cvt, cvt_r}; use sys_common::{AsInner, FromInner}; -use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek as lseek64, - dirent as dirent64, open as open64, ftruncate as ftruncate64, off_t as off64_t}; +use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t, + ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64}; use libc::{readdir_r as readdir64_r}; pub struct File(FileDesc); @@ -47,6 +49,12 @@ unsafe impl Sync for Dir {} pub struct DirEntry { entry: dirent64, root: Arc<PathBuf>, + // We need to store an owned copy of the directory name + // on Solaris and Fuchsia because a) it uses a zero-length + // array to store the name, b) its lifetime between readdir + // calls is not guaranteed. + #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] + name: Box<[u8]> } #[derive(Clone, Debug)] @@ -75,7 +83,7 @@ pub struct DirBuilder { mode: mode_t } impl FileAttr { pub fn size(&self) -> u64 { self.stat.st_size as u64 } pub fn perm(&self) -> FilePermissions { - FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 } + FilePermissions { mode: (self.stat.st_mode as mode_t) } } pub fn file_type(&self) -> FileType { @@ -85,17 +93,15 @@ impl FileAttr { impl FileAttr { pub fn modified(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_mtime as libc::time_t, - tv_nsec: 0, - })) + Err(io::Error::new(io::ErrorKind::Other, + "modification time is not available on this platform \ + currently")) } pub fn accessed(&self) -> io::Result<SystemTime> { - Ok(SystemTime::from(libc::timespec { - tv_sec: self.stat.st_atime as libc::time_t, - tv_nsec: 0, - })) + Err(io::Error::new(io::ErrorKind::Other, + "access time is not available on this platform \ + currently")) } pub fn created(&self) -> io::Result<SystemTime> { @@ -110,11 +116,17 @@ impl AsInner<stat64> for FileAttr { } impl FilePermissions { - pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 } + pub fn readonly(&self) -> bool { + // check if any class (owner, group, others) has write permission + self.mode & 0o222 == 0 + } + pub fn set_readonly(&mut self, readonly: bool) { if readonly { + // remove write permission for all classes; equivalent to `chmod a-w <file>` self.mode &= !0o222; } else { + // add write permission for all classes; equivalent to `chmod a+w <file>` self.mode |= 0o222; } } @@ -146,6 +158,42 @@ impl fmt::Debug for ReadDir { impl Iterator for ReadDir { type Item = io::Result<DirEntry>; + #[cfg(any(target_os = "solaris", target_os = "fuchsia"))] + fn next(&mut self) -> Option<io::Result<DirEntry>> { + unsafe { + loop { + // Although readdir_r(3) would be a correct function to use here because + // of the thread safety, on Illumos and Fuchsia the readdir(3C) function + // is safe to use in threaded applications and it is generally preferred + // over the readdir_r(3C) function. + super::os::set_errno(0); + let entry_ptr = libc::readdir(self.dirp.0); + if entry_ptr.is_null() { + // NULL can mean either the end is reached or an error occurred. + // So we had to clear errno beforehand to check for an error now. + return match super::os::errno() { + 0 => None, + e => Some(Err(Error::from_raw_os_error(e))), + } + } + + let name = (*entry_ptr).d_name.as_ptr(); + let namelen = libc::strlen(name) as usize; + + let ret = DirEntry { + entry: *entry_ptr, + name: ::slice::from_raw_parts(name as *const u8, + namelen as usize).to_owned().into_boxed_slice(), + root: self.root.clone() + }; + if ret.name_bytes() != b"." && ret.name_bytes() != b".." { + return Some(Ok(ret)) + } + } + } + } + + #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))] fn next(&mut self) -> Option<io::Result<DirEntry>> { unsafe { let mut ret = DirEntry { @@ -188,6 +236,12 @@ impl DirEntry { lstat(&self.path()) } + #[cfg(any(target_os = "solaris", target_os = "haiku"))] + pub fn file_type(&self) -> io::Result<FileType> { + lstat(&self.path()).map(|m| m.file_type()) + } + + #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -293,7 +347,7 @@ impl File { // Linux kernel then the flag is just ignored by the OS, so we continue // to explicitly ask for a CLOEXEC fd here. // - // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc + // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. if cfg!(target_os = "linux") { fd.set_cloexec()?; @@ -323,6 +377,10 @@ impl File { } pub fn truncate(&self, size: u64) -> io::Result<()> { + #[cfg(target_os = "android")] + return ::sys::android::ftruncate64(self.0.raw(), size); + + #[cfg(not(target_os = "android"))] return cvt_r(|| unsafe { ftruncate64(self.0.raw(), size as off64_t) }).map(|_| ()); @@ -332,10 +390,6 @@ impl File { self.0.read(buf) } - pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { - self.0.read_to_end(buf) - } - pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.0.read_at(buf, offset) } @@ -358,6 +412,8 @@ impl File { SeekFrom::End(off) => (libc::SEEK_END, off), SeekFrom::Current(off) => (libc::SEEK_CUR, off), }; + #[cfg(target_os = "emscripten")] + let pos = pos as i32; let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?; Ok(n as u64) } @@ -404,11 +460,52 @@ impl FromInner<c_int> for File { impl fmt::Debug for File { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + #[cfg(target_os = "linux")] + fn get_path(fd: c_int) -> Option<PathBuf> { + let mut p = PathBuf::from("/proc/self/fd"); + p.push(&fd.to_string()); + readlink(&p).ok() + } + + #[cfg(target_os = "macos")] + fn get_path(fd: c_int) -> Option<PathBuf> { + // FIXME: The use of PATH_MAX is generally not encouraged, but it + // is inevitable in this case because macOS defines `fcntl` with + // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no + // alternatives. If a better method is invented, it should be used + // instead. + let mut buf = vec![0;libc::PATH_MAX as usize]; + let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) }; + if n == -1 { + return None; + } + let l = buf.iter().position(|&c| c == 0).unwrap(); + buf.truncate(l as usize); + buf.shrink_to_fit(); + Some(PathBuf::from(OsString::from_vec(buf))) + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_path(_fd: c_int) -> Option<PathBuf> { // FIXME(#24570): implement this for other Unix platforms None } + #[cfg(any(target_os = "linux", target_os = "macos"))] + fn get_mode(fd: c_int) -> Option<(bool, bool)> { + let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) }; + if mode == -1 { + return None; + } + match mode & libc::O_ACCMODE { + libc::O_RDONLY => Some((true, false)), + libc::O_RDWR => Some((true, true)), + libc::O_WRONLY => Some((false, true)), + _ => None + } + } + + #[cfg(not(any(target_os = "linux", target_os = "macos")))] fn get_mode(_fd: c_int) -> Option<(bool, bool)> { // FIXME(#24570): implement this for other Unix platforms None |