|
53 | 53 | use clone::Clone;
|
54 | 54 | use io::standard_error;
|
55 | 55 | use io::{FilePermission, Write, Open, FileAccess, FileMode, FileType};
|
56 |
| -use io::{IoResult, IoError, FileStat, SeekStyle, Seek, Writer, Reader}; |
| 56 | +use io::{IoResult, IoError, InvalidInput}; |
| 57 | +use io::{FileStat, SeekStyle, Seek, Writer, Reader}; |
57 | 58 | use io::{Read, Truncate, ReadWrite, Append};
|
58 | 59 | use io::UpdateIoError;
|
59 | 60 | use io;
|
@@ -134,13 +135,26 @@ impl File {
|
134 | 135 | pub fn open_mode(path: &Path,
|
135 | 136 | mode: FileMode,
|
136 | 137 | access: FileAccess) -> IoResult<File> {
|
137 |
| - fs_imp::open(path, mode, access).map(|fd| { |
138 |
| - File { |
139 |
| - path: path.clone(), |
140 |
| - fd: fd, |
141 |
| - last_nread: -1 |
| 138 | + fs_imp::open(path, mode, access).and_then(|fd| { |
| 139 | + // On *BSD systems, we can open a directory as a file and read from it: |
| 140 | + // fd=open("/tmp", O_RDONLY); read(fd, buf, N); |
| 141 | + // due to an old tradition before the introduction of opendir(3). |
| 142 | + // We explicitly reject it because there are few use cases. |
| 143 | + if cfg!(not(any(windows, target_os = "linux", target_os = "android"))) && |
| 144 | + try!(fd.fstat()).kind == FileType::Directory { |
| 145 | + Err(IoError { |
| 146 | + kind: InvalidInput, |
| 147 | + desc: "is a directory", |
| 148 | + detail: None |
| 149 | + }) |
| 150 | + } else { |
| 151 | + Ok(File { |
| 152 | + path: path.clone(), |
| 153 | + fd: fd, |
| 154 | + last_nread: -1 |
| 155 | + }) |
142 | 156 | }
|
143 |
| - }).update_err("couldn't open file", |e| { |
| 157 | + }).update_err("couldn't open path as file", |e| { |
144 | 158 | format!("{}; path={}; mode={}; access={}", e, path.display(),
|
145 | 159 | mode_string(mode), access_string(access))
|
146 | 160 | })
|
|
0 commit comments