diff --git a/src/libnative/io/file_unix.rs b/src/libnative/io/file_unix.rs index 87225a10e76d5..c2b69483fa1e0 100644 --- a/src/libnative/io/file_unix.rs +++ b/src/libnative/io/file_unix.rs @@ -166,6 +166,14 @@ impl rtio::RtioFileStream for FileDesc { libc::ftruncate(self.fd(), offset as libc::off_t) })) } + + fn fstat(&mut self) -> IoResult { + let mut stat: libc::stat = unsafe { mem::uninit() }; + match retry(|| unsafe { libc::fstat(self.fd(), &mut stat) }) { + 0 => Ok(mkstat(&stat)), + _ => Err(super::last_error()), + } + } } impl rtio::RtioPipe for FileDesc { @@ -317,6 +325,10 @@ impl rtio::RtioFileStream for CFile { fn truncate(&mut self, offset: i64) -> Result<(), IoError> { self.flush().and_then(|()| self.fd.truncate(offset)) } + + fn fstat(&mut self) -> IoResult { + self.flush().and_then(|()| self.fd.fstat()) + } } impl Drop for CFile { @@ -455,9 +467,7 @@ pub fn link(src: &CString, dst: &CString) -> IoResult<()> { })) } -fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat { - let path = unsafe { CString::new(path.with_ref(|p| p), false) }; - +fn mkstat(stat: &libc::stat) -> io::FileStat { // FileStat times are in milliseconds fn mktime(secs: u64, nsecs: u64) -> u64 { secs * 1000 + nsecs / 1000000 } @@ -481,7 +491,6 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat { fn gen(_stat: &libc::stat) -> u64 { 0 } io::FileStat { - path: Path::new(path), size: stat.st_size as u64, kind: kind, perm: unsafe { @@ -508,7 +517,7 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat { pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::uninit() }; match retry(|| unsafe { libc::stat(p.with_ref(|p| p), &mut stat) }) { - 0 => Ok(mkstat(&stat, p)), + 0 => Ok(mkstat(&stat)), _ => Err(super::last_error()), } } @@ -516,7 +525,7 @@ pub fn stat(p: &CString) -> IoResult { pub fn lstat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::uninit() }; match retry(|| unsafe { libc::lstat(p.with_ref(|p| p), &mut stat) }) { - 0 => Ok(mkstat(&stat, p)), + 0 => Ok(mkstat(&stat)), _ => Err(super::last_error()), } } diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs index 707b0c0cf3fd5..d721e1d67f1b9 100644 --- a/src/libnative/io/file_win32.rs +++ b/src/libnative/io/file_win32.rs @@ -197,6 +197,14 @@ impl rtio::RtioFileStream for FileDesc { let _ = self.seek(orig_pos as i64, io::SeekSet); return ret; } + + fn fstat(&mut self) -> IoResult { + let mut stat: libc::stat = unsafe { mem::uninit() }; + match unsafe { libc::fstat(self.fd(), &mut stat) } { + 0 => Ok(mkstat(&stat)), + _ => Err(super::last_error()), + } + } } impl rtio::RtioPipe for FileDesc { @@ -471,8 +479,7 @@ pub fn link(src: &CString, dst: &CString) -> IoResult<()> { })) } -fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat { - let path = unsafe { CString::new(path.with_ref(|p| p), false) }; +fn mkstat(stat: &libc::stat) -> io::FileStat { let kind = match (stat.st_mode as c_int) & libc::S_IFMT { libc::S_IFREG => io::TypeFile, libc::S_IFDIR => io::TypeDirectory, @@ -483,7 +490,6 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat { }; io::FileStat { - path: Path::new(path), size: stat.st_size as u64, kind: kind, perm: unsafe { @@ -511,7 +517,7 @@ pub fn stat(p: &CString) -> IoResult { let mut stat: libc::stat = unsafe { mem::uninit() }; as_utf16_p(p.as_str().unwrap(), |up| { match unsafe { libc::wstat(up, &mut stat) } { - 0 => Ok(mkstat(&stat, p)), + 0 => Ok(mkstat(&stat)), _ => Err(super::last_error()), } }) diff --git a/src/librustuv/file.rs b/src/librustuv/file.rs index cd56e76aff667..06271e61ce7a0 100644 --- a/src/librustuv/file.rs +++ b/src/librustuv/file.rs @@ -70,6 +70,12 @@ impl FsRequest { }).map(|req| req.mkstat()) } + pub fn fstat(loop_: &Loop, fd: c_int) -> Result { + execute(|req, cb| unsafe { + uvll::uv_fs_fstat(loop_.handle, req, fd, cb) + }).map(|req| req.mkstat()) + } + pub fn write(loop_: &Loop, fd: c_int, buf: &[u8], offset: i64) -> Result<(), UvError> { @@ -262,8 +268,6 @@ impl FsRequest { } pub fn mkstat(&self) -> FileStat { - let path = unsafe { uvll::get_path_from_fs_req(self.req) }; - let path = unsafe { Path::new(CString::new(path, false)) }; let stat = self.get_stat(); fn to_msec(stat: uvll::uv_timespec_t) -> u64 { // Be sure to cast to u64 first to prevent overflowing if the tv_sec @@ -279,7 +283,6 @@ impl FsRequest { _ => io::TypeUnknown, }; FileStat { - path: path, size: stat.st_size as u64, kind: kind, perm: unsafe { @@ -463,6 +466,11 @@ impl rtio::RtioFileStream for FileWatcher { let r = FsRequest::truncate(&self.loop_, self.fd, offset); r.map_err(uv_error_to_io_error) } + + fn fstat(&mut self) -> Result { + let _m = self.fire_homing_missile(); + FsRequest::fstat(&self.loop_, self.fd).map_err(uv_error_to_io_error) + } } #[cfg(test)] @@ -537,6 +545,10 @@ mod test { assert!(result.is_ok()); assert_eq!(result.unwrap().size, 5); + let result = FsRequest::fstat(l(), file.fd); + assert!(result.is_ok()); + assert_eq!(result.unwrap().size, 5); + fn free(_: T) {} free(file); diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs index 125b4ddad88f4..a497ffd40a070 100644 --- a/src/libstd/io/fs.rs +++ b/src/libstd/io/fs.rs @@ -214,6 +214,11 @@ impl File { pub fn eof(&self) -> bool { self.last_nread == 0 } + + /// Queries information about the underlying file. + pub fn stat(&mut self) -> IoResult { + self.fd.fstat() + } } /// Unlink a file from the underlying filesystem. @@ -887,9 +892,12 @@ mod test { let tmpdir = tmpdir(); let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); { - let mut fs = File::open_mode(filename, Open, ReadWrite); + let mut fs = check!(File::open_mode(filename, Open, ReadWrite)); let msg = "hw"; fs.write(msg.as_bytes()).unwrap(); + + let fstat_res = check!(fs.stat()); + assert_eq!(fstat_res.kind, io::TypeFile); } let stat_res_fn = check!(stat(filename)); assert_eq!(stat_res_fn.kind, io::TypeFile); @@ -1228,12 +1236,12 @@ mod test { check!(file.fsync()); // Do some simple things with truncation - assert_eq!(check!(stat(&path)).size, 3); + assert_eq!(check!(file.stat()).size, 3); check!(file.truncate(10)); - assert_eq!(check!(stat(&path)).size, 10); + assert_eq!(check!(file.stat()).size, 10); check!(file.write(bytes!("bar"))); check!(file.fsync()); - assert_eq!(check!(stat(&path)).size, 10); + assert_eq!(check!(file.stat()).size, 10); assert_eq!(check!(File::open(&path).read_to_end()), (Vec::from_slice(bytes!("foobar", 0, 0, 0, 0)))); @@ -1241,10 +1249,10 @@ mod test { // Ensure that the intermediate zeroes are all filled in (we're seeked // past the end of the file). check!(file.truncate(2)); - assert_eq!(check!(stat(&path)).size, 2); + assert_eq!(check!(file.stat()).size, 2); check!(file.write(bytes!("wut"))); check!(file.fsync()); - assert_eq!(check!(stat(&path)).size, 9); + assert_eq!(check!(file.stat()).size, 9); assert_eq!(check!(File::open(&path).read_to_end()), (Vec::from_slice(bytes!("fo", 0, 0, 0, 0, "wut")))); drop(file); diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 37edab9991598..363525425902d 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -228,7 +228,6 @@ use ops::{BitOr, BitAnd, Sub}; use option::{Option, Some, None}; use os; use owned::Box; -use path::Path; use result::{Ok, Err, Result}; use slice::{Vector, MutableVector, ImmutableVector}; use str::{StrSlice, StrAllocating}; @@ -1516,8 +1515,6 @@ pub enum FileType { /// ``` #[deriving(Hash)] pub struct FileStat { - /// The path that this stat structure is describing - pub path: Path, /// The size of the file, in bytes pub size: u64, /// The kind of file this path points to (directory, file, pipe, etc.) diff --git a/src/libstd/rt/rtio.rs b/src/libstd/rt/rtio.rs index bc3a483f30d2b..d23d327d55881 100644 --- a/src/libstd/rt/rtio.rs +++ b/src/libstd/rt/rtio.rs @@ -269,6 +269,7 @@ pub trait RtioFileStream { fn fsync(&mut self) -> IoResult<()>; fn datasync(&mut self) -> IoResult<()>; fn truncate(&mut self, offset: i64) -> IoResult<()>; + fn fstat(&mut self) -> IoResult; } pub trait RtioProcess {