about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorNODA, Kai <nodakai@gmail.com>2014-12-03 06:06:59 +0800
committerNODA, Kai <nodakai@gmail.com>2014-12-04 11:19:55 +0800
commit3980cdecd073789fb5ff7256e2ca40685a289b01 (patch)
tree007c1af0e17e6c4bd21b18034d87d9e24a9c58af /src/libstd
parent805a06ca6a4f0999e13508e6271e3589f2c4c1b2 (diff)
downloadrust-3980cdecd073789fb5ff7256e2ca40685a289b01.tar.gz
rust-3980cdecd073789fb5ff7256e2ca40685a289b01.zip
libstd: explicitly disallow io::fs::File to open a directory.
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".

Fix #12460

Signed-off-by: NODA, Kai <nodakai@gmail.com>
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/io/fs.rs30
1 files changed, 22 insertions, 8 deletions
diff --git a/src/libstd/io/fs.rs b/src/libstd/io/fs.rs
index d5f23694fc8..c66540e639e 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))
         })
@@ -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");
         }