auto merge of #19303 : nodakai/rust/libsyntax-reject-dirs, r=alexcrichton

On *BSD systems, we can `open(2)` a directory and directly `read(2)` from it due to an old tradition.  We should avoid doing so by explicitly calling `fstat(2)` to check the type of the opened file.

Opening a directory as a module file can't always be avoided.  Even when there's no "path" attribute trick involved, there can always be a *directory* named `my_module.rs`.

Incidentally, remove unnecessary mutability of `&self` from `io::fs::File::stat()`.
This commit is contained in:
bors 2014-12-05 00:22:58 +00:00
commit 361baabb07
3 changed files with 25 additions and 13 deletions

View File

@ -53,7 +53,8 @@
use clone::Clone;
use io::standard_error;
use io::{FilePermission, Write, Open, FileAccess, FileMode, FileType};
use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader};
use io::{IoResult, IoError, InvalidInput};
use io::{FileStat, SeekStyle, Seek, Writer, Reader};
use io::{Read, Truncate, ReadWrite, Append};
use io::UpdateIoError;
use io;
@ -134,13 +135,26 @@ impl File {
pub fn open_mode(path: &Path,
mode: FileMode,
access: FileAccess) -> IoResult<File> {
fs_imp::open(path, mode, access).map(|fd| {
File {
path: path.clone(),
fd: fd,
last_nread: -1
fs_imp::open(path, mode, access).and_then(|fd| {
// On *BSD systems, we can open a directory as a file and read from it:
// fd=open("/tmp", O_RDONLY); read(fd, buf, N);
// due to an old tradition before the introduction of opendir(3).
// We explicitly reject it because there are few use cases.
if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) &&
try!(fd.fstat()).kind == FileType::Directory {
Err(IoError {
kind: InvalidInput,
desc: "is a directory",
detail: None
})
} else {
Ok(File {
path: path.clone(),
fd: fd,
last_nread: -1
})
}
}).update_err("couldn't open file", |e| {
}).update_err("couldn't open path as file", |e| {
format!("{}; path={}; mode={}; access={}", e, path.display(),
mode_string(mode), access_string(access))
})
@ -237,7 +251,7 @@ impl File {
}
/// Queries information about the underlying file.
pub fn stat(&mut self) -> IoResult<FileStat> {
pub fn stat(&self) -> IoResult<FileStat> {
self.fd.fstat()
.update_err("couldn't fstat file", |e|
format!("{}; path={}", e, self.path.display()))
@ -886,7 +900,7 @@ mod test {
let filename = &tmpdir.join("file_that_does_not_exist.txt");
let result = File::open_mode(filename, Open, Read);
error!(result, "couldn't open file");
error!(result, "couldn't open path as file");
if cfg!(unix) {
error!(result, "no such file or directory");
}

View File

@ -131,7 +131,7 @@ impl FileDesc {
return ret;
}
pub fn fstat(&mut self) -> IoResult<io::FileStat> {
pub fn fstat(&self) -> IoResult<io::FileStat> {
let mut stat: libc::stat = unsafe { mem::zeroed() };
match unsafe { libc::fstat(self.fd(), &mut stat) } {
0 => Ok(mkstat(&stat)),

View File

@ -18,9 +18,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// ignore-freebsd FIXME #12460
#[path = "../compile-fail"]
mod foo; //~ ERROR: illegal operation on a directory
mod foo; //~ ERROR: a directory
fn main() {}