about summary refs log tree commit diff
path: root/src/libstd/sys/windows/mod.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd/sys/windows/mod.rs')
-rw-r--r--src/libstd/sys/windows/mod.rs111
1 files changed, 92 insertions, 19 deletions
diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs
index e8b65c9b64e..8dd467eba9e 100644
--- a/src/libstd/sys/windows/mod.rs
+++ b/src/libstd/sys/windows/mod.rs
@@ -11,18 +11,14 @@
 #![allow(missing_docs)]
 #![allow(non_camel_case_types)]
 #![allow(non_snake_case)]
-#![allow(unused_imports)]
-#![allow(dead_code)]
-#![allow(unused_unsafe)]
-#![allow(unused_mut)]
-
-extern crate libc;
 
 use prelude::v1::*;
 
-use num;
+use ffi::OsStr;
+use libc;
 use mem;
 use old_io::{self, IoResult, IoError};
+use os::windows::OsStrExt;
 use sync::{Once, ONCE_INIT};
 
 macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
@@ -38,9 +34,10 @@ macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => (
 
 pub mod backtrace;
 pub mod c;
-pub mod ext;
 pub mod condvar;
+pub mod ext;
 pub mod fs;
+pub mod handle;
 pub mod helper_signal;
 pub mod mutex;
 pub mod os;
@@ -48,12 +45,12 @@ pub mod os_str;
 pub mod pipe;
 pub mod process;
 pub mod rwlock;
-pub mod sync;
 pub mod stack_overflow;
+pub mod sync;
 pub mod tcp;
-pub mod time;
 pub mod thread;
 pub mod thread_local;
+pub mod time;
 pub mod timer;
 pub mod tty;
 pub mod udp;
@@ -158,7 +155,7 @@ pub fn ms_to_timeval(ms: u64) -> libc::timeval {
 
 pub fn wouldblock() -> bool {
     let err = os::errno();
-    err == libc::WSAEWOULDBLOCK as uint
+    err == libc::WSAEWOULDBLOCK as i32
 }
 
 pub fn set_nonblocking(fd: sock_t, nb: bool) -> IoResult<()> {
@@ -191,17 +188,93 @@ pub fn unimpl() -> IoError {
     }
 }
 
-pub fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
+fn to_utf16(s: Option<&str>) -> IoResult<Vec<u16>> {
     match s {
-        Some(s) => Ok({
-            let mut s = s.utf16_units().collect::<Vec<u16>>();
-            s.push(0);
-            s
-        }),
+        Some(s) => Ok(to_utf16_os(OsStr::from_str(s))),
         None => Err(IoError {
             kind: old_io::InvalidInput,
             desc: "valid unicode input required",
-            detail: None
-        })
+            detail: None,
+        }),
+    }
+}
+
+fn to_utf16_os(s: &OsStr) -> Vec<u16> {
+    let mut v: Vec<_> = s.encode_wide().collect();
+    v.push(0);
+    v
+}
+
+// Many Windows APIs follow a pattern of where we hand the a buffer and then
+// they will report back to us how large the buffer should be or how many bytes
+// currently reside in the buffer. This function is an abstraction over these
+// functions by making them easier to call.
+//
+// The first callback, `f1`, is yielded a (pointer, len) pair which can be
+// passed to a syscall. The `ptr` is valid for `len` items (u16 in this case).
+// The closure is expected to return what the syscall returns which will be
+// interpreted by this function to determine if the syscall needs to be invoked
+// again (with more buffer space).
+//
+// Once the syscall has completed (errors bail out early) the second closure is
+// yielded the data which has been read from the syscall. The return value
+// from this closure is then the return value of the function.
+fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> IoResult<T>
+    where F1: FnMut(*mut u16, libc::DWORD) -> libc::DWORD,
+          F2: FnOnce(&[u16]) -> T
+{
+    // Start off with a stack buf but then spill over to the heap if we end up
+    // needing more space.
+    let mut stack_buf = [0u16; 512];
+    let mut heap_buf = Vec::new();
+    unsafe {
+        let mut n = stack_buf.len();
+        loop {
+            let buf = if n <= stack_buf.len() {
+                &mut stack_buf[]
+            } else {
+                let extra = n - heap_buf.len();
+                heap_buf.reserve(extra);
+                heap_buf.set_len(n);
+                &mut heap_buf[]
+            };
+
+            // This function is typically called on windows API functions which
+            // will return the correct length of the string, but these functions
+            // also return the `0` on error. In some cases, however, the
+            // returned "correct length" may actually be 0!
+            //
+            // To handle this case we call `SetLastError` to reset it to 0 and
+            // then check it again if we get the "0 error value". If the "last
+            // error" is still 0 then we interpret it as a 0 length buffer and
+            // not an actual error.
+            c::SetLastError(0);
+            let k = match f1(buf.as_mut_ptr(), n as libc::DWORD) {
+                0 if libc::GetLastError() == 0 => 0,
+                0 => return Err(IoError::last_error()),
+                n => n,
+            } as usize;
+            if k == n && libc::GetLastError() ==
+                            libc::ERROR_INSUFFICIENT_BUFFER as libc::DWORD {
+                n *= 2;
+            } else if k >= n {
+                n = k;
+            } else {
+                return Ok(f2(&buf[..k]))
+            }
+        }
+    }
+}
+
+fn os2path(s: &[u16]) -> Path {
+    // FIXME: this should not be a panicking conversion (aka path reform)
+    Path::new(String::from_utf16(s).unwrap())
+}
+
+pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] {
+    match v.iter().position(|c| *c == 0) {
+        // don't include the 0
+        Some(i) => &v[..i],
+        None => v
     }
 }