From 0c1e1ff1e300868a29405a334e65eae690df971d Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 30 Sep 2014 17:34:14 -0700 Subject: Runtime removal: refactor fs This moves the filesystem implementation from libnative into the new `sys` modules, refactoring along the way and hooking into `std::io::fs`. Because this eliminates APIs in `libnative` and `librustrt`, it is a: [breaking-change] This functionality is likely to be available publicly, in some form, from `std` in the future. --- src/libnative/io/file_unix.rs | 554 --------------------------------------- src/libnative/io/file_windows.rs | 523 ------------------------------------ src/libnative/io/mod.rs | 83 ------ src/libnative/io/timer_unix.rs | 2 +- 4 files changed, 1 insertion(+), 1161 deletions(-) delete mode 100644 src/libnative/io/file_unix.rs delete mode 100644 src/libnative/io/file_windows.rs (limited to 'src/libnative') diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs deleted file mode 100644 index f616295c73d..00000000000 --- a/src/libnative/io/file_unix.rs +++ /dev/null @@ -1,554 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Blocking posix-based file I/O - -use alloc::arc::Arc; -use libc::{mod, c_int, c_void}; -use std::c_str::CString; -use std::mem; -use std::rt::rtio::{mod, IoResult}; - -use io::{retry, keep_going}; -use io::util; - -pub type fd_t = libc::c_int; - -struct Inner { - fd: fd_t, - close_on_drop: bool, -} - -pub struct FileDesc { - inner: Arc -} - -impl FileDesc { - /// Create a `FileDesc` from an open C file descriptor. - /// - /// The `FileDesc` will take ownership of the specified file descriptor and - /// close it upon destruction if the `close_on_drop` flag is true, otherwise - /// it will not close the file descriptor when this `FileDesc` is dropped. - /// - /// Note that all I/O operations done on this object will be *blocking*, but - /// they do not require the runtime to be active. - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { inner: Arc::new(Inner { - fd: fd, - close_on_drop: close_on_drop - }) } - } - - // FIXME(#10465) these functions should not be public, but anything in - // native::io wanting to use them is forced to have all the - // rtio traits in scope - pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = retry(|| unsafe { - libc::read(self.fd(), - buf.as_mut_ptr() as *mut libc::c_void, - buf.len() as libc::size_t) - }); - if ret == 0 { - Err(util::eof()) - } else if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as uint) - } - } - pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> { - let ret = keep_going(buf, |buf, len| { - unsafe { - libc::write(self.fd(), buf as *const libc::c_void, - len as libc::size_t) as i64 - } - }); - if ret < 0 { - Err(super::last_error()) - } else { - Ok(()) - } - } - - pub fn fd(&self) -> fd_t { self.inner.fd } -} - -impl rtio::RtioFileStream for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf).map(|i| i as int) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { - match retry(|| unsafe { - libc::pread(self.fd(), buf.as_ptr() as *mut _, - buf.len() as libc::size_t, - offset as libc::off_t) - }) { - -1 => Err(super::last_error()), - n => Ok(n as int) - } - } - fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { - libc::pwrite(self.fd(), buf.as_ptr() as *const _, - buf.len() as libc::size_t, offset as libc::off_t) - })) - } - fn seek(&mut self, pos: i64, whence: rtio::SeekStyle) -> IoResult { - let whence = match whence { - rtio::SeekSet => libc::SEEK_SET, - rtio::SeekEnd => libc::SEEK_END, - rtio::SeekCur => libc::SEEK_CUR, - }; - let n = unsafe { libc::lseek(self.fd(), pos as libc::off_t, whence) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } - } - fn tell(&self) -> IoResult { - let n = unsafe { libc::lseek(self.fd(), 0, libc::SEEK_CUR) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } - } - fn fsync(&mut self) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { libc::fsync(self.fd()) })) - } - fn datasync(&mut self) -> IoResult<()> { - return super::mkerr_libc(os_datasync(self.fd())); - - #[cfg(any(target_os = "macos", target_os = "ios"))] - fn os_datasync(fd: c_int) -> c_int { - unsafe { libc::fcntl(fd, libc::F_FULLFSYNC) } - } - #[cfg(target_os = "linux")] - fn os_datasync(fd: c_int) -> c_int { - retry(|| unsafe { libc::fdatasync(fd) }) - } - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] - fn os_datasync(fd: c_int) -> c_int { - retry(|| unsafe { libc::fsync(fd) }) - } - } - fn truncate(&mut self, offset: i64) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { - libc::ftruncate(self.fd(), offset as libc::off_t) - })) - } - - fn fstat(&mut self) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::fstat(self.fd(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - } -} - -impl rtio::RtioPipe for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn clone(&self) -> Box { - box FileDesc { inner: self.inner.clone() } as Box - } - - // Only supported on named pipes currently. Note that this doesn't have an - // impact on the std::io primitives, this is never called via - // std::io::PipeStream. If the functionality is exposed in the future, then - // these methods will need to be implemented. - fn close_read(&mut self) -> IoResult<()> { - Err(super::unimpl()) - } - fn close_write(&mut self) -> IoResult<()> { - Err(super::unimpl()) - } - fn set_timeout(&mut self, _t: Option) {} - fn set_read_timeout(&mut self, _t: Option) {} - fn set_write_timeout(&mut self, _t: Option) {} -} - -impl rtio::RtioTTY for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn set_raw(&mut self, _raw: bool) -> IoResult<()> { - Err(super::unimpl()) - } - fn get_winsize(&mut self) -> IoResult<(int, int)> { - Err(super::unimpl()) - } - fn isatty(&self) -> bool { false } -} - -impl Drop for Inner { - fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.close_on_drop && self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, - self.fd); - } - } - } -} - -pub struct CFile { - file: *mut libc::FILE, - fd: FileDesc, -} - -impl CFile { - /// Create a `CFile` from an open `FILE` pointer. - /// - /// The `CFile` takes ownership of the `FILE` pointer and will close it upon - /// destruction. - pub fn new(file: *mut libc::FILE) -> CFile { - CFile { - file: file, - fd: FileDesc::new(unsafe { libc::fileno(file) }, false) - } - } - - pub fn flush(&mut self) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { libc::fflush(self.file) })) - } -} - -impl rtio::RtioFileStream for CFile { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - let ret = keep_going(buf, |buf, len| { - unsafe { - libc::fread(buf as *mut libc::c_void, 1, len as libc::size_t, - self.file) as i64 - } - }); - if ret == 0 { - Err(util::eof()) - } else if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as int) - } - } - - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - let ret = keep_going(buf, |buf, len| { - unsafe { - libc::fwrite(buf as *const libc::c_void, 1, len as libc::size_t, - self.file) as i64 - } - }); - if ret < 0 { - Err(super::last_error()) - } else { - Ok(()) - } - } - - fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { - self.flush().and_then(|()| self.fd.pread(buf, offset)) - } - fn pwrite(&mut self, buf: &[u8], offset: u64) -> IoResult<()> { - self.flush().and_then(|()| self.fd.pwrite(buf, offset)) - } - fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult { - let whence = match style { - rtio::SeekSet => libc::SEEK_SET, - rtio::SeekEnd => libc::SEEK_END, - rtio::SeekCur => libc::SEEK_CUR, - }; - let n = unsafe { libc::fseek(self.file, pos as libc::c_long, whence) }; - if n < 0 { - Err(super::last_error()) - } else { - Ok(n as u64) - } - } - fn tell(&self) -> IoResult { - let ret = unsafe { libc::ftell(self.file) }; - if ret < 0 { - Err(super::last_error()) - } else { - Ok(ret as u64) - } - } - fn fsync(&mut self) -> IoResult<()> { - self.flush().and_then(|()| self.fd.fsync()) - } - fn datasync(&mut self) -> IoResult<()> { - self.flush().and_then(|()| self.fd.datasync()) - } - fn truncate(&mut self, offset: i64) -> IoResult<()> { - self.flush().and_then(|()| self.fd.truncate(offset)) - } - - fn fstat(&mut self) -> IoResult { - self.flush().and_then(|()| self.fd.fstat()) - } -} - -impl Drop for CFile { - fn drop(&mut self) { - unsafe { let _ = libc::fclose(self.file); } - } -} - -pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) - -> IoResult -{ - let flags = match fm { - rtio::Open => 0, - rtio::Append => libc::O_APPEND, - rtio::Truncate => libc::O_TRUNC, - }; - // Opening with a write permission must silently create the file. - let (flags, mode) = match fa { - rtio::Read => (flags | libc::O_RDONLY, 0), - rtio::Write => (flags | libc::O_WRONLY | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - rtio::ReadWrite => (flags | libc::O_RDWR | libc::O_CREAT, - libc::S_IRUSR | libc::S_IWUSR), - }; - - match retry(|| unsafe { libc::open(path.as_ptr(), flags, mode) }) { - -1 => Err(super::last_error()), - fd => Ok(FileDesc::new(fd, true)), - } -} - -pub fn mkdir(p: &CString, mode: uint) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::mkdir(p.as_ptr(), mode as libc::mode_t) }) -} - -pub fn readdir(p: &CString) -> IoResult> { - use libc::{dirent_t}; - use libc::{opendir, readdir_r, closedir}; - - fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; - let root = Path::new(root); - - dirs.into_iter().filter(|path| { - path.as_vec() != b"." && path.as_vec() != b".." - }).map(|path| root.join(path).to_c_str()).collect() - } - - extern { - fn rust_dirent_t_size() -> libc::c_int; - fn rust_list_dir_val(ptr: *mut dirent_t) -> *const libc::c_char; - } - - let size = unsafe { rust_dirent_t_size() }; - let mut buf = Vec::::with_capacity(size as uint); - let ptr = buf.as_mut_slice().as_mut_ptr() as *mut dirent_t; - - let dir_ptr = unsafe {opendir(p.as_ptr())}; - - if dir_ptr as uint != 0 { - let mut paths = vec!(); - let mut entry_ptr = 0 as *mut dirent_t; - while unsafe { readdir_r(dir_ptr, ptr, &mut entry_ptr) == 0 } { - if entry_ptr.is_null() { break } - let cstr = unsafe { - CString::new(rust_list_dir_val(entry_ptr), false) - }; - paths.push(Path::new(cstr)); - } - assert_eq!(unsafe { closedir(dir_ptr) }, 0); - Ok(prune(p, paths)) - } else { - Err(super::last_error()) - } -} - -pub fn unlink(p: &CString) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::unlink(p.as_ptr()) }) -} - -pub fn rename(old: &CString, new: &CString) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::rename(old.as_ptr(), new.as_ptr()) }) -} - -pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { - libc::chmod(p.as_ptr(), mode as libc::mode_t) - })) -} - -pub fn rmdir(p: &CString) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::rmdir(p.as_ptr()) }) -} - -pub fn chown(p: &CString, uid: int, gid: int) -> IoResult<()> { - super::mkerr_libc(retry(|| unsafe { - libc::chown(p.as_ptr(), uid as libc::uid_t, - gid as libc::gid_t) - })) -} - -pub fn readlink(p: &CString) -> IoResult { - let p = p.as_ptr(); - let mut len = unsafe { libc::pathconf(p as *mut _, libc::_PC_NAME_MAX) }; - if len == -1 { - len = 1024; // FIXME: read PATH_MAX from C ffi? - } - let mut buf: Vec = Vec::with_capacity(len as uint); - match unsafe { - libc::readlink(p, buf.as_ptr() as *mut libc::c_char, - len as libc::size_t) as libc::c_int - } { - -1 => Err(super::last_error()), - n => { - assert!(n > 0); - unsafe { buf.set_len(n as uint); } - Ok(buf.as_slice().to_c_str()) - } - } -} - -pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::symlink(src.as_ptr(), dst.as_ptr()) }) -} - -pub fn link(src: &CString, dst: &CString) -> IoResult<()> { - super::mkerr_libc(unsafe { libc::link(src.as_ptr(), dst.as_ptr()) }) -} - -fn mkstat(stat: &libc::stat) -> rtio::FileStat { - // FileStat times are in milliseconds - fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn flags(stat: &libc::stat) -> u64 { stat.st_flags as u64 } - #[cfg(any(target_os = "linux", target_os = "android"))] - fn flags(_stat: &libc::stat) -> u64 { 0 } - - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn gen(stat: &libc::stat) -> u64 { stat.st_gen as u64 } - #[cfg(any(target_os = "linux", target_os = "android"))] - fn gen(_stat: &libc::stat) -> u64 { 0 } - - rtio::FileStat { - size: stat.st_size as u64, - kind: stat.st_mode as u64, - perm: stat.st_mode as u64, - created: mktime(stat.st_ctime as u64, stat.st_ctime_nsec as u64), - modified: mktime(stat.st_mtime as u64, stat.st_mtime_nsec as u64), - accessed: mktime(stat.st_atime as u64, stat.st_atime_nsec as u64), - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: stat.st_blksize as u64, - blocks: stat.st_blocks as u64, - flags: flags(stat), - gen: gen(stat), - } -} - -pub fn stat(p: &CString) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::stat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -pub fn lstat(p: &CString) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::lstat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> { - let buf = libc::utimbuf { - actime: (atime / 1000) as libc::time_t, - modtime: (mtime / 1000) as libc::time_t, - }; - super::mkerr_libc(unsafe { libc::utime(p.as_ptr(), &buf) }) -} - -#[cfg(test)] -mod tests { - use super::{CFile, FileDesc}; - use libc; - use std::os; - use std::rt::rtio::{RtioFileStream, SeekSet}; - - #[cfg_attr(target_os = "freebsd", ignore)] // hmm, maybe pipes have a tiny buffer - #[test] - fn test_file_desc() { - // Run this test with some pipes so we don't have to mess around with - // opening or closing files. - let os::Pipe { reader, writer } = unsafe { os::pipe().unwrap() }; - let mut reader = FileDesc::new(reader, true); - let mut writer = FileDesc::new(writer, true); - - writer.inner_write(b"test").ok().unwrap(); - let mut buf = [0u8, ..4]; - match reader.inner_read(buf) { - Ok(4) => { - assert_eq!(buf[0], 't' as u8); - assert_eq!(buf[1], 'e' as u8); - assert_eq!(buf[2], 's' as u8); - assert_eq!(buf[3], 't' as u8); - } - r => panic!("invalid read: {}", r), - } - - assert!(writer.inner_read(buf).is_err()); - assert!(reader.inner_write(buf).is_err()); - } - - #[test] - fn test_cfile() { - unsafe { - let f = libc::tmpfile(); - assert!(!f.is_null()); - let mut file = CFile::new(f); - - file.write(b"test").ok().unwrap(); - let mut buf = [0u8, ..4]; - let _ = file.seek(0, SeekSet).ok().unwrap(); - match file.read(buf) { - Ok(4) => { - assert_eq!(buf[0], 't' as u8); - assert_eq!(buf[1], 'e' as u8); - assert_eq!(buf[2], 's' as u8); - assert_eq!(buf[3], 't' as u8); - } - r => panic!("invalid read: {}", r) - } - } - } -} diff --git a/src/libnative/io/file_windows.rs b/src/libnative/io/file_windows.rs deleted file mode 100644 index eb4d4f22132..00000000000 --- a/src/libnative/io/file_windows.rs +++ /dev/null @@ -1,523 +0,0 @@ -// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -//! Blocking Windows-based file I/O - -use alloc::arc::Arc; -use libc::{mod, c_int}; -use std::c_str::CString; -use std::mem; -use std::os::windows::fill_utf16_buf_and_decode; -use std::ptr; -use std::rt::rtio; -use std::rt::rtio::{IoResult, IoError}; -use std::str; - -pub type fd_t = libc::c_int; - -struct Inner { - fd: fd_t, - close_on_drop: bool, -} - -pub struct FileDesc { - inner: Arc -} - -impl FileDesc { - /// Create a `FileDesc` from an open C file descriptor. - /// - /// The `FileDesc` will take ownership of the specified file descriptor and - /// close it upon destruction if the `close_on_drop` flag is true, otherwise - /// it will not close the file descriptor when this `FileDesc` is dropped. - /// - /// Note that all I/O operations done on this object will be *blocking*, but - /// they do not require the runtime to be active. - pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc { - FileDesc { inner: Arc::new(Inner { - fd: fd, - close_on_drop: close_on_drop - }) } - } - - pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult { - let mut read = 0; - let ret = unsafe { - libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut read, - ptr::null_mut()) - }; - if ret != 0 { - Ok(read as uint) - } else { - Err(super::last_error()) - } - } - pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> { - let mut cur = buf.as_ptr(); - let mut remaining = buf.len(); - while remaining > 0 { - let mut amt = 0; - let ret = unsafe { - libc::WriteFile(self.handle(), cur as libc::LPVOID, - remaining as libc::DWORD, &mut amt, - ptr::null_mut()) - }; - if ret != 0 { - remaining -= amt as uint; - cur = unsafe { cur.offset(amt as int) }; - } else { - return Err(super::last_error()) - } - } - Ok(()) - } - - pub fn fd(&self) -> fd_t { self.inner.fd } - - pub fn handle(&self) -> libc::HANDLE { - unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE } - } - - // A version of seek that takes &self so that tell can call it - // - the private seek should of course take &mut self. - fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult { - let whence = match style { - rtio::SeekSet => libc::FILE_BEGIN, - rtio::SeekEnd => libc::FILE_END, - rtio::SeekCur => libc::FILE_CURRENT, - }; - unsafe { - let mut newpos = 0; - match libc::SetFilePointerEx(self.handle(), pos, &mut newpos, - whence) { - 0 => Err(super::last_error()), - _ => Ok(newpos as u64), - } - } - } - -} - -impl rtio::RtioFileStream for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf).map(|i| i as int) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - - fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult { - let mut read = 0; - let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() }; - overlap.Offset = offset as libc::DWORD; - overlap.OffsetHigh = (offset >> 32) as libc::DWORD; - let ret = unsafe { - libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID, - buf.len() as libc::DWORD, &mut read, - &mut overlap) - }; - if ret != 0 { - Ok(read as int) - } else { - Err(super::last_error()) - } - } - fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> IoResult<()> { - let mut cur = buf.as_ptr(); - let mut remaining = buf.len(); - let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() }; - while remaining > 0 { - overlap.Offset = offset as libc::DWORD; - overlap.OffsetHigh = (offset >> 32) as libc::DWORD; - let mut amt = 0; - let ret = unsafe { - libc::WriteFile(self.handle(), cur as libc::LPVOID, - remaining as libc::DWORD, &mut amt, - &mut overlap) - }; - if ret != 0 { - remaining -= amt as uint; - cur = unsafe { cur.offset(amt as int) }; - offset += amt as u64; - } else { - return Err(super::last_error()) - } - } - Ok(()) - } - - fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult { - self.seek_common(pos, style) - } - - fn tell(&self) -> IoResult { - self.seek_common(0, rtio::SeekCur) - } - - fn fsync(&mut self) -> IoResult<()> { - super::mkerr_winbool(unsafe { - libc::FlushFileBuffers(self.handle()) - }) - } - - fn datasync(&mut self) -> IoResult<()> { return self.fsync(); } - - fn truncate(&mut self, offset: i64) -> IoResult<()> { - let orig_pos = try!(self.tell()); - let _ = try!(self.seek(offset, rtio::SeekSet)); - let ret = unsafe { - match libc::SetEndOfFile(self.handle()) { - 0 => Err(super::last_error()), - _ => Ok(()) - } - }; - let _ = self.seek(orig_pos as i64, rtio::SeekSet); - return ret; - } - - fn fstat(&mut self) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - match unsafe { libc::fstat(self.fd(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } - } -} - -impl rtio::RtioPipe for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn clone(&self) -> Box { - box FileDesc { inner: self.inner.clone() } as Box - } - - // Only supported on named pipes currently. Note that this doesn't have an - // impact on the std::io primitives, this is never called via - // std::io::PipeStream. If the functionality is exposed in the future, then - // these methods will need to be implemented. - fn close_read(&mut self) -> IoResult<()> { - Err(super::unimpl()) - } - fn close_write(&mut self) -> IoResult<()> { - Err(super::unimpl()) - } - fn set_timeout(&mut self, _t: Option) {} - fn set_read_timeout(&mut self, _t: Option) {} - fn set_write_timeout(&mut self, _t: Option) {} -} - -impl rtio::RtioTTY for FileDesc { - fn read(&mut self, buf: &mut [u8]) -> IoResult { - self.inner_read(buf) - } - fn write(&mut self, buf: &[u8]) -> IoResult<()> { - self.inner_write(buf) - } - fn set_raw(&mut self, _raw: bool) -> IoResult<()> { - Err(super::unimpl()) - } - fn get_winsize(&mut self) -> IoResult<(int, int)> { - Err(super::unimpl()) - } - fn isatty(&self) -> bool { false } -} - -impl Drop for Inner { - fn drop(&mut self) { - // closing stdio file handles makes no sense, so never do it. Also, note - // that errors are ignored when closing a file descriptor. The reason - // for this is that if an error occurs we don't actually know if the - // file descriptor was closed or not, and if we retried (for something - // like EINTR), we might close another valid file descriptor (opened - // after we closed ours. - if self.close_on_drop && self.fd > libc::STDERR_FILENO { - let n = unsafe { libc::close(self.fd) }; - if n != 0 { - println!("error {} when closing file descriptor {}", n, self.fd); - } - } - } -} - -pub fn to_utf16(s: &CString) -> IoResult> { - match s.as_str() { - Some(s) => Ok({ - let mut s = s.utf16_units().collect::>(); - s.push(0); - s - }), - None => Err(IoError { - code: libc::ERROR_INVALID_NAME as uint, - extra: 0, - detail: Some("valid unicode input required".to_string()), - }) - } -} - -pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess) - -> IoResult { - // Flags passed to open_osfhandle - let flags = match fm { - rtio::Open => 0, - rtio::Append => libc::O_APPEND, - rtio::Truncate => libc::O_TRUNC, - }; - let flags = match fa { - rtio::Read => flags | libc::O_RDONLY, - rtio::Write => flags | libc::O_WRONLY | libc::O_CREAT, - rtio::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT, - }; - - let mut dwDesiredAccess = match fa { - rtio::Read => libc::FILE_GENERIC_READ, - rtio::Write => libc::FILE_GENERIC_WRITE, - rtio::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE - }; - - // libuv has a good comment about this, but the basic idea is what we try to - // emulate unix semantics by enabling all sharing by allowing things such as - // deleting a file while it's still open. - let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE | - libc::FILE_SHARE_DELETE; - - let dwCreationDisposition = match (fm, fa) { - (rtio::Truncate, rtio::Read) => libc::TRUNCATE_EXISTING, - (rtio::Truncate, _) => libc::CREATE_ALWAYS, - (rtio::Open, rtio::Read) => libc::OPEN_EXISTING, - (rtio::Open, _) => libc::OPEN_ALWAYS, - (rtio::Append, rtio::Read) => { - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_EXISTING - } - (rtio::Append, _) => { - dwDesiredAccess &= !libc::FILE_WRITE_DATA; - dwDesiredAccess |= libc::FILE_APPEND_DATA; - libc::OPEN_ALWAYS - } - }; - - let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL; - // Compat with unix, this allows opening directories (see libuv) - dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS; - - let path = try!(to_utf16(path)); - let handle = unsafe { - libc::CreateFileW(path.as_ptr(), - dwDesiredAccess, - dwShareMode, - ptr::null_mut(), - dwCreationDisposition, - dwFlagsAndAttributes, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - Err(super::last_error()) - } else { - let fd = unsafe { - libc::open_osfhandle(handle as libc::intptr_t, flags) - }; - if fd < 0 { - let _ = unsafe { libc::CloseHandle(handle) }; - Err(super::last_error()) - } else { - Ok(FileDesc::new(fd, true)) - } - } -} - -pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_winbool(unsafe { - // FIXME: turn mode into something useful? #2623 - libc::CreateDirectoryW(p.as_ptr(), ptr::null_mut()) - }) -} - -pub fn readdir(p: &CString) -> IoResult> { - fn prune(root: &CString, dirs: Vec) -> Vec { - let root = unsafe { CString::new(root.as_ptr(), false) }; - let root = Path::new(root); - - dirs.into_iter().filter(|path| { - path.as_vec() != b"." && path.as_vec() != b".." - }).map(|path| root.join(path).to_c_str()).collect() - } - - let star = Path::new(unsafe { - CString::new(p.as_ptr(), false) - }).join("*"); - let path = try!(to_utf16(&star.to_c_str())); - - unsafe { - let mut wfd = mem::zeroed(); - let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd); - if find_handle != libc::INVALID_HANDLE_VALUE { - let mut paths = vec![]; - let mut more_files = 1 as libc::BOOL; - while more_files != 0 { - { - let filename = str::truncate_utf16_at_nul(wfd.cFileName); - match String::from_utf16(filename) { - Some(filename) => paths.push(Path::new(filename)), - None => { - assert!(libc::FindClose(find_handle) != 0); - return Err(IoError { - code: super::c::ERROR_ILLEGAL_CHARACTER as uint, - extra: 0, - detail: Some(format!("path was not valid UTF-16: {}", filename)), - }) - }, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring - } - } - more_files = libc::FindNextFileW(find_handle, &mut wfd); - } - assert!(libc::FindClose(find_handle) != 0); - Ok(prune(p, paths)) - } else { - Err(super::last_error()) - } - } -} - -pub fn unlink(p: &CString) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_winbool(unsafe { - libc::DeleteFileW(p.as_ptr()) - }) -} - -pub fn rename(old: &CString, new: &CString) -> IoResult<()> { - let old = try!(to_utf16(old)); - let new = try!(to_utf16(new)); - super::mkerr_winbool(unsafe { - libc::MoveFileExW(old.as_ptr(), new.as_ptr(), - libc::MOVEFILE_REPLACE_EXISTING) - }) -} - -pub fn chmod(p: &CString, mode: uint) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_libc(unsafe { - libc::wchmod(p.as_ptr(), mode as libc::c_int) - }) -} - -pub fn rmdir(p: &CString) -> IoResult<()> { - let p = try!(to_utf16(p)); - super::mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) }) -} - -pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> { - // libuv has this as a no-op, so seems like this should as well? - Ok(()) -} - -pub fn readlink(p: &CString) -> IoResult { - // FIXME: I have a feeling that this reads intermediate symlinks as well. - use io::c::compat::kernel32::GetFinalPathNameByHandleW; - let p = try!(to_utf16(p)); - let handle = unsafe { - libc::CreateFileW(p.as_ptr(), - libc::GENERIC_READ, - libc::FILE_SHARE_READ, - ptr::null_mut(), - libc::OPEN_EXISTING, - libc::FILE_ATTRIBUTE_NORMAL, - ptr::null_mut()) - }; - if handle == libc::INVALID_HANDLE_VALUE { - return Err(super::last_error()) - } - // Specify (sz - 1) because the documentation states that it's the size - // without the null pointer - let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe { - GetFinalPathNameByHandleW(handle, - buf as *const u16, - sz - 1, - libc::VOLUME_NAME_DOS) - }); - let ret = match ret { - Some(ref s) if s.as_slice().starts_with(r"\\?\") => { - Ok(Path::new(s.as_slice().slice_from(4)).to_c_str()) - } - Some(s) => Ok(Path::new(s).to_c_str()), - None => Err(super::last_error()), - }; - assert!(unsafe { libc::CloseHandle(handle) } != 0); - return ret; -} - -pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> { - use io::c::compat::kernel32::CreateSymbolicLinkW; - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL - }) -} - -pub fn link(src: &CString, dst: &CString) -> IoResult<()> { - let src = try!(to_utf16(src)); - let dst = try!(to_utf16(dst)); - super::mkerr_winbool(unsafe { - libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::null_mut()) - }) -} - -fn mkstat(stat: &libc::stat) -> rtio::FileStat { - rtio::FileStat { - size: stat.st_size as u64, - kind: stat.st_mode as u64, - perm: stat.st_mode as u64, - created: stat.st_ctime as u64, - modified: stat.st_mtime as u64, - accessed: stat.st_atime as u64, - device: stat.st_dev as u64, - inode: stat.st_ino as u64, - rdev: stat.st_rdev as u64, - nlink: stat.st_nlink as u64, - uid: stat.st_uid as u64, - gid: stat.st_gid as u64, - blksize: 0, - blocks: 0, - flags: 0, - gen: 0, - } -} - -pub fn stat(p: &CString) -> IoResult { - let mut stat: libc::stat = unsafe { mem::zeroed() }; - let p = try!(to_utf16(p)); - match unsafe { libc::wstat(p.as_ptr(), &mut stat) } { - 0 => Ok(mkstat(&stat)), - _ => Err(super::last_error()), - } -} - -pub fn lstat(_p: &CString) -> IoResult { - // FIXME: implementation is missing - Err(super::unimpl()) -} - -pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> { - let mut buf = libc::utimbuf { - actime: atime as libc::time64_t, - modtime: mtime as libc::time64_t, - }; - let p = try!(to_utf16(p)); - super::mkerr_libc(unsafe { - libc::wutime(p.as_ptr(), &mut buf) - }) -} diff --git a/src/libnative/io/mod.rs b/src/libnative/io/mod.rs index a541712e17f..baf58b83dcd 100644 --- a/src/libnative/io/mod.rs +++ b/src/libnative/io/mod.rs @@ -30,7 +30,6 @@ use std::rt::rtio::{mod, IoResult, IoError}; use std::num; // Local re-exports -pub use self::file::FileDesc; pub use self::process::Process; mod helper_thread; @@ -41,13 +40,6 @@ pub mod net; pub mod process; mod util; -#[cfg(unix)] -#[path = "file_unix.rs"] -pub mod file; -#[cfg(windows)] -#[path = "file_windows.rs"] -pub mod file; - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "freebsd", @@ -92,25 +84,6 @@ fn last_error() -> IoError { } } -// unix has nonzero values as errors -fn mkerr_libc (ret: Int) -> IoResult<()> { - if !ret.is_zero() { - Err(last_error()) - } else { - Ok(()) - } -} - -// windows has zero values as errors -#[cfg(windows)] -fn mkerr_winbool(ret: libc::c_int) -> IoResult<()> { - if ret == 0 { - Err(last_error()) - } else { - Ok(()) - } -} - #[cfg(windows)] #[inline] fn retry (f: || -> I) -> I { f() } // PR rust-lang/rust/#17020 @@ -199,62 +172,6 @@ impl rtio::IoFactory for IoFactory { addrinfo::GetAddrInfoRequest::run(host, servname, hint) } - // filesystem operations - fn fs_from_raw_fd(&mut self, fd: c_int, close: rtio::CloseBehavior) - -> Box { - let close = match close { - rtio::CloseSynchronously | rtio::CloseAsynchronously => true, - rtio::DontClose => false - }; - box file::FileDesc::new(fd, close) as Box - } - fn fs_open(&mut self, path: &CString, fm: rtio::FileMode, - fa: rtio::FileAccess) - -> IoResult> - { - file::open(path, fm, fa).map(|fd| box fd as Box) - } - fn fs_unlink(&mut self, path: &CString) -> IoResult<()> { - file::unlink(path) - } - fn fs_stat(&mut self, path: &CString) -> IoResult { - file::stat(path) - } - fn fs_mkdir(&mut self, path: &CString, mode: uint) -> IoResult<()> { - file::mkdir(path, mode) - } - fn fs_chmod(&mut self, path: &CString, mode: uint) -> IoResult<()> { - file::chmod(path, mode) - } - fn fs_rmdir(&mut self, path: &CString) -> IoResult<()> { - file::rmdir(path) - } - fn fs_rename(&mut self, path: &CString, to: &CString) -> IoResult<()> { - file::rename(path, to) - } - fn fs_readdir(&mut self, path: &CString, _flags: c_int) -> IoResult> { - file::readdir(path) - } - fn fs_lstat(&mut self, path: &CString) -> IoResult { - file::lstat(path) - } - fn fs_chown(&mut self, path: &CString, uid: int, gid: int) -> IoResult<()> { - file::chown(path, uid, gid) - } - fn fs_readlink(&mut self, path: &CString) -> IoResult { - file::readlink(path) - } - fn fs_symlink(&mut self, src: &CString, dst: &CString) -> IoResult<()> { - file::symlink(src, dst) - } - fn fs_link(&mut self, src: &CString, dst: &CString) -> IoResult<()> { - file::link(src, dst) - } - fn fs_utime(&mut self, src: &CString, atime: u64, - mtime: u64) -> IoResult<()> { - file::utime(src, atime, mtime) - } - // misc fn timer_init(&mut self) -> IoResult> { timer::Timer::new().map(|t| box t as Box) diff --git a/src/libnative/io/timer_unix.rs b/src/libnative/io/timer_unix.rs index 38895f2a8f9..c26e2e76cee 100644 --- a/src/libnative/io/timer_unix.rs +++ b/src/libnative/io/timer_unix.rs @@ -56,7 +56,7 @@ use std::sync::atomic; use std::comm; use io::c; -use io::file::FileDesc; +use platform_imp::fs::FileDesc; use io::helper_thread::Helper; helper_init!(static HELPER: Helper) -- cgit 1.4.1-3-g733a5