Skip to content

Commit d3ec067

Browse files
committed
readdir: return error instead of failing on invalid UTF-16
Fixes #15279 Signed-off-by: Peter Atashian <[email protected]>
1 parent 82c0527 commit d3ec067

File tree

3 files changed

+39
-57
lines changed

3 files changed

+39
-57
lines changed

src/liblibc/lib.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,7 @@ pub use funcs::bsd43::{shutdown};
249249
#[cfg(windows)] pub use types::os::arch::extra::{LARGE_INTEGER, LPVOID, LONG};
250250
#[cfg(windows)] pub use types::os::arch::extra::{time64_t, OVERLAPPED, LPCWSTR};
251251
#[cfg(windows)] pub use types::os::arch::extra::{LPOVERLAPPED, SIZE_T, LPDWORD};
252-
#[cfg(windows)] pub use types::os::arch::extra::{SECURITY_ATTRIBUTES};
252+
#[cfg(windows)] pub use types::os::arch::extra::{SECURITY_ATTRIBUTES, WIN32_FIND_DATAW};
253253
#[cfg(windows)] pub use funcs::c95::string::{wcslen};
254254
#[cfg(windows)] pub use funcs::posix88::stat_::{wstat, wutime, wchmod, wrmdir};
255255
#[cfg(windows)] pub use funcs::bsd43::{closesocket};
@@ -1638,6 +1638,22 @@ pub mod types {
16381638
pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO;
16391639

16401640
pub type GROUP = c_uint;
1641+
1642+
#[repr(C)]
1643+
pub struct WIN32_FIND_DATAW {
1644+
pub dwFileAttributes: DWORD,
1645+
pub ftCreationTime: FILETIME,
1646+
pub ftLastAccessTime: FILETIME,
1647+
pub ftLastWriteTime: FILETIME,
1648+
pub nFileSizeHigh: DWORD,
1649+
pub nFileSizeLow: DWORD,
1650+
pub dwReserved0: DWORD,
1651+
pub dwReserved1: DWORD,
1652+
pub cFileName: [wchar_t, ..260], // #define MAX_PATH 260
1653+
pub cAlternateFileName: [wchar_t, ..14],
1654+
}
1655+
1656+
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
16411657
}
16421658
}
16431659
}
@@ -4763,7 +4779,7 @@ pub mod funcs {
47634779
LPMEMORY_BASIC_INFORMATION,
47644780
LPSYSTEM_INFO, HANDLE, LPHANDLE,
47654781
LARGE_INTEGER, PLARGE_INTEGER,
4766-
LPFILETIME};
4782+
LPFILETIME, LPWIN32_FIND_DATAW};
47674783

47684784
extern "system" {
47694785
pub fn GetEnvironmentVariableW(n: LPCWSTR,
@@ -4793,9 +4809,9 @@ pub mod funcs {
47934809
-> DWORD;
47944810
pub fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
47954811
pub fn GetLastError() -> DWORD;
4796-
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: HANDLE)
4812+
pub fn FindFirstFileW(fileName: LPCWSTR, findFileData: LPWIN32_FIND_DATAW)
47974813
-> HANDLE;
4798-
pub fn FindNextFileW(findFile: HANDLE, findFileData: HANDLE)
4814+
pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW)
47994815
-> BOOL;
48004816
pub fn FindClose(findFile: HANDLE) -> BOOL;
48014817
pub fn DuplicateHandle(hSourceProcessHandle: HANDLE,

src/libnative/io/file_windows.rs

+19-26
Original file line numberDiff line numberDiff line change
@@ -11,16 +11,14 @@
1111
//! Blocking Windows-based file I/O
1212
1313
use alloc::arc::Arc;
14-
use libc::{c_int, c_void};
15-
use libc;
14+
use libc::{mod, c_int};
1615
use std::c_str::CString;
1716
use std::mem;
1817
use std::os::windows::fill_utf16_buf_and_decode;
1918
use std::ptr;
2019
use std::rt::rtio;
2120
use std::rt::rtio::{IoResult, IoError};
2221
use std::str;
23-
use std::vec;
2422

2523
pub type fd_t = libc::c_int;
2624

@@ -344,8 +342,6 @@ pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> {
344342
}
345343

346344
pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
347-
use std::rt::libc_heap::malloc_raw;
348-
349345
fn prune(root: &CString, dirs: Vec<Path>) -> Vec<CString> {
350346
let root = unsafe { CString::new(root.as_ptr(), false) };
351347
let root = Path::new(root);
@@ -355,38 +351,35 @@ pub fn readdir(p: &CString) -> IoResult<Vec<CString>> {
355351
}).map(|path| root.join(path).to_c_str()).collect()
356352
}
357353

358-
extern {
359-
fn rust_list_dir_wfd_size() -> libc::size_t;
360-
fn rust_list_dir_wfd_fp_buf(wfd: *mut libc::c_void) -> *const u16;
361-
}
362354
let star = Path::new(unsafe {
363355
CString::new(p.as_ptr(), false)
364356
}).join("*");
365357
let path = try!(to_utf16(&star.to_c_str()));
366358

367359
unsafe {
368-
let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
369-
let find_handle = libc::FindFirstFileW(path.as_ptr(),
370-
wfd_ptr as libc::HANDLE);
360+
let mut wfd = mem::zeroed();
361+
let find_handle = libc::FindFirstFileW(path.as_ptr(), &mut wfd);
371362
if find_handle != libc::INVALID_HANDLE_VALUE {
372-
let mut paths = vec!();
373-
let mut more_files = 1 as libc::c_int;
363+
let mut paths = vec![];
364+
let mut more_files = 1 as libc::BOOL;
374365
while more_files != 0 {
375-
let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr as *mut c_void);
376-
if fp_buf as uint == 0 {
377-
fail!("os::list_dir() failure: got null ptr from wfd");
378-
} else {
379-
let fp_vec = vec::raw::from_buf(fp_buf, libc::wcslen(fp_buf) as uint);
380-
let fp_trimmed = str::truncate_utf16_at_nul(fp_vec.as_slice());
381-
let fp_str = String::from_utf16(fp_trimmed)
382-
.expect("rust_list_dir_wfd_fp_buf returned invalid UTF-16");
383-
paths.push(Path::new(fp_str));
366+
{
367+
let filename = str::truncate_utf16_at_nul(wfd.cFileName);
368+
match String::from_utf16(filename) {
369+
Some(filename) => paths.push(Path::new(filename)),
370+
None => {
371+
assert!(libc::FindClose(find_handle) != 0);
372+
return Err(IoError {
373+
code: super::c::ERROR_ILLEGAL_CHARACTER as uint,
374+
extra: 0,
375+
detail: Some(format!("path was not valid UTF-16: {}", filename)),
376+
})
377+
}, // FIXME #12056: Convert the UCS-2 to invalid utf-8 instead of erroring
378+
}
384379
}
385-
more_files = libc::FindNextFileW(find_handle,
386-
wfd_ptr as libc::HANDLE);
380+
more_files = libc::FindNextFileW(find_handle, &mut wfd);
387381
}
388382
assert!(libc::FindClose(find_handle) != 0);
389-
libc::free(wfd_ptr as *mut c_void);
390383
Ok(prune(p, paths))
391384
} else {
392385
Err(super::last_error())

src/rt/rust_builtin.c

-27
Original file line numberDiff line numberDiff line change
@@ -100,33 +100,6 @@ rust_list_dir_val(struct dirent* entry_ptr) {
100100
}
101101
#endif
102102

103-
size_t
104-
#if defined(__WIN32__)
105-
rust_list_dir_wfd_size() {
106-
return sizeof(WIN32_FIND_DATAW);
107-
}
108-
#else
109-
rust_list_dir_wfd_size() {
110-
return 0;
111-
}
112-
#endif
113-
114-
void*
115-
#if defined(__WIN32__)
116-
rust_list_dir_wfd_fp_buf(WIN32_FIND_DATAW* wfd) {
117-
if(wfd == NULL) {
118-
return 0;
119-
}
120-
else {
121-
return wfd->cFileName;
122-
}
123-
}
124-
#else
125-
rust_list_dir_wfd_fp_buf(void* wfd) {
126-
return 0;
127-
}
128-
#endif
129-
130103
typedef struct {
131104
int32_t tm_sec;
132105
int32_t tm_min;

0 commit comments

Comments
 (0)