From d3ec0674bbf031008a5b741d04edc9ebdc466264 Mon Sep 17 00:00:00 2001 From: Peter Atashian Date: Sat, 6 Sep 2014 12:51:42 -0400 Subject: [PATCH] readdir: return error instead of failing on invalid UTF-16 Fixes #15279 Signed-off-by: Peter Atashian --- src/liblibc/lib.rs | 24 ++++++++++++++--- src/libnative/io/file_windows.rs | 45 ++++++++++++++------------------ src/rt/rust_builtin.c | 27 ------------------- 3 files changed, 39 insertions(+), 57 deletions(-) diff --git a/src/liblibc/lib.rs b/src/liblibc/lib.rs index bbccdf0acf9..35b05a672b2 100644 --- a/src/liblibc/lib.rs +++ b/src/liblibc/lib.rs @@ -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, diff --git a/src/libnative/io/file_windows.rs b/src/libnative/io/file_windows.rs index cb1d79b8397..adc97c6bede 100644 --- a/src/libnative/io/file_windows.rs +++ b/src/libnative/io/file_windows.rs @@ -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> { - use std::rt::libc_heap::malloc_raw; - fn prune(root: &CString, dirs: Vec) -> Vec { let root = unsafe { CString::new(root.as_ptr(), false) }; let root = Path::new(root); @@ -355,38 +351,35 @@ fn prune(root: &CString, dirs: Vec) -> Vec { }).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()) diff --git a/src/rt/rust_builtin.c b/src/rt/rust_builtin.c index ba20f2c6f27..5dc07f859ae 100644 --- a/src/rt/rust_builtin.c +++ b/src/rt/rust_builtin.c @@ -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;