about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2014-12-05 00:22:58 +0000
committerbors <bors@rust-lang.org>2014-12-05 00:22:58 +0000
commit361baabb07b2fb921d0f556d0787b3ea7ef86746 (patch)
treebc61837ee47ed0611090b199b69e43a89e5c5c7b /src/libstd
parentd9c7c00b9a3d80fc81fbbb77a9f21e5f71a1d213 (diff)
parent3980cdecd073789fb5ff7256e2ca40685a289b01 (diff)
downloadrust-361baabb07b2fb921d0f556d0787b3ea7ef86746.tar.gz
rust-361baabb07b2fb921d0f556d0787b3ea7ef86746.zip
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()`.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/fs.rs32
-rw-r--r--src/libstd/sys/windows/fs.rs2
2 files changed, 24 insertions, 10 deletions
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs
index fd6b57d096a..e52c00f8247 100644
--- a/src/libstd/io/fs.rs
+++ b/src/libstd/io/fs.rs
@@ -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");
         }
diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs
index 9c4ffb926b5..9402c63dcf5 100644
--- a/src/libstd/sys/windows/fs.rs
+++ b/src/libstd/sys/windows/fs.rs
@@ -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)),