readdir: return error instead of failing on invalid UTF-16

Fixes #15279

Signed-off-by: Peter Atashian <retep998@gmail.com>
This commit is contained in:
Peter Atashian 2014-09-06 12:51:42 -04:00
parent 82c052794d
commit d3ec0674bb
3 changed files with 39 additions and 57 deletions

View File

@ -249,7 +249,7 @@
#[cfg(windows)] pub use types::os::arch::extra::{LARGE_INTEGER, LPVOID, LONG};
#[cfg(windows)] pub use types::os::arch::extra::{time64_t, OVERLAPPED, LPCWSTR};
#[cfg(windows)] pub use types::os::arch::extra::{LPOVERLAPPED, SIZE_T, LPDWORD};
#[cfg(windows)] pub use types::os::arch::extra::{SECURITY_ATTRIBUTES};
#[cfg(windows)] pub use types::os::arch::extra::{SECURITY_ATTRIBUTES, WIN32_FIND_DATAW};
#[cfg(windows)] pub use funcs::c95::string::{wcslen};
#[cfg(windows)] pub use funcs::posix88::stat_::{wstat, wutime, wchmod, wrmdir};
#[cfg(windows)] pub use funcs::bsd43::{closesocket};
@ -1638,6 +1638,22 @@ pub struct WSAPROTOCOL_INFO {
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
pub type GROUP = c_uint;
#[repr(C)]
pub struct WIN32_FIND_DATAW {
pub dwFileAttributes: DWORD,
pub ftCreationTime: FILETIME,
pub ftLastAccessTime: FILETIME,
pub ftLastWriteTime: FILETIME,
pub nFileSizeHigh: DWORD,
pub nFileSizeLow: DWORD,
pub dwReserved0: DWORD,
pub dwReserved1: DWORD,
pub cFileName: [wchar_t, ..260], // #define MAX_PATH 260
pub cAlternateFileName: [wchar_t, ..14],
}
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
}
}
}
@ -4763,7 +4779,7 @@ pub mod kernel32 {
LPMEMORY_BASIC_INFORMATION,
LPSYSTEM_INFO, HANDLE, LPHANDLE,
LARGE_INTEGER, PLARGE_INTEGER,
LPFILETIME};
LPFILETIME, LPWIN32_FIND_DATAW};
extern "system" {
pub fn GetEnvironmentVariableW(n: LPCWSTR,
@ -4793,9 +4809,9 @@ pub fn GetCurrentDirectoryW(nBufferLength: DWORD,
-> DWORD;
pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
pub fn GetLastError() -> DWORD;
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: HANDLE)
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW)
-> HANDLE;
pub fn FindNextFileW(findFile: HANDLE, findFileData: HANDLE)
pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
-> BOOL;
pub fn FindClose(findFile: HANDLE) -> BOOL;
pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,

View File

@ -11,8 +11,7 @@
//! Blocking Windows-based file I/O
use alloc::arc::Arc;
use libc::{c_int, c_void};
use libc;
use libc::{mod, c_int};
use std::c_str::CString;
use std::mem;
use std::os::windows::fill_utf16_buf_and_decode;
@ -20,7 +19,6 @@
use std::rt::rtio;
use std::rt::rtio::{IoResult, IoError};
use std::str;
use std::vec;
pub type fd_t = libc::c_int;
@ -344,8 +342,6 @@ pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> {
}
pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
use std::rt::libc_heap::malloc_raw;
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
let root = unsafe { CString::new(root.as_ptr(), false) };
let root = Path::new(root);
@ -355,38 +351,35 @@ fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
}).map(|path| root.join(path).to_c_str()).collect()
}
extern {
fn rust_list_dir_wfd_size() -> libc::size_t;
fn rust_list_dir_wfd_fp_buf(wfd: *mut libc::c_void) -> *const u16;
}
let star = Path::new(unsafe {
CString::new(p.as_ptr(), false)
}).join("*");
let path = try!(to_utf16(&star.to_c_str()));
unsafe {
let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
let find_handle = libc::FindFirstFileW(path.as_ptr(),
wfd_ptr as libc::HANDLE);
let mut wfd = mem::zeroed();
let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
if find_handle != libc::INVALID_HANDLE_VALUE {
let mut paths = vec!();
let mut more_files = 1 as libc::c_int;
let mut paths = vec![];
let mut more_files = 1 as libc::BOOL;
while more_files != 0 {
let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr as *mut c_void);
if fp_buf as uint == 0 {
fail!("os::list_dir() failure: got null ptr from wfd");
} else {
let fp_vec = vec::raw::from_buf(fp_buf, libc::wcslen(fp_buf) as uint);
let fp_trimmed = str::truncate_utf16_at_nul(fp_vec.as_slice());
let fp_str = String::from_utf16(fp_trimmed)
.expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
paths.push(Path::new(fp_str));
{
let filename = str::truncate_utf16_at_nul(wfd.cFileName);
match String::from_utf16(filename) {
Some(filename) => paths.push(Path::new(filename)),
None => {
assert!(libc::FindClose(find_handle) != 0);
return Err(IoError {
code: super::c::ERROR_ILLEGAL_CHARACTER as uint,
extra: 0,
detail: Some(format!("path was not valid UTF-16: {}", filename)),
})
}, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring
}
}
more_files = libc::FindNextFileW(find_handle,
wfd_ptr as libc::HANDLE);
more_files = libc::FindNextFileW(find_handle, &mut wfd);
}
assert!(libc::FindClose(find_handle) != 0);
libc::free(wfd_ptr as *mut c_void);
Ok(prune(p, paths))
} else {
Err(super::last_error())

View File

@ -100,33 +100,6 @@ rust_list_dir_val(struct dirent* entry_ptr) {
}
#endif
size_t
#if defined(__WIN32__)
rust_list_dir_wfd_size() {
return sizeof(WIN32_FIND_DATAW);
}
#else
rust_list_dir_wfd_size() {
return 0;
}
#endif
void*
#if defined(__WIN32__)
rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
if(wfd == NULL) {
return 0;
}
else {
return wfd->cFileName;
}
}
#else
rust_list_dir_wfd_fp_buf(void* wfd) {
return 0;
}
#endif
typedef struct {
int32_t tm_sec;
int32_t tm_min;