Skip to content

Add stat method to std::io::fs::File to stat without a Path. #14128

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions src/libnative/io/file_unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,14 @@ impl rtio::RtioFileStream for FileDesc {
libc::ftruncate(self.fd(), offset as libc::off_t)
}))
}

fn fstat(&mut self) -> IoResult<io::FileStat> {
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 {
Expand Down Expand Up @@ -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<io::FileStat> {
self.flush().and_then(|()| self.fd.fstat())
}
}

impl Drop for CFile {
Expand Down Expand Up @@ -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 }

Expand All @@ -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 {
Expand All @@ -508,15 +517,15 @@ fn mkstat(stat: &libc::stat, path: &CString) -> io::FileStat {
pub fn stat(p: &CString) -> IoResult<io::FileStat> {
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()),
}
}

pub fn lstat(p: &CString) -> IoResult<io::FileStat> {
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()),
}
}
Expand Down
14 changes: 10 additions & 4 deletions src/libnative/io/file_win32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<io::FileStat> {
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 {
Expand Down Expand Up @@ -469,8 +477,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,
Expand All @@ -481,7 +488,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 {
Expand Down Expand Up @@ -509,7 +515,7 @@ pub fn stat(p: &CString) -> IoResult<io::FileStat> {
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()),
}
})
Expand Down
18 changes: 15 additions & 3 deletions src/librustuv/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,12 @@ impl FsRequest {
}).map(|req| req.mkstat())
}

pub fn fstat(loop_: &Loop, fd: c_int) -> Result<FileStat, UvError> {
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>
{
Expand Down Expand Up @@ -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
Expand All @@ -279,7 +283,6 @@ impl FsRequest {
_ => io::TypeUnknown,
};
FileStat {
path: path,
size: stat.st_size as u64,
kind: kind,
perm: unsafe {
Expand Down Expand Up @@ -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<FileStat, IoError> {
let _m = self.fire_homing_missile();
FsRequest::fstat(&self.loop_, self.fd).map_err(uv_error_to_io_error)
}
}

#[cfg(test)]
Expand Down Expand Up @@ -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>(_: T) {}
free(file);

Expand Down
20 changes: 14 additions & 6 deletions src/libstd/io/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileStat> {
self.fd.fstat()
}
}

/// Unlink a file from the underlying filesystem.
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1228,23 +1236,23 @@ 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))));

// Truncate to a smaller length, don't seek, and then write something.
// 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);
Expand Down
3 changes: 0 additions & 3 deletions src/libstd/io/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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.)
Expand Down
1 change: 1 addition & 0 deletions src/libstd/rt/rtio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<FileStat>;
}

pub trait RtioProcess {
Expand Down