]> git.lizzy.rs Git - rust.git/commitdiff
Complete renaming of win32 to windows
authorVadim Chugunov <vadimcn@gmail.com>
Sat, 23 Aug 2014 08:12:59 +0000 (01:12 -0700)
committerVadim Chugunov <vadimcn@gmail.com>
Sat, 23 Aug 2014 09:11:28 +0000 (02:11 -0700)
19 files changed:
src/liblibc/lib.rs
src/libnative/io/c_win32.rs [deleted file]
src/libnative/io/c_windows.rs [new file with mode: 0644]
src/libnative/io/file_win32.rs [deleted file]
src/libnative/io/file_windows.rs [new file with mode: 0644]
src/libnative/io/mod.rs
src/libnative/io/pipe_win32.rs [deleted file]
src/libnative/io/pipe_windows.rs [new file with mode: 0644]
src/libnative/io/process.rs
src/libnative/io/timer_win32.rs [deleted file]
src/libnative/io/timer_windows.rs [new file with mode: 0644]
src/libnative/io/tty_win32.rs [deleted file]
src/libnative/io/tty_windows.rs [new file with mode: 0644]
src/librustc/back/link.rs
src/librustc/middle/trans/adt.rs
src/libstd/io/mod.rs
src/libstd/os.rs
src/libterm/win.rs
src/test/run-pass/linkage-visibility.rs

index 859a2bce9728e181e2dae95da4ed27376bcddde1..807635f9b82a3c58fcb4d15dbbb4c392b6588638 100644 (file)
@@ -64,7 +64,7 @@
 * sanity while editing, filling-in-details and eliminating duplication) into
 * definitions common-to-all (held in modules named c95, c99, posix88, posix01
 * and posix08) and definitions that appear only on *some* platforms (named
-* 'extra'). This would be things like significant OSX foundation kit, or win32
+* 'extra'). This would be things like significant OSX foundation kit, or Windows
 * library kernel32.dll, or various fancy glibc, linux or BSD extensions.
 *
 * In addition to the per-platform 'extra' modules, we define a module of
@@ -1195,7 +1195,6 @@ pub mod extra {
     }
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod os {
         pub mod common {
             pub mod posix01 {
@@ -1203,7 +1202,7 @@ pub mod posix01 {
                 use types::os::arch::extra::{int64, time64_t};
                 use types::os::arch::posix88::{dev_t, ino_t};
 
-                // pub Note: this is the struct called stat64 in win32. Not stat,
+                // pub Note: this is the struct called stat64 in Windows. Not stat,
                 // nor stati64.
                 #[repr(C)]
                 pub struct stat {
@@ -1220,7 +1219,7 @@ pub struct stat {
                     pub st_ctime: time64_t,
                 }
 
-                // note that this is called utimbuf64 in win32
+                // note that this is called utimbuf64 in Windows
                 #[repr(C)]
                 pub struct utimbuf {
                     pub actime: time64_t,
@@ -1907,7 +1906,6 @@ pub mod consts {
     // into this module.
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod os {
         pub mod c95 {
             use types::os::arch::c95::{c_int, c_uint};
@@ -3992,7 +3990,6 @@ pub fn memchr(cx: *const c_void, c: c_int,
     // with the same POSIX functions and types as other platforms.
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod posix88 {
         pub mod stat_ {
             use types::os::common::posix01::{stat, utimbuf};
@@ -4422,7 +4419,6 @@ pub fn posix_madvise(addr: *mut c_void,
     }
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod posix01 {
         pub mod stat_ {
         }
@@ -4439,7 +4435,6 @@ pub mod mman {
 
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     #[cfg(target_os = "linux")]
     #[cfg(target_os = "android")]
     #[cfg(target_os = "macos")]
@@ -4578,7 +4573,6 @@ pub fn mincore(addr: *mut c_void, len: size_t, vec: *mut c_uchar)
 
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod bsd44 {
     }
 
@@ -4605,7 +4599,6 @@ pub mod extra {
 
 
     #[cfg(target_os = "windows")]
-    #[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
     pub mod extra {
 
         pub mod kernel32 {
diff --git a/src/libnative/io/c_win32.rs b/src/libnative/io/c_win32.rs
deleted file mode 100644 (file)
index 80c9e91..0000000
+++ /dev/null
@@ -1,207 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! C definitions used by libnative that don't belong in liblibc
-
-#![allow(type_overflow)]
-
-use libc;
-
-pub static WSADESCRIPTION_LEN: uint = 256;
-pub static WSASYS_STATUS_LEN: uint = 128;
-pub static FIONBIO: libc::c_long = 0x8004667e;
-static FD_SETSIZE: uint = 64;
-pub static MSG_DONTWAIT: libc::c_int = 0;
-pub static ERROR_ILLEGAL_CHARACTER: libc::c_int = 582;
-pub static ENABLE_ECHO_INPUT: libc::DWORD = 0x4;
-pub static ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80;
-pub static ENABLE_INSERT_MODE: libc::DWORD = 0x20;
-pub static ENABLE_LINE_INPUT: libc::DWORD = 0x2;
-pub static ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1;
-pub static ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40;
-
-#[repr(C)]
-#[cfg(target_arch = "x86")]
-pub struct WSADATA {
-    pub wVersion: libc::WORD,
-    pub wHighVersion: libc::WORD,
-    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
-    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
-    pub iMaxSockets: u16,
-    pub iMaxUdpDg: u16,
-    pub lpVendorInfo: *mut u8,
-}
-#[repr(C)]
-#[cfg(target_arch = "x86_64")]
-pub struct WSADATA {
-    pub wVersion: libc::WORD,
-    pub wHighVersion: libc::WORD,
-    pub iMaxSockets: u16,
-    pub iMaxUdpDg: u16,
-    pub lpVendorInfo: *mut u8,
-    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
-    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
-}
-
-pub type LPWSADATA = *mut WSADATA;
-
-#[repr(C)]
-pub struct fd_set {
-    fd_count: libc::c_uint,
-    fd_array: [libc::SOCKET, ..FD_SETSIZE],
-}
-
-pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
-    set.fd_array[set.fd_count as uint] = s;
-    set.fd_count += 1;
-}
-
-#[link(name = "ws2_32")]
-extern "system" {
-    pub fn WSAStartup(wVersionRequested: libc::WORD,
-                      lpWSAData: LPWSADATA) -> libc::c_int;
-    pub fn WSAGetLastError() -> libc::c_int;
-
-    pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long,
-                       argp: *mut libc::c_ulong) -> libc::c_int;
-    pub fn select(nfds: libc::c_int,
-                  readfds: *mut fd_set,
-                  writefds: *mut fd_set,
-                  exceptfds: *mut fd_set,
-                  timeout: *mut libc::timeval) -> libc::c_int;
-    pub fn getsockopt(sockfd: libc::SOCKET,
-                      level: libc::c_int,
-                      optname: libc::c_int,
-                      optval: *mut libc::c_char,
-                      optlen: *mut libc::c_int) -> libc::c_int;
-
-    pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL;
-    pub fn CancelIoEx(hFile: libc::HANDLE,
-                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
-}
-
-pub mod compat {
-    use std::intrinsics::{atomic_store_relaxed, transmute};
-    use std::iter::Iterator;
-    use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
-
-    extern "system" {
-        fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
-        fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
-    }
-
-    // store_func() is idempotent, so using relaxed ordering for the atomics
-    // should be enough.  This way, calling a function in this compatibility
-    // layer (after it's loaded) shouldn't be any slower than a regular DLL
-    // call.
-    unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
-        let module: Vec<u16> = module.utf16_units().collect();
-        let module = module.append_one(0);
-        symbol.with_c_str(|symbol| {
-            let handle = GetModuleHandleW(module.as_ptr());
-            let func: uint = transmute(GetProcAddress(handle, symbol));
-            atomic_store_relaxed(ptr, if func == 0 {
-                fallback
-            } else {
-                func
-            })
-        })
-    }
-
-    /// Macro for creating a compatibility fallback for a Windows function
-    ///
-    /// # Example
-    /// ```
-    /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) {
-    ///     // Fallback implementation
-    /// })
-    /// ```
-    ///
-    /// Note that arguments unused by the fallback implementation should not be called `_` as
-    /// they are used to be passed to the real function if available.
-    macro_rules! compat_fn(
-        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*)
-                                      -> $rettype:ty $fallback:block) => (
-            #[inline(always)]
-            pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
-                static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk;
-
-                extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
-                    unsafe {
-                        ::io::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
-                                                    stringify!($module),
-                                                    stringify!($symbol),
-                                                    fallback as uint);
-                        ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
-                    }
-                }
-
-                extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
-
-                ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
-            }
-        );
-
-        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => (
-            compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback)
-        )
-    )
-
-    /// Compatibility layer for functions in `kernel32.dll`
-    ///
-    /// Latest versions of Windows this is needed for:
-    ///
-    /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003
-    /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003
-    pub mod kernel32 {
-        use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
-        use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
-
-        extern "system" {
-            fn SetLastError(dwErrCode: DWORD);
-        }
-
-        compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
-                                                 _lpTargetFileName: LPCWSTR,
-                                                 _dwFlags: DWORD) -> BOOLEAN {
-            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
-            0
-        })
-
-        compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE,
-                                                       _lpszFilePath: LPCWSTR,
-                                                       _cchFilePath: DWORD,
-                                                       _dwFlags: DWORD) -> DWORD {
-            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
-            0
-        })
-    }
-}
-
-extern "system" {
-    // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
-    pub fn ReadConsoleW(hConsoleInput: libc::HANDLE,
-                        lpBuffer: libc::LPVOID,
-                        nNumberOfCharsToRead: libc::DWORD,
-                        lpNumberOfCharsRead: libc::LPDWORD,
-                        pInputControl: libc::LPVOID) -> libc::BOOL;
-
-    pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE,
-                         lpBuffer: libc::types::os::arch::extra::LPCVOID,
-                         nNumberOfCharsToWrite: libc::DWORD,
-                         lpNumberOfCharsWritten: libc::LPDWORD,
-                         lpReserved: libc::LPVOID) -> libc::BOOL;
-
-    pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
-                          lpMode: libc::LPDWORD) -> libc::BOOL;
-
-    pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE,
-                          lpMode: libc::DWORD) -> libc::BOOL;
-}
diff --git a/src/libnative/io/c_windows.rs b/src/libnative/io/c_windows.rs
new file mode 100644 (file)
index 0000000..80c9e91
--- /dev/null
@@ -0,0 +1,207 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! C definitions used by libnative that don't belong in liblibc
+
+#![allow(type_overflow)]
+
+use libc;
+
+pub static WSADESCRIPTION_LEN: uint = 256;
+pub static WSASYS_STATUS_LEN: uint = 128;
+pub static FIONBIO: libc::c_long = 0x8004667e;
+static FD_SETSIZE: uint = 64;
+pub static MSG_DONTWAIT: libc::c_int = 0;
+pub static ERROR_ILLEGAL_CHARACTER: libc::c_int = 582;
+pub static ENABLE_ECHO_INPUT: libc::DWORD = 0x4;
+pub static ENABLE_EXTENDED_FLAGS: libc::DWORD = 0x80;
+pub static ENABLE_INSERT_MODE: libc::DWORD = 0x20;
+pub static ENABLE_LINE_INPUT: libc::DWORD = 0x2;
+pub static ENABLE_PROCESSED_INPUT: libc::DWORD = 0x1;
+pub static ENABLE_QUICK_EDIT_MODE: libc::DWORD = 0x40;
+
+#[repr(C)]
+#[cfg(target_arch = "x86")]
+pub struct WSADATA {
+    pub wVersion: libc::WORD,
+    pub wHighVersion: libc::WORD,
+    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
+    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: *mut u8,
+}
+#[repr(C)]
+#[cfg(target_arch = "x86_64")]
+pub struct WSADATA {
+    pub wVersion: libc::WORD,
+    pub wHighVersion: libc::WORD,
+    pub iMaxSockets: u16,
+    pub iMaxUdpDg: u16,
+    pub lpVendorInfo: *mut u8,
+    pub szDescription: [u8, ..WSADESCRIPTION_LEN + 1],
+    pub szSystemStatus: [u8, ..WSASYS_STATUS_LEN + 1],
+}
+
+pub type LPWSADATA = *mut WSADATA;
+
+#[repr(C)]
+pub struct fd_set {
+    fd_count: libc::c_uint,
+    fd_array: [libc::SOCKET, ..FD_SETSIZE],
+}
+
+pub fn fd_set(set: &mut fd_set, s: libc::SOCKET) {
+    set.fd_array[set.fd_count as uint] = s;
+    set.fd_count += 1;
+}
+
+#[link(name = "ws2_32")]
+extern "system" {
+    pub fn WSAStartup(wVersionRequested: libc::WORD,
+                      lpWSAData: LPWSADATA) -> libc::c_int;
+    pub fn WSAGetLastError() -> libc::c_int;
+
+    pub fn ioctlsocket(s: libc::SOCKET, cmd: libc::c_long,
+                       argp: *mut libc::c_ulong) -> libc::c_int;
+    pub fn select(nfds: libc::c_int,
+                  readfds: *mut fd_set,
+                  writefds: *mut fd_set,
+                  exceptfds: *mut fd_set,
+                  timeout: *mut libc::timeval) -> libc::c_int;
+    pub fn getsockopt(sockfd: libc::SOCKET,
+                      level: libc::c_int,
+                      optname: libc::c_int,
+                      optval: *mut libc::c_char,
+                      optlen: *mut libc::c_int) -> libc::c_int;
+
+    pub fn CancelIo(hFile: libc::HANDLE) -> libc::BOOL;
+    pub fn CancelIoEx(hFile: libc::HANDLE,
+                      lpOverlapped: libc::LPOVERLAPPED) -> libc::BOOL;
+}
+
+pub mod compat {
+    use std::intrinsics::{atomic_store_relaxed, transmute};
+    use std::iter::Iterator;
+    use libc::types::os::arch::extra::{LPCWSTR, HMODULE, LPCSTR, LPVOID};
+
+    extern "system" {
+        fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE;
+        fn GetProcAddress(hModule: HMODULE, lpProcName: LPCSTR) -> LPVOID;
+    }
+
+    // store_func() is idempotent, so using relaxed ordering for the atomics
+    // should be enough.  This way, calling a function in this compatibility
+    // layer (after it's loaded) shouldn't be any slower than a regular DLL
+    // call.
+    unsafe fn store_func(ptr: *mut uint, module: &str, symbol: &str, fallback: uint) {
+        let module: Vec<u16> = module.utf16_units().collect();
+        let module = module.append_one(0);
+        symbol.with_c_str(|symbol| {
+            let handle = GetModuleHandleW(module.as_ptr());
+            let func: uint = transmute(GetProcAddress(handle, symbol));
+            atomic_store_relaxed(ptr, if func == 0 {
+                fallback
+            } else {
+                func
+            })
+        })
+    }
+
+    /// Macro for creating a compatibility fallback for a Windows function
+    ///
+    /// # Example
+    /// ```
+    /// compat_fn!(adll32::SomeFunctionW(_arg: LPCWSTR) {
+    ///     // Fallback implementation
+    /// })
+    /// ```
+    ///
+    /// Note that arguments unused by the fallback implementation should not be called `_` as
+    /// they are used to be passed to the real function if available.
+    macro_rules! compat_fn(
+        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*)
+                                      -> $rettype:ty $fallback:block) => (
+            #[inline(always)]
+            pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype {
+                static mut ptr: extern "system" fn($($argname: $argtype),*) -> $rettype = thunk;
+
+                extern "system" fn thunk($($argname: $argtype),*) -> $rettype {
+                    unsafe {
+                        ::io::c::compat::store_func(&mut ptr as *mut _ as *mut uint,
+                                                    stringify!($module),
+                                                    stringify!($symbol),
+                                                    fallback as uint);
+                        ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+                    }
+                }
+
+                extern "system" fn fallback($($argname: $argtype),*) -> $rettype $fallback
+
+                ::std::intrinsics::atomic_load_relaxed(&ptr)($($argname),*)
+            }
+        );
+
+        ($module:ident::$symbol:ident($($argname:ident: $argtype:ty),*) $fallback:block) => (
+            compat_fn!($module::$symbol($($argname: $argtype),*) -> () $fallback)
+        )
+    )
+
+    /// Compatibility layer for functions in `kernel32.dll`
+    ///
+    /// Latest versions of Windows this is needed for:
+    ///
+    /// * `CreateSymbolicLinkW`: Windows XP, Windows Server 2003
+    /// * `GetFinalPathNameByHandleW`: Windows XP, Windows Server 2003
+    pub mod kernel32 {
+        use libc::types::os::arch::extra::{DWORD, LPCWSTR, BOOLEAN, HANDLE};
+        use libc::consts::os::extra::ERROR_CALL_NOT_IMPLEMENTED;
+
+        extern "system" {
+            fn SetLastError(dwErrCode: DWORD);
+        }
+
+        compat_fn!(kernel32::CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR,
+                                                 _lpTargetFileName: LPCWSTR,
+                                                 _dwFlags: DWORD) -> BOOLEAN {
+            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
+            0
+        })
+
+        compat_fn!(kernel32::GetFinalPathNameByHandleW(_hFile: HANDLE,
+                                                       _lpszFilePath: LPCWSTR,
+                                                       _cchFilePath: DWORD,
+                                                       _dwFlags: DWORD) -> DWORD {
+            unsafe { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); }
+            0
+        })
+    }
+}
+
+extern "system" {
+    // FIXME - pInputControl should be PCONSOLE_READCONSOLE_CONTROL
+    pub fn ReadConsoleW(hConsoleInput: libc::HANDLE,
+                        lpBuffer: libc::LPVOID,
+                        nNumberOfCharsToRead: libc::DWORD,
+                        lpNumberOfCharsRead: libc::LPDWORD,
+                        pInputControl: libc::LPVOID) -> libc::BOOL;
+
+    pub fn WriteConsoleW(hConsoleOutput: libc::HANDLE,
+                         lpBuffer: libc::types::os::arch::extra::LPCVOID,
+                         nNumberOfCharsToWrite: libc::DWORD,
+                         lpNumberOfCharsWritten: libc::LPDWORD,
+                         lpReserved: libc::LPVOID) -> libc::BOOL;
+
+    pub fn GetConsoleMode(hConsoleHandle: libc::HANDLE,
+                          lpMode: libc::LPDWORD) -> libc::BOOL;
+
+    pub fn SetConsoleMode(hConsoleHandle: libc::HANDLE,
+                          lpMode: libc::DWORD) -> libc::BOOL;
+}
diff --git a/src/libnative/io/file_win32.rs b/src/libnative/io/file_win32.rs
deleted file mode 100644 (file)
index fe29c02..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Blocking win32-based file I/O
-
-use alloc::arc::Arc;
-use libc::{c_int, c_void};
-use libc;
-use std::c_str::CString;
-use std::mem;
-use std::os::win32::fill_utf16_buf_and_decode;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::{IoResult, IoError};
-use std::str;
-use std::vec;
-
-pub type fd_t = libc::c_int;
-
-struct Inner {
-    fd: fd_t,
-    close_on_drop: bool,
-}
-
-pub struct FileDesc {
-    inner: Arc<Inner>
-}
-
-impl FileDesc {
-    /// Create a `FileDesc` from an open C file descriptor.
-    ///
-    /// The `FileDesc` will take ownership of the specified file descriptor and
-    /// close it upon destruction if the `close_on_drop` flag is true, otherwise
-    /// it will not close the file descriptor when this `FileDesc` is dropped.
-    ///
-    /// Note that all I/O operations done on this object will be *blocking*, but
-    /// they do not require the runtime to be active.
-    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
-        FileDesc { inner: Arc::new(Inner {
-            fd: fd,
-            close_on_drop: close_on_drop
-        }) }
-    }
-
-    pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        let mut read = 0;
-        let ret = unsafe {
-            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
-                           buf.len() as libc::DWORD, &mut read,
-                           ptr::mut_null())
-        };
-        if ret != 0 {
-            Ok(read as uint)
-        } else {
-            Err(super::last_error())
-        }
-    }
-    pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let mut cur = buf.as_ptr();
-        let mut remaining = buf.len();
-        while remaining > 0 {
-            let mut amt = 0;
-            let ret = unsafe {
-                libc::WriteFile(self.handle(), cur as libc::LPVOID,
-                                remaining as libc::DWORD, &mut amt,
-                                ptr::mut_null())
-            };
-            if ret != 0 {
-                remaining -= amt as uint;
-                cur = unsafe { cur.offset(amt as int) };
-            } else {
-                return Err(super::last_error())
-            }
-        }
-        Ok(())
-    }
-
-    pub fn fd(&self) -> fd_t { self.inner.fd }
-
-    pub fn handle(&self) -> libc::HANDLE {
-        unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE }
-    }
-
-    // A version of seek that takes &self so that tell can call it
-    //   - the private seek should of course take &mut self.
-    fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
-        let whence = match style {
-            rtio::SeekSet => libc::FILE_BEGIN,
-            rtio::SeekEnd => libc::FILE_END,
-            rtio::SeekCur => libc::FILE_CURRENT,
-        };
-        unsafe {
-            let mut newpos = 0;
-            match libc::SetFilePointerEx(self.handle(), pos, &mut newpos,
-                                         whence) {
-                0 => Err(super::last_error()),
-                _ => Ok(newpos as u64),
-            }
-        }
-    }
-
-}
-
-impl rtio::RtioFileStream for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
-        self.inner_read(buf).map(|i| i as int)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-
-    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
-        let mut read = 0;
-        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        overlap.Offset = offset as libc::DWORD;
-        overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
-        let ret = unsafe {
-            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
-                           buf.len() as libc::DWORD, &mut read,
-                           &mut overlap)
-        };
-        if ret != 0 {
-            Ok(read as int)
-        } else {
-            Err(super::last_error())
-        }
-    }
-    fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> IoResult<()> {
-        let mut cur = buf.as_ptr();
-        let mut remaining = buf.len();
-        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        while remaining > 0 {
-            overlap.Offset = offset as libc::DWORD;
-            overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
-            let mut amt = 0;
-            let ret = unsafe {
-                libc::WriteFile(self.handle(), cur as libc::LPVOID,
-                                remaining as libc::DWORD, &mut amt,
-                                &mut overlap)
-            };
-            if ret != 0 {
-                remaining -= amt as uint;
-                cur = unsafe { cur.offset(amt as int) };
-                offset += amt as u64;
-            } else {
-                return Err(super::last_error())
-            }
-        }
-        Ok(())
-    }
-
-    fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
-        self.seek_common(pos, style)
-    }
-
-    fn tell(&self) -> IoResult<u64> {
-        self.seek_common(0, rtio::SeekCur)
-    }
-
-    fn fsync(&mut self) -> IoResult<()> {
-        super::mkerr_winbool(unsafe {
-            libc::FlushFileBuffers(self.handle())
-        })
-    }
-
-    fn datasync(&mut self) -> IoResult<()> { return self.fsync(); }
-
-    fn truncate(&mut self, offset: i64) -> IoResult<()> {
-        let orig_pos = try!(self.tell());
-        let _ = try!(self.seek(offset, rtio::SeekSet));
-        let ret = unsafe {
-            match libc::SetEndOfFile(self.handle()) {
-                0 => Err(super::last_error()),
-                _ => Ok(())
-            }
-        };
-        let _ = self.seek(orig_pos as i64, rtio::SeekSet);
-        return ret;
-    }
-
-    fn fstat(&mut self) -> IoResult<rtio::FileStat> {
-        let mut stat: libc::stat = unsafe { mem::zeroed() };
-        match unsafe { libc::fstat(self.fd(), &mut stat) } {
-            0 => Ok(mkstat(&stat)),
-            _ => Err(super::last_error()),
-        }
-    }
-}
-
-impl rtio::RtioPipe for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
-        box FileDesc { inner: self.inner.clone() } as Box<rtio::RtioPipe + Send>
-    }
-
-    // Only supported on named pipes currently. Note that this doesn't have an
-    // impact on the std::io primitives, this is never called via
-    // std::io::PipeStream. If the functionality is exposed in the future, then
-    // these methods will need to be implemented.
-    fn close_read(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn close_write(&mut self) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn set_timeout(&mut self, _t: Option<u64>) {}
-    fn set_read_timeout(&mut self, _t: Option<u64>) {}
-    fn set_write_timeout(&mut self, _t: Option<u64>) {}
-}
-
-impl rtio::RtioTTY for FileDesc {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        self.inner_read(buf)
-    }
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        self.inner_write(buf)
-    }
-    fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
-        Err(super::unimpl())
-    }
-    fn get_winsize(&mut self) -> IoResult<(int, int)> {
-        Err(super::unimpl())
-    }
-    fn isatty(&self) -> bool { false }
-}
-
-impl Drop for Inner {
-    fn drop(&mut self) {
-        // closing stdio file handles makes no sense, so never do it. Also, note
-        // that errors are ignored when closing a file descriptor. The reason
-        // for this is that if an error occurs we don't actually know if the
-        // file descriptor was closed or not, and if we retried (for something
-        // like EINTR), we might close another valid file descriptor (opened
-        // after we closed ours.
-        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
-            let n = unsafe { libc::close(self.fd) };
-            if n != 0 {
-                println!("error {} when closing file descriptor {}", n, self.fd);
-            }
-        }
-    }
-}
-
-pub fn to_utf16(s: &CString) -> IoResult<Vec<u16>> {
-    match s.as_str() {
-        Some(s) => Ok(s.utf16_units().collect::<Vec<u16>>().append_one(0)),
-        None => Err(IoError {
-            code: libc::ERROR_INVALID_NAME as uint,
-            extra: 0,
-            detail: Some("valid unicode input required".to_string()),
-        })
-    }
-}
-
-pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess)
-        -> IoResult<FileDesc> {
-    // Flags passed to open_osfhandle
-    let flags = match fm {
-        rtio::Open => 0,
-        rtio::Append => libc::O_APPEND,
-        rtio::Truncate => libc::O_TRUNC,
-    };
-    let flags = match fa {
-        rtio::Read => flags | libc::O_RDONLY,
-        rtio::Write => flags | libc::O_WRONLY | libc::O_CREAT,
-        rtio::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT,
-    };
-
-    let mut dwDesiredAccess = match fa {
-        rtio::Read => libc::FILE_GENERIC_READ,
-        rtio::Write => libc::FILE_GENERIC_WRITE,
-        rtio::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE
-    };
-
-    // libuv has a good comment about this, but the basic idea is what we try to
-    // emulate unix semantics by enabling all sharing by allowing things such as
-    // deleting a file while it's still open.
-    let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE |
-                      libc::FILE_SHARE_DELETE;
-
-    let dwCreationDisposition = match (fm, fa) {
-        (rtio::Truncate, rtio::Read) => libc::TRUNCATE_EXISTING,
-        (rtio::Truncate, _) => libc::CREATE_ALWAYS,
-        (rtio::Open, rtio::Read) => libc::OPEN_EXISTING,
-        (rtio::Open, _) => libc::OPEN_ALWAYS,
-        (rtio::Append, rtio::Read) => {
-            dwDesiredAccess |= libc::FILE_APPEND_DATA;
-            libc::OPEN_EXISTING
-        }
-        (rtio::Append, _) => {
-            dwDesiredAccess &= !libc::FILE_WRITE_DATA;
-            dwDesiredAccess |= libc::FILE_APPEND_DATA;
-            libc::OPEN_ALWAYS
-        }
-    };
-
-    let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL;
-    // Compat with unix, this allows opening directories (see libuv)
-    dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS;
-
-    let path = try!(to_utf16(path));
-    let handle = unsafe {
-        libc::CreateFileW(path.as_ptr(),
-                          dwDesiredAccess,
-                          dwShareMode,
-                          ptr::mut_null(),
-                          dwCreationDisposition,
-                          dwFlagsAndAttributes,
-                          ptr::mut_null())
-    };
-    if handle == libc::INVALID_HANDLE_VALUE {
-        Err(super::last_error())
-    } else {
-        let fd = unsafe {
-            libc::open_osfhandle(handle as libc::intptr_t, flags)
-        };
-        if fd < 0 {
-            let _ = unsafe { libc::CloseHandle(handle) };
-            Err(super::last_error())
-        } else {
-            Ok(FileDesc::new(fd, true))
-        }
-    }
-}
-
-pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_winbool(unsafe {
-        // FIXME: turn mode into something useful? #2623
-        libc::CreateDirectoryW(p.as_ptr(), ptr::mut_null())
-    })
-}
-
-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);
-
-        dirs.move_iter().filter(|path| {
-            path.as_vec() != b"." && path.as_vec() != b".."
-        }).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);
-        if find_handle != libc::INVALID_HANDLE_VALUE {
-            let mut paths = vec!();
-            let mut more_files = 1 as libc::c_int;
-            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));
-                }
-                more_files = libc::FindNextFileW(find_handle,
-                                                 wfd_ptr as libc::HANDLE);
-            }
-            assert!(libc::FindClose(find_handle) != 0);
-            libc::free(wfd_ptr as *mut c_void);
-            Ok(prune(p, paths))
-        } else {
-            Err(super::last_error())
-        }
-    }
-}
-
-pub fn unlink(p: &CString) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_winbool(unsafe {
-        libc::DeleteFileW(p.as_ptr())
-    })
-}
-
-pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
-    let old = try!(to_utf16(old));
-    let new = try!(to_utf16(new));
-    super::mkerr_winbool(unsafe {
-        libc::MoveFileExW(old.as_ptr(), new.as_ptr(),
-                          libc::MOVEFILE_REPLACE_EXISTING)
-    })
-}
-
-pub fn chmod(p: &CString, mode: uint) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe {
-        libc::wchmod(p.as_ptr(), mode as libc::c_int)
-    })
-}
-
-pub fn rmdir(p: &CString) -> IoResult<()> {
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) })
-}
-
-pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> {
-    // libuv has this as a no-op, so seems like this should as well?
-    Ok(())
-}
-
-pub fn readlink(p: &CString) -> IoResult<CString> {
-    // FIXME: I have a feeling that this reads intermediate symlinks as well.
-    use io::c::compat::kernel32::GetFinalPathNameByHandleW;
-    let p = try!(to_utf16(p));
-    let handle = unsafe {
-        libc::CreateFileW(p.as_ptr(),
-                          libc::GENERIC_READ,
-                          libc::FILE_SHARE_READ,
-                          ptr::mut_null(),
-                          libc::OPEN_EXISTING,
-                          libc::FILE_ATTRIBUTE_NORMAL,
-                          ptr::mut_null())
-    };
-    if handle == libc::INVALID_HANDLE_VALUE {
-        return Err(super::last_error())
-    }
-    // Specify (sz - 1) because the documentation states that it's the size
-    // without the null pointer
-    let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
-        GetFinalPathNameByHandleW(handle,
-                                  buf as *const u16,
-                                  sz - 1,
-                                  libc::VOLUME_NAME_DOS)
-    });
-    let ret = match ret {
-        Some(ref s) if s.as_slice().starts_with(r"\\?\") => {
-            Ok(Path::new(s.as_slice().slice_from(4)).to_c_str())
-        }
-        Some(s) => Ok(Path::new(s).to_c_str()),
-        None => Err(super::last_error()),
-    };
-    assert!(unsafe { libc::CloseHandle(handle) } != 0);
-    return ret;
-}
-
-pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
-    use io::c::compat::kernel32::CreateSymbolicLinkW;
-    let src = try!(to_utf16(src));
-    let dst = try!(to_utf16(dst));
-    super::mkerr_winbool(unsafe {
-        CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
-    })
-}
-
-pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
-    let src = try!(to_utf16(src));
-    let dst = try!(to_utf16(dst));
-    super::mkerr_winbool(unsafe {
-        libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::mut_null())
-    })
-}
-
-fn mkstat(stat: &libc::stat) -> rtio::FileStat {
-    rtio::FileStat {
-        size: stat.st_size as u64,
-        kind: stat.st_mode as u64,
-        perm: stat.st_mode as u64,
-        created: stat.st_ctime as u64,
-        modified: stat.st_mtime as u64,
-        accessed: stat.st_atime as u64,
-        device: stat.st_dev as u64,
-        inode: stat.st_ino as u64,
-        rdev: stat.st_rdev as u64,
-        nlink: stat.st_nlink as u64,
-        uid: stat.st_uid as u64,
-        gid: stat.st_gid as u64,
-        blksize: 0,
-        blocks: 0,
-        flags: 0,
-        gen: 0,
-    }
-}
-
-pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
-    let mut stat: libc::stat = unsafe { mem::zeroed() };
-    let p = try!(to_utf16(p));
-    match unsafe { libc::wstat(p.as_ptr(), &mut stat) } {
-        0 => Ok(mkstat(&stat)),
-        _ => Err(super::last_error()),
-    }
-}
-
-pub fn lstat(_p: &CString) -> IoResult<rtio::FileStat> {
-    // FIXME: implementation is missing
-    Err(super::unimpl())
-}
-
-pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
-    let mut buf = libc::utimbuf {
-        actime: atime as libc::time64_t,
-        modtime: mtime as libc::time64_t,
-    };
-    let p = try!(to_utf16(p));
-    super::mkerr_libc(unsafe {
-        libc::wutime(p.as_ptr(), &mut buf)
-    })
-}
diff --git a/src/libnative/io/file_windows.rs b/src/libnative/io/file_windows.rs
new file mode 100644 (file)
index 0000000..cb1d79b
--- /dev/null
@@ -0,0 +1,526 @@
+// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Blocking Windows-based file I/O
+
+use alloc::arc::Arc;
+use libc::{c_int, c_void};
+use libc;
+use std::c_str::CString;
+use std::mem;
+use std::os::windows::fill_utf16_buf_and_decode;
+use std::ptr;
+use std::rt::rtio;
+use std::rt::rtio::{IoResult, IoError};
+use std::str;
+use std::vec;
+
+pub type fd_t = libc::c_int;
+
+struct Inner {
+    fd: fd_t,
+    close_on_drop: bool,
+}
+
+pub struct FileDesc {
+    inner: Arc<Inner>
+}
+
+impl FileDesc {
+    /// Create a `FileDesc` from an open C file descriptor.
+    ///
+    /// The `FileDesc` will take ownership of the specified file descriptor and
+    /// close it upon destruction if the `close_on_drop` flag is true, otherwise
+    /// it will not close the file descriptor when this `FileDesc` is dropped.
+    ///
+    /// Note that all I/O operations done on this object will be *blocking*, but
+    /// they do not require the runtime to be active.
+    pub fn new(fd: fd_t, close_on_drop: bool) -> FileDesc {
+        FileDesc { inner: Arc::new(Inner {
+            fd: fd,
+            close_on_drop: close_on_drop
+        }) }
+    }
+
+    pub fn inner_read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        let mut read = 0;
+        let ret = unsafe {
+            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD, &mut read,
+                           ptr::mut_null())
+        };
+        if ret != 0 {
+            Ok(read as uint)
+        } else {
+            Err(super::last_error())
+        }
+    }
+    pub fn inner_write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let mut cur = buf.as_ptr();
+        let mut remaining = buf.len();
+        while remaining > 0 {
+            let mut amt = 0;
+            let ret = unsafe {
+                libc::WriteFile(self.handle(), cur as libc::LPVOID,
+                                remaining as libc::DWORD, &mut amt,
+                                ptr::mut_null())
+            };
+            if ret != 0 {
+                remaining -= amt as uint;
+                cur = unsafe { cur.offset(amt as int) };
+            } else {
+                return Err(super::last_error())
+            }
+        }
+        Ok(())
+    }
+
+    pub fn fd(&self) -> fd_t { self.inner.fd }
+
+    pub fn handle(&self) -> libc::HANDLE {
+        unsafe { libc::get_osfhandle(self.fd()) as libc::HANDLE }
+    }
+
+    // A version of seek that takes &self so that tell can call it
+    //   - the private seek should of course take &mut self.
+    fn seek_common(&self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
+        let whence = match style {
+            rtio::SeekSet => libc::FILE_BEGIN,
+            rtio::SeekEnd => libc::FILE_END,
+            rtio::SeekCur => libc::FILE_CURRENT,
+        };
+        unsafe {
+            let mut newpos = 0;
+            match libc::SetFilePointerEx(self.handle(), pos, &mut newpos,
+                                         whence) {
+                0 => Err(super::last_error()),
+                _ => Ok(newpos as u64),
+            }
+        }
+    }
+
+}
+
+impl rtio::RtioFileStream for FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<int> {
+        self.inner_read(buf).map(|i| i as int)
+    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.inner_write(buf)
+    }
+
+    fn pread(&mut self, buf: &mut [u8], offset: u64) -> IoResult<int> {
+        let mut read = 0;
+        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlap.Offset = offset as libc::DWORD;
+        overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
+        let ret = unsafe {
+            libc::ReadFile(self.handle(), buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD, &mut read,
+                           &mut overlap)
+        };
+        if ret != 0 {
+            Ok(read as int)
+        } else {
+            Err(super::last_error())
+        }
+    }
+    fn pwrite(&mut self, buf: &[u8], mut offset: u64) -> IoResult<()> {
+        let mut cur = buf.as_ptr();
+        let mut remaining = buf.len();
+        let mut overlap: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        while remaining > 0 {
+            overlap.Offset = offset as libc::DWORD;
+            overlap.OffsetHigh = (offset >> 32) as libc::DWORD;
+            let mut amt = 0;
+            let ret = unsafe {
+                libc::WriteFile(self.handle(), cur as libc::LPVOID,
+                                remaining as libc::DWORD, &mut amt,
+                                &mut overlap)
+            };
+            if ret != 0 {
+                remaining -= amt as uint;
+                cur = unsafe { cur.offset(amt as int) };
+                offset += amt as u64;
+            } else {
+                return Err(super::last_error())
+            }
+        }
+        Ok(())
+    }
+
+    fn seek(&mut self, pos: i64, style: rtio::SeekStyle) -> IoResult<u64> {
+        self.seek_common(pos, style)
+    }
+
+    fn tell(&self) -> IoResult<u64> {
+        self.seek_common(0, rtio::SeekCur)
+    }
+
+    fn fsync(&mut self) -> IoResult<()> {
+        super::mkerr_winbool(unsafe {
+            libc::FlushFileBuffers(self.handle())
+        })
+    }
+
+    fn datasync(&mut self) -> IoResult<()> { return self.fsync(); }
+
+    fn truncate(&mut self, offset: i64) -> IoResult<()> {
+        let orig_pos = try!(self.tell());
+        let _ = try!(self.seek(offset, rtio::SeekSet));
+        let ret = unsafe {
+            match libc::SetEndOfFile(self.handle()) {
+                0 => Err(super::last_error()),
+                _ => Ok(())
+            }
+        };
+        let _ = self.seek(orig_pos as i64, rtio::SeekSet);
+        return ret;
+    }
+
+    fn fstat(&mut self) -> IoResult<rtio::FileStat> {
+        let mut stat: libc::stat = unsafe { mem::zeroed() };
+        match unsafe { libc::fstat(self.fd(), &mut stat) } {
+            0 => Ok(mkstat(&stat)),
+            _ => Err(super::last_error()),
+        }
+    }
+}
+
+impl rtio::RtioPipe for FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        self.inner_read(buf)
+    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.inner_write(buf)
+    }
+    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
+        box FileDesc { inner: self.inner.clone() } as Box<rtio::RtioPipe + Send>
+    }
+
+    // Only supported on named pipes currently. Note that this doesn't have an
+    // impact on the std::io primitives, this is never called via
+    // std::io::PipeStream. If the functionality is exposed in the future, then
+    // these methods will need to be implemented.
+    fn close_read(&mut self) -> IoResult<()> {
+        Err(super::unimpl())
+    }
+    fn close_write(&mut self) -> IoResult<()> {
+        Err(super::unimpl())
+    }
+    fn set_timeout(&mut self, _t: Option<u64>) {}
+    fn set_read_timeout(&mut self, _t: Option<u64>) {}
+    fn set_write_timeout(&mut self, _t: Option<u64>) {}
+}
+
+impl rtio::RtioTTY for FileDesc {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        self.inner_read(buf)
+    }
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        self.inner_write(buf)
+    }
+    fn set_raw(&mut self, _raw: bool) -> IoResult<()> {
+        Err(super::unimpl())
+    }
+    fn get_winsize(&mut self) -> IoResult<(int, int)> {
+        Err(super::unimpl())
+    }
+    fn isatty(&self) -> bool { false }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) {
+        // closing stdio file handles makes no sense, so never do it. Also, note
+        // that errors are ignored when closing a file descriptor. The reason
+        // for this is that if an error occurs we don't actually know if the
+        // file descriptor was closed or not, and if we retried (for something
+        // like EINTR), we might close another valid file descriptor (opened
+        // after we closed ours.
+        if self.close_on_drop && self.fd > libc::STDERR_FILENO {
+            let n = unsafe { libc::close(self.fd) };
+            if n != 0 {
+                println!("error {} when closing file descriptor {}", n, self.fd);
+            }
+        }
+    }
+}
+
+pub fn to_utf16(s: &CString) -> IoResult<Vec<u16>> {
+    match s.as_str() {
+        Some(s) => Ok(s.utf16_units().collect::<Vec<u16>>().append_one(0)),
+        None => Err(IoError {
+            code: libc::ERROR_INVALID_NAME as uint,
+            extra: 0,
+            detail: Some("valid unicode input required".to_string()),
+        })
+    }
+}
+
+pub fn open(path: &CString, fm: rtio::FileMode, fa: rtio::FileAccess)
+        -> IoResult<FileDesc> {
+    // Flags passed to open_osfhandle
+    let flags = match fm {
+        rtio::Open => 0,
+        rtio::Append => libc::O_APPEND,
+        rtio::Truncate => libc::O_TRUNC,
+    };
+    let flags = match fa {
+        rtio::Read => flags | libc::O_RDONLY,
+        rtio::Write => flags | libc::O_WRONLY | libc::O_CREAT,
+        rtio::ReadWrite => flags | libc::O_RDWR | libc::O_CREAT,
+    };
+
+    let mut dwDesiredAccess = match fa {
+        rtio::Read => libc::FILE_GENERIC_READ,
+        rtio::Write => libc::FILE_GENERIC_WRITE,
+        rtio::ReadWrite => libc::FILE_GENERIC_READ | libc::FILE_GENERIC_WRITE
+    };
+
+    // libuv has a good comment about this, but the basic idea is what we try to
+    // emulate unix semantics by enabling all sharing by allowing things such as
+    // deleting a file while it's still open.
+    let dwShareMode = libc::FILE_SHARE_READ | libc::FILE_SHARE_WRITE |
+                      libc::FILE_SHARE_DELETE;
+
+    let dwCreationDisposition = match (fm, fa) {
+        (rtio::Truncate, rtio::Read) => libc::TRUNCATE_EXISTING,
+        (rtio::Truncate, _) => libc::CREATE_ALWAYS,
+        (rtio::Open, rtio::Read) => libc::OPEN_EXISTING,
+        (rtio::Open, _) => libc::OPEN_ALWAYS,
+        (rtio::Append, rtio::Read) => {
+            dwDesiredAccess |= libc::FILE_APPEND_DATA;
+            libc::OPEN_EXISTING
+        }
+        (rtio::Append, _) => {
+            dwDesiredAccess &= !libc::FILE_WRITE_DATA;
+            dwDesiredAccess |= libc::FILE_APPEND_DATA;
+            libc::OPEN_ALWAYS
+        }
+    };
+
+    let mut dwFlagsAndAttributes = libc::FILE_ATTRIBUTE_NORMAL;
+    // Compat with unix, this allows opening directories (see libuv)
+    dwFlagsAndAttributes |= libc::FILE_FLAG_BACKUP_SEMANTICS;
+
+    let path = try!(to_utf16(path));
+    let handle = unsafe {
+        libc::CreateFileW(path.as_ptr(),
+                          dwDesiredAccess,
+                          dwShareMode,
+                          ptr::mut_null(),
+                          dwCreationDisposition,
+                          dwFlagsAndAttributes,
+                          ptr::mut_null())
+    };
+    if handle == libc::INVALID_HANDLE_VALUE {
+        Err(super::last_error())
+    } else {
+        let fd = unsafe {
+            libc::open_osfhandle(handle as libc::intptr_t, flags)
+        };
+        if fd < 0 {
+            let _ = unsafe { libc::CloseHandle(handle) };
+            Err(super::last_error())
+        } else {
+            Ok(FileDesc::new(fd, true))
+        }
+    }
+}
+
+pub fn mkdir(p: &CString, _mode: uint) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    super::mkerr_winbool(unsafe {
+        // FIXME: turn mode into something useful? #2623
+        libc::CreateDirectoryW(p.as_ptr(), ptr::mut_null())
+    })
+}
+
+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);
+
+        dirs.move_iter().filter(|path| {
+            path.as_vec() != b"." && path.as_vec() != b".."
+        }).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);
+        if find_handle != libc::INVALID_HANDLE_VALUE {
+            let mut paths = vec!();
+            let mut more_files = 1 as libc::c_int;
+            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));
+                }
+                more_files = libc::FindNextFileW(find_handle,
+                                                 wfd_ptr as libc::HANDLE);
+            }
+            assert!(libc::FindClose(find_handle) != 0);
+            libc::free(wfd_ptr as *mut c_void);
+            Ok(prune(p, paths))
+        } else {
+            Err(super::last_error())
+        }
+    }
+}
+
+pub fn unlink(p: &CString) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    super::mkerr_winbool(unsafe {
+        libc::DeleteFileW(p.as_ptr())
+    })
+}
+
+pub fn rename(old: &CString, new: &CString) -> IoResult<()> {
+    let old = try!(to_utf16(old));
+    let new = try!(to_utf16(new));
+    super::mkerr_winbool(unsafe {
+        libc::MoveFileExW(old.as_ptr(), new.as_ptr(),
+                          libc::MOVEFILE_REPLACE_EXISTING)
+    })
+}
+
+pub fn chmod(p: &CString, mode: uint) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    super::mkerr_libc(unsafe {
+        libc::wchmod(p.as_ptr(), mode as libc::c_int)
+    })
+}
+
+pub fn rmdir(p: &CString) -> IoResult<()> {
+    let p = try!(to_utf16(p));
+    super::mkerr_libc(unsafe { libc::wrmdir(p.as_ptr()) })
+}
+
+pub fn chown(_p: &CString, _uid: int, _gid: int) -> IoResult<()> {
+    // libuv has this as a no-op, so seems like this should as well?
+    Ok(())
+}
+
+pub fn readlink(p: &CString) -> IoResult<CString> {
+    // FIXME: I have a feeling that this reads intermediate symlinks as well.
+    use io::c::compat::kernel32::GetFinalPathNameByHandleW;
+    let p = try!(to_utf16(p));
+    let handle = unsafe {
+        libc::CreateFileW(p.as_ptr(),
+                          libc::GENERIC_READ,
+                          libc::FILE_SHARE_READ,
+                          ptr::mut_null(),
+                          libc::OPEN_EXISTING,
+                          libc::FILE_ATTRIBUTE_NORMAL,
+                          ptr::mut_null())
+    };
+    if handle == libc::INVALID_HANDLE_VALUE {
+        return Err(super::last_error())
+    }
+    // Specify (sz - 1) because the documentation states that it's the size
+    // without the null pointer
+    let ret = fill_utf16_buf_and_decode(|buf, sz| unsafe {
+        GetFinalPathNameByHandleW(handle,
+                                  buf as *const u16,
+                                  sz - 1,
+                                  libc::VOLUME_NAME_DOS)
+    });
+    let ret = match ret {
+        Some(ref s) if s.as_slice().starts_with(r"\\?\") => {
+            Ok(Path::new(s.as_slice().slice_from(4)).to_c_str())
+        }
+        Some(s) => Ok(Path::new(s).to_c_str()),
+        None => Err(super::last_error()),
+    };
+    assert!(unsafe { libc::CloseHandle(handle) } != 0);
+    return ret;
+}
+
+pub fn symlink(src: &CString, dst: &CString) -> IoResult<()> {
+    use io::c::compat::kernel32::CreateSymbolicLinkW;
+    let src = try!(to_utf16(src));
+    let dst = try!(to_utf16(dst));
+    super::mkerr_winbool(unsafe {
+        CreateSymbolicLinkW(dst.as_ptr(), src.as_ptr(), 0) as libc::BOOL
+    })
+}
+
+pub fn link(src: &CString, dst: &CString) -> IoResult<()> {
+    let src = try!(to_utf16(src));
+    let dst = try!(to_utf16(dst));
+    super::mkerr_winbool(unsafe {
+        libc::CreateHardLinkW(dst.as_ptr(), src.as_ptr(), ptr::mut_null())
+    })
+}
+
+fn mkstat(stat: &libc::stat) -> rtio::FileStat {
+    rtio::FileStat {
+        size: stat.st_size as u64,
+        kind: stat.st_mode as u64,
+        perm: stat.st_mode as u64,
+        created: stat.st_ctime as u64,
+        modified: stat.st_mtime as u64,
+        accessed: stat.st_atime as u64,
+        device: stat.st_dev as u64,
+        inode: stat.st_ino as u64,
+        rdev: stat.st_rdev as u64,
+        nlink: stat.st_nlink as u64,
+        uid: stat.st_uid as u64,
+        gid: stat.st_gid as u64,
+        blksize: 0,
+        blocks: 0,
+        flags: 0,
+        gen: 0,
+    }
+}
+
+pub fn stat(p: &CString) -> IoResult<rtio::FileStat> {
+    let mut stat: libc::stat = unsafe { mem::zeroed() };
+    let p = try!(to_utf16(p));
+    match unsafe { libc::wstat(p.as_ptr(), &mut stat) } {
+        0 => Ok(mkstat(&stat)),
+        _ => Err(super::last_error()),
+    }
+}
+
+pub fn lstat(_p: &CString) -> IoResult<rtio::FileStat> {
+    // FIXME: implementation is missing
+    Err(super::unimpl())
+}
+
+pub fn utime(p: &CString, atime: u64, mtime: u64) -> IoResult<()> {
+    let mut buf = libc::utimbuf {
+        actime: atime as libc::time64_t,
+        modtime: mtime as libc::time64_t,
+    };
+    let p = try!(to_utf16(p));
+    super::mkerr_libc(unsafe {
+        libc::wutime(p.as_ptr(), &mut buf)
+    })
+}
index 5d66100732918695b8a8c8235a2cc1dce07c5175..2dc6539b1780620b904ea408c3a6194a4268bd73 100644 (file)
@@ -46,7 +46,7 @@
 #[path = "file_unix.rs"]
 pub mod file;
 #[cfg(windows)]
-#[path = "file_win32.rs"]
+#[path = "file_windows.rs"]
 pub mod file;
 
 #[cfg(target_os = "macos")]
@@ -59,8 +59,7 @@
 pub mod timer;
 
 #[cfg(target_os = "windows")]
-#[cfg(stage0, target_os = "win32")] // NOTE: Remove after snapshot
-#[path = "timer_win32.rs"]
+#[path = "timer_windows.rs"]
 pub mod timer;
 
 #[cfg(unix)]
 pub mod pipe;
 
 #[cfg(windows)]
-#[path = "pipe_win32.rs"]
+#[path = "pipe_windows.rs"]
 pub mod pipe;
 
 #[cfg(windows)]
-#[path = "tty_win32.rs"]
+#[path = "tty_windows.rs"]
 mod tty;
 
 #[cfg(unix)]    #[path = "c_unix.rs"]  mod c;
-#[cfg(windows)] #[path = "c_win32.rs"] mod c;
+#[cfg(windows)] #[path = "c_windows.rs"] mod c;
 
 fn unimpl() -> IoError {
     #[cfg(unix)] use libc::ENOSYS as ERROR;
diff --git a/src/libnative/io/pipe_win32.rs b/src/libnative/io/pipe_win32.rs
deleted file mode 100644 (file)
index 717915e..0000000
+++ /dev/null
@@ -1,713 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Named pipes implementation for windows
-//!
-//! If are unfortunate enough to be reading this code, I would like to first
-//! apologize. This was my first encounter with windows named pipes, and it
-//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
-//! read on as I'll try to explain some fun things that I ran into.
-//!
-//! # Unix pipes vs Named pipes
-//!
-//! As with everything else, named pipes on windows are pretty different from
-//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
-//! pipes. So long as this server pipe is active, new children pipes can
-//! connect. On windows, you instead have a number of "server pipes", and each
-//! of these server pipes can throughout their lifetime be attached to a client
-//! or not. Once attached to a client, a server pipe may then disconnect at a
-//! later date.
-//!
-//! # Accepting clients
-//!
-//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
-//! are built around the unix flavors. This means that we have one "server
-//! pipe" to which many clients can connect. In order to make this compatible
-//! with the windows model, each connected client consumes ownership of a server
-//! pipe, and then a new server pipe is created for the next client.
-//!
-//! Note that the server pipes attached to clients are never given back to the
-//! listener for recycling. This could possibly be implemented with a channel so
-//! the listener half can re-use server pipes, but for now I err'd on the simple
-//! side of things. Each stream accepted by a listener will destroy the server
-//! pipe after the stream is dropped.
-//!
-//! This model ends up having a small race or two, and you can find more details
-//! on the `native_accept` method.
-//!
-//! # Simultaneous reads and writes
-//!
-//! In testing, I found that two simultaneous writes and two simultaneous reads
-//! on a pipe ended up working out just fine, but problems were encountered when
-//! a read was executed simultaneously with a write. After some googling around,
-//! it sounded like named pipes just weren't built for this kind of interaction,
-//! and the suggested solution was to use overlapped I/O.
-//!
-//! I don't really know what overlapped I/O is, but my basic understanding after
-//! reading about it is that you have an external Event which is used to signal
-//! I/O completion, passed around in some OVERLAPPED structures. As to what this
-//! is, I'm not exactly sure.
-//!
-//! This problem implies that all named pipes are created with the
-//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
-//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
-//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
-//! determined to be pending (may complete in the future), the
-//! GetOverlappedResult function is used to block on the event, waiting for the
-//! I/O to finish.
-//!
-//! This scheme ended up working well enough. There were two snags that I ran
-//! into, however:
-//!
-//! * Each UnixStream instance needs its own read/write events to wait on. These
-//!   can't be shared among clones of the same stream because the documentation
-//!   states that it unsets the event when the I/O is started (would possibly
-//!   corrupt other events simultaneously waiting). For convenience's sake,
-//!   these events are lazily initialized.
-//!
-//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
-//!   to all pipes created through `connect`. Notably this means that the
-//!   ConnectNamedPipe function is nonblocking, implying that the Listener needs
-//!   to have yet another event to do the actual blocking.
-//!
-//! # Conclusion
-//!
-//! The conclusion here is that I probably don't know the best way to work with
-//! windows named pipes, but the solution here seems to work well enough to get
-//! the test suite passing (the suite is in libstd), and that's good enough for
-//! me!
-
-use alloc::arc::Arc;
-use libc;
-use std::c_str::CString;
-use std::mem;
-use std::os;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::{IoResult, IoError};
-use std::sync::atomic;
-use std::rt::mutex;
-
-use super::c;
-use super::util;
-use super::file::to_utf16;
-
-struct Event(libc::HANDLE);
-
-impl Event {
-    fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
-        let event = unsafe {
-            libc::CreateEventW(ptr::mut_null(),
-                               manual_reset as libc::BOOL,
-                               initial_state as libc::BOOL,
-                               ptr::null())
-        };
-        if event as uint == 0 {
-            Err(super::last_error())
-        } else {
-            Ok(Event(event))
-        }
-    }
-
-    fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
-}
-
-impl Drop for Event {
-    fn drop(&mut self) {
-        unsafe { let _ = libc::CloseHandle(self.handle()); }
-    }
-}
-
-struct Inner {
-    handle: libc::HANDLE,
-    lock: mutex::NativeMutex,
-    read_closed: atomic::AtomicBool,
-    write_closed: atomic::AtomicBool,
-}
-
-impl Inner {
-    fn new(handle: libc::HANDLE) -> Inner {
-        Inner {
-            handle: handle,
-            lock: unsafe { mutex::NativeMutex::new() },
-            read_closed: atomic::AtomicBool::new(false),
-            write_closed: atomic::AtomicBool::new(false),
-        }
-    }
-}
-
-impl Drop for Inner {
-    fn drop(&mut self) {
-        unsafe {
-            let _ = libc::FlushFileBuffers(self.handle);
-            let _ = libc::CloseHandle(self.handle);
-        }
-    }
-}
-
-unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE {
-    libc::CreateNamedPipeW(
-        name,
-        libc::PIPE_ACCESS_DUPLEX |
-            if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
-            libc::FILE_FLAG_OVERLAPPED,
-        libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
-            libc::PIPE_WAIT,
-        libc::PIPE_UNLIMITED_INSTANCES,
-        65536,
-        65536,
-        0,
-        ptr::mut_null()
-    )
-}
-
-pub fn await(handle: libc::HANDLE, deadline: u64,
-             overlapped: &mut libc::OVERLAPPED) -> bool {
-    if deadline == 0 { return true }
-
-    // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
-    // to figure out if we should indeed get the result.
-    let now = ::io::timer::now();
-    let timeout = deadline < now || unsafe {
-        let ms = (deadline - now) as libc::DWORD;
-        let r = libc::WaitForSingleObject(overlapped.hEvent,
-                                          ms);
-        r != libc::WAIT_OBJECT_0
-    };
-    if timeout {
-        unsafe { let _ = c::CancelIo(handle); }
-        false
-    } else {
-        true
-    }
-}
-
-fn epipe() -> IoError {
-    IoError {
-        code: libc::ERROR_BROKEN_PIPE as uint,
-        extra: 0,
-        detail: None,
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Unix Streams
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct UnixStream {
-    inner: Arc<Inner>,
-    write: Option<Event>,
-    read: Option<Event>,
-    read_deadline: u64,
-    write_deadline: u64,
-}
-
-impl UnixStream {
-    fn try_connect(p: *const u16) -> Option<libc::HANDLE> {
-        // Note that most of this is lifted from the libuv implementation.
-        // The idea is that if we fail to open a pipe in read/write mode
-        // that we try afterwards in just read or just write
-        let mut result = unsafe {
-            libc::CreateFileW(p,
-                libc::GENERIC_READ | libc::GENERIC_WRITE,
-                0,
-                ptr::mut_null(),
-                libc::OPEN_EXISTING,
-                libc::FILE_FLAG_OVERLAPPED,
-                ptr::mut_null())
-        };
-        if result != libc::INVALID_HANDLE_VALUE {
-            return Some(result)
-        }
-
-        let err = unsafe { libc::GetLastError() };
-        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
-            result = unsafe {
-                libc::CreateFileW(p,
-                    libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
-                    0,
-                    ptr::mut_null(),
-                    libc::OPEN_EXISTING,
-                    libc::FILE_FLAG_OVERLAPPED,
-                    ptr::mut_null())
-            };
-            if result != libc::INVALID_HANDLE_VALUE {
-                return Some(result)
-            }
-        }
-        let err = unsafe { libc::GetLastError() };
-        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
-            result = unsafe {
-                libc::CreateFileW(p,
-                    libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
-                    0,
-                    ptr::mut_null(),
-                    libc::OPEN_EXISTING,
-                    libc::FILE_FLAG_OVERLAPPED,
-                    ptr::mut_null())
-            };
-            if result != libc::INVALID_HANDLE_VALUE {
-                return Some(result)
-            }
-        }
-        None
-    }
-
-    pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> {
-        let addr = try!(to_utf16(addr));
-        let start = ::io::timer::now();
-        loop {
-            match UnixStream::try_connect(addr.as_ptr()) {
-                Some(handle) => {
-                    let inner = Inner::new(handle);
-                    let mut mode = libc::PIPE_TYPE_BYTE |
-                                   libc::PIPE_READMODE_BYTE |
-                                   libc::PIPE_WAIT;
-                    let ret = unsafe {
-                        libc::SetNamedPipeHandleState(inner.handle,
-                                                      &mut mode,
-                                                      ptr::mut_null(),
-                                                      ptr::mut_null())
-                    };
-                    return if ret == 0 {
-                        Err(super::last_error())
-                    } else {
-                        Ok(UnixStream {
-                            inner: Arc::new(inner),
-                            read: None,
-                            write: None,
-                            read_deadline: 0,
-                            write_deadline: 0,
-                        })
-                    }
-                }
-                None => {}
-            }
-
-            // On windows, if you fail to connect, you may need to call the
-            // `WaitNamedPipe` function, and this is indicated with an error
-            // code of ERROR_PIPE_BUSY.
-            let code = unsafe { libc::GetLastError() };
-            if code as int != libc::ERROR_PIPE_BUSY as int {
-                return Err(super::last_error())
-            }
-
-            match timeout {
-                Some(timeout) => {
-                    let now = ::io::timer::now();
-                    let timed_out = (now - start) >= timeout || unsafe {
-                        let ms = (timeout - (now - start)) as libc::DWORD;
-                        libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0
-                    };
-                    if timed_out {
-                        return Err(util::timeout("connect timed out"))
-                    }
-                }
-
-                // An example I found on Microsoft's website used 20
-                // seconds, libuv uses 30 seconds, hence we make the
-                // obvious choice of waiting for 25 seconds.
-                None => {
-                    if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 {
-                        return Err(super::last_error())
-                    }
-                }
-            }
-        }
-    }
-
-    fn handle(&self) -> libc::HANDLE { self.inner.handle }
-
-    fn read_closed(&self) -> bool {
-        self.inner.read_closed.load(atomic::SeqCst)
-    }
-
-    fn write_closed(&self) -> bool {
-        self.inner.write_closed.load(atomic::SeqCst)
-    }
-
-    fn cancel_io(&self) -> IoResult<()> {
-        match unsafe { c::CancelIoEx(self.handle(), ptr::mut_null()) } {
-            0 if os::errno() == libc::ERROR_NOT_FOUND as uint => {
-                Ok(())
-            }
-            0 => Err(super::last_error()),
-            _ => Ok(())
-        }
-    }
-}
-
-impl rtio::RtioPipe for UnixStream {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        if self.read.is_none() {
-            self.read = Some(try!(Event::new(true, false)));
-        }
-
-        let mut bytes_read = 0;
-        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        overlapped.hEvent = self.read.get_ref().handle();
-
-        // Pre-flight check to see if the reading half has been closed. This
-        // must be done before issuing the ReadFile request, but after we
-        // acquire the lock.
-        //
-        // See comments in close_read() about why this lock is necessary.
-        let guard = unsafe { self.inner.lock.lock() };
-        if self.read_closed() {
-            return Err(util::eof())
-        }
-
-        // Issue a nonblocking requests, succeeding quickly if it happened to
-        // succeed.
-        let ret = unsafe {
-            libc::ReadFile(self.handle(),
-                           buf.as_ptr() as libc::LPVOID,
-                           buf.len() as libc::DWORD,
-                           &mut bytes_read,
-                           &mut overlapped)
-        };
-        if ret != 0 { return Ok(bytes_read as uint) }
-
-        // If our errno doesn't say that the I/O is pending, then we hit some
-        // legitimate error and return immediately.
-        if os::errno() != libc::ERROR_IO_PENDING as uint {
-            return Err(super::last_error())
-        }
-
-        // Now that we've issued a successful nonblocking request, we need to
-        // wait for it to finish. This can all be done outside the lock because
-        // we'll see any invocation of CancelIoEx. We also call this in a loop
-        // because we're woken up if the writing half is closed, we just need to
-        // realize that the reading half wasn't closed and we go right back to
-        // sleep.
-        drop(guard);
-        loop {
-            // Process a timeout if one is pending
-            let succeeded = await(self.handle(), self.read_deadline,
-                                  &mut overlapped);
-
-            let ret = unsafe {
-                libc::GetOverlappedResult(self.handle(),
-                                          &mut overlapped,
-                                          &mut bytes_read,
-                                          libc::TRUE)
-            };
-            // If we succeeded, or we failed for some reason other than
-            // CancelIoEx, return immediately
-            if ret != 0 { return Ok(bytes_read as uint) }
-            if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
-                return Err(super::last_error())
-            }
-
-            // If the reading half is now closed, then we're done. If we woke up
-            // because the writing half was closed, keep trying.
-            if !succeeded {
-                return Err(util::timeout("read timed out"))
-            }
-            if self.read_closed() {
-                return Err(util::eof())
-            }
-        }
-    }
-
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        if self.write.is_none() {
-            self.write = Some(try!(Event::new(true, false)));
-        }
-
-        let mut offset = 0;
-        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        overlapped.hEvent = self.write.get_ref().handle();
-
-        while offset < buf.len() {
-            let mut bytes_written = 0;
-
-            // This sequence below is quite similar to the one found in read().
-            // Some careful looping is done to ensure that if close_write() is
-            // invoked we bail out early, and if close_read() is invoked we keep
-            // going after we woke up.
-            //
-            // See comments in close_read() about why this lock is necessary.
-            let guard = unsafe { self.inner.lock.lock() };
-            if self.write_closed() {
-                return Err(epipe())
-            }
-            let ret = unsafe {
-                libc::WriteFile(self.handle(),
-                                buf.slice_from(offset).as_ptr() as libc::LPVOID,
-                                (buf.len() - offset) as libc::DWORD,
-                                &mut bytes_written,
-                                &mut overlapped)
-            };
-            let err = os::errno();
-            drop(guard);
-
-            if ret == 0 {
-                if err != libc::ERROR_IO_PENDING as uint {
-                    return Err(IoError {
-                        code: err as uint,
-                        extra: 0,
-                        detail: Some(os::error_string(err as uint)),
-                    })
-                }
-                // Process a timeout if one is pending
-                let succeeded = await(self.handle(), self.write_deadline,
-                                      &mut overlapped);
-                let ret = unsafe {
-                    libc::GetOverlappedResult(self.handle(),
-                                              &mut overlapped,
-                                              &mut bytes_written,
-                                              libc::TRUE)
-                };
-                // If we weren't aborted, this was a legit error, if we were
-                // aborted, then check to see if the write half was actually
-                // closed or whether we woke up from the read half closing.
-                if ret == 0 {
-                    if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
-                        return Err(super::last_error())
-                    }
-                    if !succeeded {
-                        let amt = offset + bytes_written as uint;
-                        return if amt > 0 {
-                            Err(IoError {
-                                code: libc::ERROR_OPERATION_ABORTED as uint,
-                                extra: amt,
-                                detail: Some("short write during write".to_string()),
-                            })
-                        } else {
-                            Err(util::timeout("write timed out"))
-                        }
-                    }
-                    if self.write_closed() {
-                        return Err(epipe())
-                    }
-                    continue // retry
-                }
-            }
-            offset += bytes_written as uint;
-        }
-        Ok(())
-    }
-
-    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
-        box UnixStream {
-            inner: self.inner.clone(),
-            read: None,
-            write: None,
-            read_deadline: 0,
-            write_deadline: 0,
-        } as Box<rtio::RtioPipe + Send>
-    }
-
-    fn close_read(&mut self) -> IoResult<()> {
-        // On windows, there's no actual shutdown() method for pipes, so we're
-        // forced to emulate the behavior manually at the application level. To
-        // do this, we need to both cancel any pending requests, as well as
-        // prevent all future requests from succeeding. These two operations are
-        // not atomic with respect to one another, so we must use a lock to do
-        // so.
-        //
-        // The read() code looks like:
-        //
-        //      1. Make sure the pipe is still open
-        //      2. Submit a read request
-        //      3. Wait for the read request to finish
-        //
-        // The race this lock is preventing is if another thread invokes
-        // close_read() between steps 1 and 2. By atomically executing steps 1
-        // and 2 with a lock with respect to close_read(), we're guaranteed that
-        // no thread will erroneously sit in a read forever.
-        let _guard = unsafe { self.inner.lock.lock() };
-        self.inner.read_closed.store(true, atomic::SeqCst);
-        self.cancel_io()
-    }
-
-    fn close_write(&mut self) -> IoResult<()> {
-        // see comments in close_read() for why this lock is necessary
-        let _guard = unsafe { self.inner.lock.lock() };
-        self.inner.write_closed.store(true, atomic::SeqCst);
-        self.cancel_io()
-    }
-
-    fn set_timeout(&mut self, timeout: Option<u64>) {
-        let deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
-        self.read_deadline = deadline;
-        self.write_deadline = deadline;
-    }
-    fn set_read_timeout(&mut self, timeout: Option<u64>) {
-        self.read_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
-    }
-    fn set_write_timeout(&mut self, timeout: Option<u64>) {
-        self.write_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
-    }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// Unix Listener
-////////////////////////////////////////////////////////////////////////////////
-
-pub struct UnixListener {
-    handle: libc::HANDLE,
-    name: CString,
-}
-
-impl UnixListener {
-    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
-        // Although we technically don't need the pipe until much later, we
-        // create the initial handle up front to test the validity of the name
-        // and such.
-        let addr_v = try!(to_utf16(addr));
-        let ret = unsafe { pipe(addr_v.as_ptr(), true) };
-        if ret == libc::INVALID_HANDLE_VALUE {
-            Err(super::last_error())
-        } else {
-            Ok(UnixListener { handle: ret, name: addr.clone() })
-        }
-    }
-
-    pub fn native_listen(self) -> IoResult<UnixAcceptor> {
-        Ok(UnixAcceptor {
-            listener: self,
-            event: try!(Event::new(true, false)),
-            deadline: 0,
-        })
-    }
-}
-
-impl Drop for UnixListener {
-    fn drop(&mut self) {
-        unsafe { let _ = libc::CloseHandle(self.handle); }
-    }
-}
-
-impl rtio::RtioUnixListener for UnixListener {
-    fn listen(self: Box<UnixListener>)
-              -> IoResult<Box<rtio::RtioUnixAcceptor + Send>> {
-        self.native_listen().map(|a| {
-            box a as Box<rtio::RtioUnixAcceptor + Send>
-        })
-    }
-}
-
-pub struct UnixAcceptor {
-    listener: UnixListener,
-    event: Event,
-    deadline: u64,
-}
-
-impl UnixAcceptor {
-    pub fn native_accept(&mut self) -> IoResult<UnixStream> {
-        // This function has some funky implementation details when working with
-        // unix pipes. On windows, each server named pipe handle can be
-        // connected to a one or zero clients. To the best of my knowledge, a
-        // named server is considered active and present if there exists at
-        // least one server named pipe for it.
-        //
-        // The model of this function is to take the current known server
-        // handle, connect a client to it, and then transfer ownership to the
-        // UnixStream instance. The next time accept() is invoked, it'll need a
-        // different server handle to connect a client to.
-        //
-        // Note that there is a possible race here. Once our server pipe is
-        // handed off to a `UnixStream` object, the stream could be closed,
-        // meaning that there would be no active server pipes, hence even though
-        // we have a valid `UnixAcceptor`, no one can connect to it. For this
-        // reason, we generate the next accept call's server pipe at the end of
-        // this function call.
-        //
-        // This provides us an invariant that we always have at least one server
-        // connection open at a time, meaning that all connects to this acceptor
-        // should succeed while this is active.
-        //
-        // The actual implementation of doing this is a little tricky. Once a
-        // server pipe is created, a client can connect to it at any time. I
-        // assume that which server a client connects to is nondeterministic, so
-        // we also need to guarantee that the only server able to be connected
-        // to is the one that we're calling ConnectNamedPipe on. This means that
-        // we have to create the second server pipe *after* we've already
-        // accepted a connection. In order to at least somewhat gracefully
-        // handle errors, this means that if the second server pipe creation
-        // fails that we disconnect the connected client and then just keep
-        // using the original server pipe.
-        let handle = self.listener.handle;
-
-        let name = try!(to_utf16(&self.listener.name));
-
-        // Once we've got a "server handle", we need to wait for a client to
-        // connect. The ConnectNamedPipe function will block this thread until
-        // someone on the other end connects. This function can "fail" if a
-        // client connects after we created the pipe but before we got down
-        // here. Thanks windows.
-        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
-        overlapped.hEvent = self.event.handle();
-        if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
-            let mut err = unsafe { libc::GetLastError() };
-
-            if err == libc::ERROR_IO_PENDING as libc::DWORD {
-                // Process a timeout if one is pending
-                let _ = await(handle, self.deadline, &mut overlapped);
-
-                // This will block until the overlapped I/O is completed. The
-                // timeout was previously handled, so this will either block in
-                // the normal case or succeed very quickly in the timeout case.
-                let ret = unsafe {
-                    let mut transfer = 0;
-                    libc::GetOverlappedResult(handle,
-                                              &mut overlapped,
-                                              &mut transfer,
-                                              libc::TRUE)
-                };
-                if ret == 0 {
-                    err = unsafe { libc::GetLastError() };
-                } else {
-                    // we succeeded, bypass the check below
-                    err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
-                }
-            }
-            if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
-                return Err(super::last_error())
-            }
-        }
-
-        // Now that we've got a connected client to our handle, we need to
-        // create a second server pipe. If this fails, we disconnect the
-        // connected client and return an error (see comments above).
-        let new_handle = unsafe { pipe(name.as_ptr(), false) };
-        if new_handle == libc::INVALID_HANDLE_VALUE {
-            let ret = Err(super::last_error());
-            // If our disconnection fails, then there's not really a whole lot
-            // that we can do, so fail the task.
-            let err = unsafe { libc::DisconnectNamedPipe(handle) };
-            assert!(err != 0);
-            return ret;
-        } else {
-            self.listener.handle = new_handle;
-        }
-
-        // Transfer ownership of our handle into this stream
-        Ok(UnixStream {
-            inner: Arc::new(Inner::new(handle)),
-            read: None,
-            write: None,
-            read_deadline: 0,
-            write_deadline: 0,
-        })
-    }
-}
-
-impl rtio::RtioUnixAcceptor for UnixAcceptor {
-    fn accept(&mut self) -> IoResult<Box<rtio::RtioPipe + Send>> {
-        self.native_accept().map(|s| box s as Box<rtio::RtioPipe + Send>)
-    }
-    fn set_timeout(&mut self, timeout: Option<u64>) {
-        self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0);
-    }
-}
-
diff --git a/src/libnative/io/pipe_windows.rs b/src/libnative/io/pipe_windows.rs
new file mode 100644 (file)
index 0000000..717915e
--- /dev/null
@@ -0,0 +1,713 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Named pipes implementation for windows
+//!
+//! If are unfortunate enough to be reading this code, I would like to first
+//! apologize. This was my first encounter with windows named pipes, and it
+//! didn't exactly turn out very cleanly. If you, too, are new to named pipes,
+//! read on as I'll try to explain some fun things that I ran into.
+//!
+//! # Unix pipes vs Named pipes
+//!
+//! As with everything else, named pipes on windows are pretty different from
+//! unix pipes on unix. On unix, you use one "server pipe" to accept new client
+//! pipes. So long as this server pipe is active, new children pipes can
+//! connect. On windows, you instead have a number of "server pipes", and each
+//! of these server pipes can throughout their lifetime be attached to a client
+//! or not. Once attached to a client, a server pipe may then disconnect at a
+//! later date.
+//!
+//! # Accepting clients
+//!
+//! As with most other I/O interfaces, our Listener/Acceptor/Stream interfaces
+//! are built around the unix flavors. This means that we have one "server
+//! pipe" to which many clients can connect. In order to make this compatible
+//! with the windows model, each connected client consumes ownership of a server
+//! pipe, and then a new server pipe is created for the next client.
+//!
+//! Note that the server pipes attached to clients are never given back to the
+//! listener for recycling. This could possibly be implemented with a channel so
+//! the listener half can re-use server pipes, but for now I err'd on the simple
+//! side of things. Each stream accepted by a listener will destroy the server
+//! pipe after the stream is dropped.
+//!
+//! This model ends up having a small race or two, and you can find more details
+//! on the `native_accept` method.
+//!
+//! # Simultaneous reads and writes
+//!
+//! In testing, I found that two simultaneous writes and two simultaneous reads
+//! on a pipe ended up working out just fine, but problems were encountered when
+//! a read was executed simultaneously with a write. After some googling around,
+//! it sounded like named pipes just weren't built for this kind of interaction,
+//! and the suggested solution was to use overlapped I/O.
+//!
+//! I don't really know what overlapped I/O is, but my basic understanding after
+//! reading about it is that you have an external Event which is used to signal
+//! I/O completion, passed around in some OVERLAPPED structures. As to what this
+//! is, I'm not exactly sure.
+//!
+//! This problem implies that all named pipes are created with the
+//! FILE_FLAG_OVERLAPPED option. This means that all of their I/O is
+//! asynchronous. Each I/O operation has an associated OVERLAPPED structure, and
+//! inside of this structure is a HANDLE from CreateEvent. After the I/O is
+//! determined to be pending (may complete in the future), the
+//! GetOverlappedResult function is used to block on the event, waiting for the
+//! I/O to finish.
+//!
+//! This scheme ended up working well enough. There were two snags that I ran
+//! into, however:
+//!
+//! * Each UnixStream instance needs its own read/write events to wait on. These
+//!   can't be shared among clones of the same stream because the documentation
+//!   states that it unsets the event when the I/O is started (would possibly
+//!   corrupt other events simultaneously waiting). For convenience's sake,
+//!   these events are lazily initialized.
+//!
+//! * Each server pipe needs to be created with FILE_FLAG_OVERLAPPED in addition
+//!   to all pipes created through `connect`. Notably this means that the
+//!   ConnectNamedPipe function is nonblocking, implying that the Listener needs
+//!   to have yet another event to do the actual blocking.
+//!
+//! # Conclusion
+//!
+//! The conclusion here is that I probably don't know the best way to work with
+//! windows named pipes, but the solution here seems to work well enough to get
+//! the test suite passing (the suite is in libstd), and that's good enough for
+//! me!
+
+use alloc::arc::Arc;
+use libc;
+use std::c_str::CString;
+use std::mem;
+use std::os;
+use std::ptr;
+use std::rt::rtio;
+use std::rt::rtio::{IoResult, IoError};
+use std::sync::atomic;
+use std::rt::mutex;
+
+use super::c;
+use super::util;
+use super::file::to_utf16;
+
+struct Event(libc::HANDLE);
+
+impl Event {
+    fn new(manual_reset: bool, initial_state: bool) -> IoResult<Event> {
+        let event = unsafe {
+            libc::CreateEventW(ptr::mut_null(),
+                               manual_reset as libc::BOOL,
+                               initial_state as libc::BOOL,
+                               ptr::null())
+        };
+        if event as uint == 0 {
+            Err(super::last_error())
+        } else {
+            Ok(Event(event))
+        }
+    }
+
+    fn handle(&self) -> libc::HANDLE { let Event(handle) = *self; handle }
+}
+
+impl Drop for Event {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle()); }
+    }
+}
+
+struct Inner {
+    handle: libc::HANDLE,
+    lock: mutex::NativeMutex,
+    read_closed: atomic::AtomicBool,
+    write_closed: atomic::AtomicBool,
+}
+
+impl Inner {
+    fn new(handle: libc::HANDLE) -> Inner {
+        Inner {
+            handle: handle,
+            lock: unsafe { mutex::NativeMutex::new() },
+            read_closed: atomic::AtomicBool::new(false),
+            write_closed: atomic::AtomicBool::new(false),
+        }
+    }
+}
+
+impl Drop for Inner {
+    fn drop(&mut self) {
+        unsafe {
+            let _ = libc::FlushFileBuffers(self.handle);
+            let _ = libc::CloseHandle(self.handle);
+        }
+    }
+}
+
+unsafe fn pipe(name: *const u16, init: bool) -> libc::HANDLE {
+    libc::CreateNamedPipeW(
+        name,
+        libc::PIPE_ACCESS_DUPLEX |
+            if init {libc::FILE_FLAG_FIRST_PIPE_INSTANCE} else {0} |
+            libc::FILE_FLAG_OVERLAPPED,
+        libc::PIPE_TYPE_BYTE | libc::PIPE_READMODE_BYTE |
+            libc::PIPE_WAIT,
+        libc::PIPE_UNLIMITED_INSTANCES,
+        65536,
+        65536,
+        0,
+        ptr::mut_null()
+    )
+}
+
+pub fn await(handle: libc::HANDLE, deadline: u64,
+             overlapped: &mut libc::OVERLAPPED) -> bool {
+    if deadline == 0 { return true }
+
+    // If we've got a timeout, use WaitForSingleObject in tandem with CancelIo
+    // to figure out if we should indeed get the result.
+    let now = ::io::timer::now();
+    let timeout = deadline < now || unsafe {
+        let ms = (deadline - now) as libc::DWORD;
+        let r = libc::WaitForSingleObject(overlapped.hEvent,
+                                          ms);
+        r != libc::WAIT_OBJECT_0
+    };
+    if timeout {
+        unsafe { let _ = c::CancelIo(handle); }
+        false
+    } else {
+        true
+    }
+}
+
+fn epipe() -> IoError {
+    IoError {
+        code: libc::ERROR_BROKEN_PIPE as uint,
+        extra: 0,
+        detail: None,
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Streams
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixStream {
+    inner: Arc<Inner>,
+    write: Option<Event>,
+    read: Option<Event>,
+    read_deadline: u64,
+    write_deadline: u64,
+}
+
+impl UnixStream {
+    fn try_connect(p: *const u16) -> Option<libc::HANDLE> {
+        // Note that most of this is lifted from the libuv implementation.
+        // The idea is that if we fail to open a pipe in read/write mode
+        // that we try afterwards in just read or just write
+        let mut result = unsafe {
+            libc::CreateFileW(p,
+                libc::GENERIC_READ | libc::GENERIC_WRITE,
+                0,
+                ptr::mut_null(),
+                libc::OPEN_EXISTING,
+                libc::FILE_FLAG_OVERLAPPED,
+                ptr::mut_null())
+        };
+        if result != libc::INVALID_HANDLE_VALUE {
+            return Some(result)
+        }
+
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_READ | libc::FILE_WRITE_ATTRIBUTES,
+                    0,
+                    ptr::mut_null(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::mut_null())
+            };
+            if result != libc::INVALID_HANDLE_VALUE {
+                return Some(result)
+            }
+        }
+        let err = unsafe { libc::GetLastError() };
+        if err == libc::ERROR_ACCESS_DENIED as libc::DWORD {
+            result = unsafe {
+                libc::CreateFileW(p,
+                    libc::GENERIC_WRITE | libc::FILE_READ_ATTRIBUTES,
+                    0,
+                    ptr::mut_null(),
+                    libc::OPEN_EXISTING,
+                    libc::FILE_FLAG_OVERLAPPED,
+                    ptr::mut_null())
+            };
+            if result != libc::INVALID_HANDLE_VALUE {
+                return Some(result)
+            }
+        }
+        None
+    }
+
+    pub fn connect(addr: &CString, timeout: Option<u64>) -> IoResult<UnixStream> {
+        let addr = try!(to_utf16(addr));
+        let start = ::io::timer::now();
+        loop {
+            match UnixStream::try_connect(addr.as_ptr()) {
+                Some(handle) => {
+                    let inner = Inner::new(handle);
+                    let mut mode = libc::PIPE_TYPE_BYTE |
+                                   libc::PIPE_READMODE_BYTE |
+                                   libc::PIPE_WAIT;
+                    let ret = unsafe {
+                        libc::SetNamedPipeHandleState(inner.handle,
+                                                      &mut mode,
+                                                      ptr::mut_null(),
+                                                      ptr::mut_null())
+                    };
+                    return if ret == 0 {
+                        Err(super::last_error())
+                    } else {
+                        Ok(UnixStream {
+                            inner: Arc::new(inner),
+                            read: None,
+                            write: None,
+                            read_deadline: 0,
+                            write_deadline: 0,
+                        })
+                    }
+                }
+                None => {}
+            }
+
+            // On windows, if you fail to connect, you may need to call the
+            // `WaitNamedPipe` function, and this is indicated with an error
+            // code of ERROR_PIPE_BUSY.
+            let code = unsafe { libc::GetLastError() };
+            if code as int != libc::ERROR_PIPE_BUSY as int {
+                return Err(super::last_error())
+            }
+
+            match timeout {
+                Some(timeout) => {
+                    let now = ::io::timer::now();
+                    let timed_out = (now - start) >= timeout || unsafe {
+                        let ms = (timeout - (now - start)) as libc::DWORD;
+                        libc::WaitNamedPipeW(addr.as_ptr(), ms) == 0
+                    };
+                    if timed_out {
+                        return Err(util::timeout("connect timed out"))
+                    }
+                }
+
+                // An example I found on Microsoft's website used 20
+                // seconds, libuv uses 30 seconds, hence we make the
+                // obvious choice of waiting for 25 seconds.
+                None => {
+                    if unsafe { libc::WaitNamedPipeW(addr.as_ptr(), 25000) } == 0 {
+                        return Err(super::last_error())
+                    }
+                }
+            }
+        }
+    }
+
+    fn handle(&self) -> libc::HANDLE { self.inner.handle }
+
+    fn read_closed(&self) -> bool {
+        self.inner.read_closed.load(atomic::SeqCst)
+    }
+
+    fn write_closed(&self) -> bool {
+        self.inner.write_closed.load(atomic::SeqCst)
+    }
+
+    fn cancel_io(&self) -> IoResult<()> {
+        match unsafe { c::CancelIoEx(self.handle(), ptr::mut_null()) } {
+            0 if os::errno() == libc::ERROR_NOT_FOUND as uint => {
+                Ok(())
+            }
+            0 => Err(super::last_error()),
+            _ => Ok(())
+        }
+    }
+}
+
+impl rtio::RtioPipe for UnixStream {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        if self.read.is_none() {
+            self.read = Some(try!(Event::new(true, false)));
+        }
+
+        let mut bytes_read = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.read.get_ref().handle();
+
+        // Pre-flight check to see if the reading half has been closed. This
+        // must be done before issuing the ReadFile request, but after we
+        // acquire the lock.
+        //
+        // See comments in close_read() about why this lock is necessary.
+        let guard = unsafe { self.inner.lock.lock() };
+        if self.read_closed() {
+            return Err(util::eof())
+        }
+
+        // Issue a nonblocking requests, succeeding quickly if it happened to
+        // succeed.
+        let ret = unsafe {
+            libc::ReadFile(self.handle(),
+                           buf.as_ptr() as libc::LPVOID,
+                           buf.len() as libc::DWORD,
+                           &mut bytes_read,
+                           &mut overlapped)
+        };
+        if ret != 0 { return Ok(bytes_read as uint) }
+
+        // If our errno doesn't say that the I/O is pending, then we hit some
+        // legitimate error and return immediately.
+        if os::errno() != libc::ERROR_IO_PENDING as uint {
+            return Err(super::last_error())
+        }
+
+        // Now that we've issued a successful nonblocking request, we need to
+        // wait for it to finish. This can all be done outside the lock because
+        // we'll see any invocation of CancelIoEx. We also call this in a loop
+        // because we're woken up if the writing half is closed, we just need to
+        // realize that the reading half wasn't closed and we go right back to
+        // sleep.
+        drop(guard);
+        loop {
+            // Process a timeout if one is pending
+            let succeeded = await(self.handle(), self.read_deadline,
+                                  &mut overlapped);
+
+            let ret = unsafe {
+                libc::GetOverlappedResult(self.handle(),
+                                          &mut overlapped,
+                                          &mut bytes_read,
+                                          libc::TRUE)
+            };
+            // If we succeeded, or we failed for some reason other than
+            // CancelIoEx, return immediately
+            if ret != 0 { return Ok(bytes_read as uint) }
+            if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+                return Err(super::last_error())
+            }
+
+            // If the reading half is now closed, then we're done. If we woke up
+            // because the writing half was closed, keep trying.
+            if !succeeded {
+                return Err(util::timeout("read timed out"))
+            }
+            if self.read_closed() {
+                return Err(util::eof())
+            }
+        }
+    }
+
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        if self.write.is_none() {
+            self.write = Some(try!(Event::new(true, false)));
+        }
+
+        let mut offset = 0;
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.write.get_ref().handle();
+
+        while offset < buf.len() {
+            let mut bytes_written = 0;
+
+            // This sequence below is quite similar to the one found in read().
+            // Some careful looping is done to ensure that if close_write() is
+            // invoked we bail out early, and if close_read() is invoked we keep
+            // going after we woke up.
+            //
+            // See comments in close_read() about why this lock is necessary.
+            let guard = unsafe { self.inner.lock.lock() };
+            if self.write_closed() {
+                return Err(epipe())
+            }
+            let ret = unsafe {
+                libc::WriteFile(self.handle(),
+                                buf.slice_from(offset).as_ptr() as libc::LPVOID,
+                                (buf.len() - offset) as libc::DWORD,
+                                &mut bytes_written,
+                                &mut overlapped)
+            };
+            let err = os::errno();
+            drop(guard);
+
+            if ret == 0 {
+                if err != libc::ERROR_IO_PENDING as uint {
+                    return Err(IoError {
+                        code: err as uint,
+                        extra: 0,
+                        detail: Some(os::error_string(err as uint)),
+                    })
+                }
+                // Process a timeout if one is pending
+                let succeeded = await(self.handle(), self.write_deadline,
+                                      &mut overlapped);
+                let ret = unsafe {
+                    libc::GetOverlappedResult(self.handle(),
+                                              &mut overlapped,
+                                              &mut bytes_written,
+                                              libc::TRUE)
+                };
+                // If we weren't aborted, this was a legit error, if we were
+                // aborted, then check to see if the write half was actually
+                // closed or whether we woke up from the read half closing.
+                if ret == 0 {
+                    if os::errno() != libc::ERROR_OPERATION_ABORTED as uint {
+                        return Err(super::last_error())
+                    }
+                    if !succeeded {
+                        let amt = offset + bytes_written as uint;
+                        return if amt > 0 {
+                            Err(IoError {
+                                code: libc::ERROR_OPERATION_ABORTED as uint,
+                                extra: amt,
+                                detail: Some("short write during write".to_string()),
+                            })
+                        } else {
+                            Err(util::timeout("write timed out"))
+                        }
+                    }
+                    if self.write_closed() {
+                        return Err(epipe())
+                    }
+                    continue // retry
+                }
+            }
+            offset += bytes_written as uint;
+        }
+        Ok(())
+    }
+
+    fn clone(&self) -> Box<rtio::RtioPipe + Send> {
+        box UnixStream {
+            inner: self.inner.clone(),
+            read: None,
+            write: None,
+            read_deadline: 0,
+            write_deadline: 0,
+        } as Box<rtio::RtioPipe + Send>
+    }
+
+    fn close_read(&mut self) -> IoResult<()> {
+        // On windows, there's no actual shutdown() method for pipes, so we're
+        // forced to emulate the behavior manually at the application level. To
+        // do this, we need to both cancel any pending requests, as well as
+        // prevent all future requests from succeeding. These two operations are
+        // not atomic with respect to one another, so we must use a lock to do
+        // so.
+        //
+        // The read() code looks like:
+        //
+        //      1. Make sure the pipe is still open
+        //      2. Submit a read request
+        //      3. Wait for the read request to finish
+        //
+        // The race this lock is preventing is if another thread invokes
+        // close_read() between steps 1 and 2. By atomically executing steps 1
+        // and 2 with a lock with respect to close_read(), we're guaranteed that
+        // no thread will erroneously sit in a read forever.
+        let _guard = unsafe { self.inner.lock.lock() };
+        self.inner.read_closed.store(true, atomic::SeqCst);
+        self.cancel_io()
+    }
+
+    fn close_write(&mut self) -> IoResult<()> {
+        // see comments in close_read() for why this lock is necessary
+        let _guard = unsafe { self.inner.lock.lock() };
+        self.inner.write_closed.store(true, atomic::SeqCst);
+        self.cancel_io()
+    }
+
+    fn set_timeout(&mut self, timeout: Option<u64>) {
+        let deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
+        self.read_deadline = deadline;
+        self.write_deadline = deadline;
+    }
+    fn set_read_timeout(&mut self, timeout: Option<u64>) {
+        self.read_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
+    }
+    fn set_write_timeout(&mut self, timeout: Option<u64>) {
+        self.write_deadline = timeout.map(|a| ::io::timer::now() + a).unwrap_or(0);
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Unix Listener
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct UnixListener {
+    handle: libc::HANDLE,
+    name: CString,
+}
+
+impl UnixListener {
+    pub fn bind(addr: &CString) -> IoResult<UnixListener> {
+        // Although we technically don't need the pipe until much later, we
+        // create the initial handle up front to test the validity of the name
+        // and such.
+        let addr_v = try!(to_utf16(addr));
+        let ret = unsafe { pipe(addr_v.as_ptr(), true) };
+        if ret == libc::INVALID_HANDLE_VALUE {
+            Err(super::last_error())
+        } else {
+            Ok(UnixListener { handle: ret, name: addr.clone() })
+        }
+    }
+
+    pub fn native_listen(self) -> IoResult<UnixAcceptor> {
+        Ok(UnixAcceptor {
+            listener: self,
+            event: try!(Event::new(true, false)),
+            deadline: 0,
+        })
+    }
+}
+
+impl Drop for UnixListener {
+    fn drop(&mut self) {
+        unsafe { let _ = libc::CloseHandle(self.handle); }
+    }
+}
+
+impl rtio::RtioUnixListener for UnixListener {
+    fn listen(self: Box<UnixListener>)
+              -> IoResult<Box<rtio::RtioUnixAcceptor + Send>> {
+        self.native_listen().map(|a| {
+            box a as Box<rtio::RtioUnixAcceptor + Send>
+        })
+    }
+}
+
+pub struct UnixAcceptor {
+    listener: UnixListener,
+    event: Event,
+    deadline: u64,
+}
+
+impl UnixAcceptor {
+    pub fn native_accept(&mut self) -> IoResult<UnixStream> {
+        // This function has some funky implementation details when working with
+        // unix pipes. On windows, each server named pipe handle can be
+        // connected to a one or zero clients. To the best of my knowledge, a
+        // named server is considered active and present if there exists at
+        // least one server named pipe for it.
+        //
+        // The model of this function is to take the current known server
+        // handle, connect a client to it, and then transfer ownership to the
+        // UnixStream instance. The next time accept() is invoked, it'll need a
+        // different server handle to connect a client to.
+        //
+        // Note that there is a possible race here. Once our server pipe is
+        // handed off to a `UnixStream` object, the stream could be closed,
+        // meaning that there would be no active server pipes, hence even though
+        // we have a valid `UnixAcceptor`, no one can connect to it. For this
+        // reason, we generate the next accept call's server pipe at the end of
+        // this function call.
+        //
+        // This provides us an invariant that we always have at least one server
+        // connection open at a time, meaning that all connects to this acceptor
+        // should succeed while this is active.
+        //
+        // The actual implementation of doing this is a little tricky. Once a
+        // server pipe is created, a client can connect to it at any time. I
+        // assume that which server a client connects to is nondeterministic, so
+        // we also need to guarantee that the only server able to be connected
+        // to is the one that we're calling ConnectNamedPipe on. This means that
+        // we have to create the second server pipe *after* we've already
+        // accepted a connection. In order to at least somewhat gracefully
+        // handle errors, this means that if the second server pipe creation
+        // fails that we disconnect the connected client and then just keep
+        // using the original server pipe.
+        let handle = self.listener.handle;
+
+        let name = try!(to_utf16(&self.listener.name));
+
+        // Once we've got a "server handle", we need to wait for a client to
+        // connect. The ConnectNamedPipe function will block this thread until
+        // someone on the other end connects. This function can "fail" if a
+        // client connects after we created the pipe but before we got down
+        // here. Thanks windows.
+        let mut overlapped: libc::OVERLAPPED = unsafe { mem::zeroed() };
+        overlapped.hEvent = self.event.handle();
+        if unsafe { libc::ConnectNamedPipe(handle, &mut overlapped) == 0 } {
+            let mut err = unsafe { libc::GetLastError() };
+
+            if err == libc::ERROR_IO_PENDING as libc::DWORD {
+                // Process a timeout if one is pending
+                let _ = await(handle, self.deadline, &mut overlapped);
+
+                // This will block until the overlapped I/O is completed. The
+                // timeout was previously handled, so this will either block in
+                // the normal case or succeed very quickly in the timeout case.
+                let ret = unsafe {
+                    let mut transfer = 0;
+                    libc::GetOverlappedResult(handle,
+                                              &mut overlapped,
+                                              &mut transfer,
+                                              libc::TRUE)
+                };
+                if ret == 0 {
+                    err = unsafe { libc::GetLastError() };
+                } else {
+                    // we succeeded, bypass the check below
+                    err = libc::ERROR_PIPE_CONNECTED as libc::DWORD;
+                }
+            }
+            if err != libc::ERROR_PIPE_CONNECTED as libc::DWORD {
+                return Err(super::last_error())
+            }
+        }
+
+        // Now that we've got a connected client to our handle, we need to
+        // create a second server pipe. If this fails, we disconnect the
+        // connected client and return an error (see comments above).
+        let new_handle = unsafe { pipe(name.as_ptr(), false) };
+        if new_handle == libc::INVALID_HANDLE_VALUE {
+            let ret = Err(super::last_error());
+            // If our disconnection fails, then there's not really a whole lot
+            // that we can do, so fail the task.
+            let err = unsafe { libc::DisconnectNamedPipe(handle) };
+            assert!(err != 0);
+            return ret;
+        } else {
+            self.listener.handle = new_handle;
+        }
+
+        // Transfer ownership of our handle into this stream
+        Ok(UnixStream {
+            inner: Arc::new(Inner::new(handle)),
+            read: None,
+            write: None,
+            read_deadline: 0,
+            write_deadline: 0,
+        })
+    }
+}
+
+impl rtio::RtioUnixAcceptor for UnixAcceptor {
+    fn accept(&mut self) -> IoResult<Box<rtio::RtioPipe + Send>> {
+        self.native_accept().map(|s| box s as Box<rtio::RtioPipe + Send>)
+    }
+    fn set_timeout(&mut self, timeout: Option<u64>) {
+        self.deadline = timeout.map(|i| i + ::io::timer::now()).unwrap_or(0);
+    }
+}
+
index 443d7645388a32644e9bcc3266a0f15864c0b3ff..d1b2885415747b8cc4d80e8301cd62bb21c77bb6 100644 (file)
@@ -786,7 +786,7 @@ fn with_envp<T>(env: Option<&[(&CString, &CString)]>,
 
 #[cfg(windows)]
 fn with_envp<T>(env: Option<&[(&CString, &CString)]>, cb: |*mut c_void| -> T) -> T {
-    // On win32 we pass an "environment block" which is not a char**, but
+    // On Windows we pass an "environment block" which is not a char**, but
     // rather a concatenation of null-terminated k=v\0 sequences, with a final
     // \0 to terminate.
     match env {
diff --git a/src/libnative/io/timer_win32.rs b/src/libnative/io/timer_win32.rs
deleted file mode 100644 (file)
index 1e55941..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-//! Timers based on win32 WaitableTimers
-//!
-//! This implementation is meant to be used solely on windows. As with other
-//! implementations, there is a worker thread which is doing all the waiting on
-//! a large number of timers for all active timers in the system. This worker
-//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
-//! objects being waited on is a signal into the worker thread to notify that
-//! the incoming channel should be looked at.
-//!
-//! Other than that, the implementation is pretty straightforward in terms of
-//! the other two implementations of timers with nothing *that* new showing up.
-
-use libc;
-use std::ptr;
-use std::rt::rtio;
-use std::rt::rtio::{IoResult, Callback};
-use std::comm;
-
-use io::helper_thread::Helper;
-
-helper_init!(static mut HELPER: Helper<Req>)
-
-pub struct Timer {
-    obj: libc::HANDLE,
-    on_worker: bool,
-}
-
-pub enum Req {
-    NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
-    RemoveTimer(libc::HANDLE, Sender<()>),
-}
-
-fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
-    let mut objs = vec![input];
-    let mut chans = vec![];
-
-    'outer: loop {
-        let idx = unsafe {
-            imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
-                                        objs.as_ptr(),
-                                        0 as libc::BOOL,
-                                        libc::INFINITE)
-        };
-
-        if idx == 0 {
-            loop {
-                match messages.try_recv() {
-                    Ok(NewTimer(obj, c, one)) => {
-                        objs.push(obj);
-                        chans.push((c, one));
-                    }
-                    Ok(RemoveTimer(obj, c)) => {
-                        c.send(());
-                        match objs.iter().position(|&o| o == obj) {
-                            Some(i) => {
-                                drop(objs.remove(i));
-                                drop(chans.remove(i - 1));
-                            }
-                            None => {}
-                        }
-                    }
-                    Err(comm::Disconnected) => {
-                        assert_eq!(objs.len(), 1);
-                        assert_eq!(chans.len(), 0);
-                        break 'outer;
-                    }
-                    Err(..) => break
-                }
-            }
-        } else {
-            let remove = {
-                match chans.get_mut(idx as uint - 1) {
-                    &(ref mut c, oneshot) => { c.call(); oneshot }
-                }
-            };
-            if remove {
-                drop(objs.remove(idx as uint));
-                drop(chans.remove(idx as uint - 1));
-            }
-        }
-    }
-}
-
-// returns the current time (in milliseconds)
-pub fn now() -> u64 {
-    let mut ticks_per_s = 0;
-    assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
-    let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
-    let mut ticks = 0;
-    assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
-
-    return (ticks as u64 * 1000) / (ticks_per_s as u64);
-}
-
-impl Timer {
-    pub fn new() -> IoResult<Timer> {
-        unsafe { HELPER.boot(|| {}, helper) }
-
-        let obj = unsafe {
-            imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
-        };
-        if obj.is_null() {
-            Err(super::last_error())
-        } else {
-            Ok(Timer { obj: obj, on_worker: false, })
-        }
-    }
-
-    pub fn sleep(ms: u64) {
-        use std::rt::rtio::RtioTimer;
-        let mut t = Timer::new().ok().expect("must allocate a timer!");
-        t.sleep(ms);
-    }
-
-    fn remove(&mut self) {
-        if !self.on_worker { return }
-
-        let (tx, rx) = channel();
-        unsafe { HELPER.send(RemoveTimer(self.obj, tx)) }
-        rx.recv();
-
-        self.on_worker = false;
-    }
-}
-
-impl rtio::RtioTimer for Timer {
-    fn sleep(&mut self, msecs: u64) {
-        self.remove();
-
-        // there are 10^6 nanoseconds in a millisecond, and the parameter is in
-        // 100ns intervals, so we multiply by 10^4.
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, 0, ptr::mut_null(),
-                                  ptr::mut_null(), 0)
-        }, 1);
-
-        let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
-    }
-
-    fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
-        self.remove();
-
-        // see above for the calculation
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, 0, ptr::mut_null(),
-                                  ptr::mut_null(), 0)
-        }, 1);
-
-        unsafe { HELPER.send(NewTimer(self.obj, cb, true)) }
-        self.on_worker = true;
-    }
-
-    fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
-        self.remove();
-
-        // see above for the calculation
-        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
-        assert_eq!(unsafe {
-            imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
-                                  ptr::mut_null(), ptr::mut_null(), 0)
-        }, 1);
-
-        unsafe { HELPER.send(NewTimer(self.obj, cb, false)) }
-        self.on_worker = true;
-    }
-}
-
-impl Drop for Timer {
-    fn drop(&mut self) {
-        self.remove();
-        assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
-    }
-}
-
-mod imp {
-    use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
-                    LONG, LPVOID, DWORD, c_void};
-
-    pub type PTIMERAPCROUTINE = *mut c_void;
-
-    extern "system" {
-        pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
-                                    bManualReset: BOOL,
-                                    lpTimerName: LPCSTR) -> HANDLE;
-        pub fn SetWaitableTimer(hTimer: HANDLE,
-                                pDueTime: *const LARGE_INTEGER,
-                                lPeriod: LONG,
-                                pfnCompletionRoutine: PTIMERAPCROUTINE,
-                                lpArgToCompletionRoutine: LPVOID,
-                                fResume: BOOL) -> BOOL;
-        pub fn WaitForMultipleObjects(nCount: DWORD,
-                                      lpHandles: *const HANDLE,
-                                      bWaitAll: BOOL,
-                                      dwMilliseconds: DWORD) -> DWORD;
-        pub fn WaitForSingleObject(hHandle: HANDLE,
-                                   dwMilliseconds: DWORD) -> DWORD;
-    }
-}
diff --git a/src/libnative/io/timer_windows.rs b/src/libnative/io/timer_windows.rs
new file mode 100644 (file)
index 0000000..8d781f5
--- /dev/null
@@ -0,0 +1,210 @@
+// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+//! Timers based on Windows WaitableTimers
+//!
+//! This implementation is meant to be used solely on windows. As with other
+//! implementations, there is a worker thread which is doing all the waiting on
+//! a large number of timers for all active timers in the system. This worker
+//! thread uses the select() equivalent, WaitForMultipleObjects. One of the
+//! objects being waited on is a signal into the worker thread to notify that
+//! the incoming channel should be looked at.
+//!
+//! Other than that, the implementation is pretty straightforward in terms of
+//! the other two implementations of timers with nothing *that* new showing up.
+
+use libc;
+use std::ptr;
+use std::rt::rtio;
+use std::rt::rtio::{IoResult, Callback};
+use std::comm;
+
+use io::helper_thread::Helper;
+
+helper_init!(static mut HELPER: Helper<Req>)
+
+pub struct Timer {
+    obj: libc::HANDLE,
+    on_worker: bool,
+}
+
+pub enum Req {
+    NewTimer(libc::HANDLE, Box<Callback + Send>, bool),
+    RemoveTimer(libc::HANDLE, Sender<()>),
+}
+
+fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
+    let mut objs = vec![input];
+    let mut chans = vec![];
+
+    'outer: loop {
+        let idx = unsafe {
+            imp::WaitForMultipleObjects(objs.len() as libc::DWORD,
+                                        objs.as_ptr(),
+                                        0 as libc::BOOL,
+                                        libc::INFINITE)
+        };
+
+        if idx == 0 {
+            loop {
+                match messages.try_recv() {
+                    Ok(NewTimer(obj, c, one)) => {
+                        objs.push(obj);
+                        chans.push((c, one));
+                    }
+                    Ok(RemoveTimer(obj, c)) => {
+                        c.send(());
+                        match objs.iter().position(|&o| o == obj) {
+                            Some(i) => {
+                                drop(objs.remove(i));
+                                drop(chans.remove(i - 1));
+                            }
+                            None => {}
+                        }
+                    }
+                    Err(comm::Disconnected) => {
+                        assert_eq!(objs.len(), 1);
+                        assert_eq!(chans.len(), 0);
+                        break 'outer;
+                    }
+                    Err(..) => break
+                }
+            }
+        } else {
+            let remove = {
+                match chans.get_mut(idx as uint - 1) {
+                    &(ref mut c, oneshot) => { c.call(); oneshot }
+                }
+            };
+            if remove {
+                drop(objs.remove(idx as uint));
+                drop(chans.remove(idx as uint - 1));
+            }
+        }
+    }
+}
+
+// returns the current time (in milliseconds)
+pub fn now() -> u64 {
+    let mut ticks_per_s = 0;
+    assert_eq!(unsafe { libc::QueryPerformanceFrequency(&mut ticks_per_s) }, 1);
+    let ticks_per_s = if ticks_per_s == 0 {1} else {ticks_per_s};
+    let mut ticks = 0;
+    assert_eq!(unsafe { libc::QueryPerformanceCounter(&mut ticks) }, 1);
+
+    return (ticks as u64 * 1000) / (ticks_per_s as u64);
+}
+
+impl Timer {
+    pub fn new() -> IoResult<Timer> {
+        unsafe { HELPER.boot(|| {}, helper) }
+
+        let obj = unsafe {
+            imp::CreateWaitableTimerA(ptr::mut_null(), 0, ptr::null())
+        };
+        if obj.is_null() {
+            Err(super::last_error())
+        } else {
+            Ok(Timer { obj: obj, on_worker: false, })
+        }
+    }
+
+    pub fn sleep(ms: u64) {
+        use std::rt::rtio::RtioTimer;
+        let mut t = Timer::new().ok().expect("must allocate a timer!");
+        t.sleep(ms);
+    }
+
+    fn remove(&mut self) {
+        if !self.on_worker { return }
+
+        let (tx, rx) = channel();
+        unsafe { HELPER.send(RemoveTimer(self.obj, tx)) }
+        rx.recv();
+
+        self.on_worker = false;
+    }
+}
+
+impl rtio::RtioTimer for Timer {
+    fn sleep(&mut self, msecs: u64) {
+        self.remove();
+
+        // there are 10^6 nanoseconds in a millisecond, and the parameter is in
+        // 100ns intervals, so we multiply by 10^4.
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::mut_null(),
+                                  ptr::mut_null(), 0)
+        }, 1);
+
+        let _ = unsafe { imp::WaitForSingleObject(self.obj, libc::INFINITE) };
+    }
+
+    fn oneshot(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        self.remove();
+
+        // see above for the calculation
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, 0, ptr::mut_null(),
+                                  ptr::mut_null(), 0)
+        }, 1);
+
+        unsafe { HELPER.send(NewTimer(self.obj, cb, true)) }
+        self.on_worker = true;
+    }
+
+    fn period(&mut self, msecs: u64, cb: Box<Callback + Send>) {
+        self.remove();
+
+        // see above for the calculation
+        let due = -(msecs as i64 * 10000) as libc::LARGE_INTEGER;
+        assert_eq!(unsafe {
+            imp::SetWaitableTimer(self.obj, &due, msecs as libc::LONG,
+                                  ptr::mut_null(), ptr::mut_null(), 0)
+        }, 1);
+
+        unsafe { HELPER.send(NewTimer(self.obj, cb, false)) }
+        self.on_worker = true;
+    }
+}
+
+impl Drop for Timer {
+    fn drop(&mut self) {
+        self.remove();
+        assert!(unsafe { libc::CloseHandle(self.obj) != 0 });
+    }
+}
+
+mod imp {
+    use libc::{LPSECURITY_ATTRIBUTES, BOOL, LPCSTR, HANDLE, LARGE_INTEGER,
+                    LONG, LPVOID, DWORD, c_void};
+
+    pub type PTIMERAPCROUTINE = *mut c_void;
+
+    extern "system" {
+        pub fn CreateWaitableTimerA(lpTimerAttributes: LPSECURITY_ATTRIBUTES,
+                                    bManualReset: BOOL,
+                                    lpTimerName: LPCSTR) -> HANDLE;
+        pub fn SetWaitableTimer(hTimer: HANDLE,
+                                pDueTime: *const LARGE_INTEGER,
+                                lPeriod: LONG,
+                                pfnCompletionRoutine: PTIMERAPCROUTINE,
+                                lpArgToCompletionRoutine: LPVOID,
+                                fResume: BOOL) -> BOOL;
+        pub fn WaitForMultipleObjects(nCount: DWORD,
+                                      lpHandles: *const HANDLE,
+                                      bWaitAll: BOOL,
+                                      dwMilliseconds: DWORD) -> DWORD;
+        pub fn WaitForSingleObject(hHandle: HANDLE,
+                                   dwMilliseconds: DWORD) -> DWORD;
+    }
+}
diff --git a/src/libnative/io/tty_win32.rs b/src/libnative/io/tty_win32.rs
deleted file mode 100644 (file)
index e98fe1e..0000000
+++ /dev/null
@@ -1,158 +0,0 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// ignore-lexer-test FIXME #15877
-
-//! Windows specific console TTY implementation
-//!
-//! This module contains the implementation of a Windows specific console TTY.
-//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
-//! UTF-8 and some functions will fail. In particular ReadFile and ReadConsole
-//! will fail when the codepage is set to UTF-8 and a unicode character is
-//! entered.
-//!
-//! FIXME
-//! This implementation does not account for codepoints that are split across
-//! multiple reads and writes. Also, this implementation does not expose a way
-//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
-//! wrapper that performs encoding/decoding, this implementation should switch
-//! to working in raw UTF-16, with such a wrapper around it.
-
-use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
-use super::c::{ERROR_ILLEGAL_CHARACTER};
-use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
-use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
-use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
-use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
-use libc::{get_osfhandle, CloseHandle};
-use libc::types::os::arch::extra::LPCVOID;
-use std::io::MemReader;
-use std::ptr;
-use std::rt::rtio::{IoResult, IoError, RtioTTY};
-use std::str::{from_utf16, from_utf8};
-
-fn invalid_encoding() -> IoError {
-    IoError {
-        code: ERROR_ILLEGAL_CHARACTER as uint,
-        extra: 0,
-        detail: Some("text was not valid unicode".to_string()),
-    }
-}
-
-pub fn is_tty(fd: c_int) -> bool {
-    let mut out: DWORD = 0;
-    // If this function doesn't fail then fd is a TTY
-    match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
-                                  &mut out as LPDWORD) } {
-        0 => false,
-        _ => true,
-    }
-}
-
-pub struct WindowsTTY {
-    closeme: bool,
-    handle: HANDLE,
-    utf8: MemReader,
-}
-
-impl WindowsTTY {
-    pub fn new(fd: c_int) -> WindowsTTY {
-        // If the file descriptor is one of stdin, stderr, or stdout
-        // then it should not be closed by us
-        let closeme = match fd {
-            0..2 => false,
-            _ => true,
-        };
-        let handle = unsafe { get_osfhandle(fd) as HANDLE };
-        WindowsTTY {
-            handle: handle,
-            utf8: MemReader::new(Vec::new()),
-            closeme: closeme,
-        }
-    }
-}
-
-impl Drop for WindowsTTY {
-    fn drop(&mut self) {
-        if self.closeme {
-            // Nobody cares about the return value
-            let _ = unsafe { CloseHandle(self.handle) };
-        }
-    }
-}
-
-impl RtioTTY for WindowsTTY {
-    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
-        // Read more if the buffer is empty
-        if self.utf8.eof() {
-            let mut utf16 = Vec::from_elem(0x1000, 0u16);
-            let mut num: DWORD = 0;
-            match unsafe { ReadConsoleW(self.handle,
-                                         utf16.as_mut_ptr() as LPVOID,
-                                         utf16.len() as u32,
-                                         &mut num as LPDWORD,
-                                         ptr::mut_null()) } {
-                0 => return Err(super::last_error()),
-                _ => (),
-            };
-            utf16.truncate(num as uint);
-            let utf8 = match from_utf16(utf16.as_slice()) {
-                Some(utf8) => utf8.into_bytes(),
-                None => return Err(invalid_encoding()),
-            };
-            self.utf8 = MemReader::new(utf8);
-        }
-        // MemReader shouldn't error here since we just filled it
-        Ok(self.utf8.read(buf).unwrap())
-    }
-
-    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
-        let utf16 = match from_utf8(buf) {
-            Some(utf8) => utf8.to_utf16(),
-            None => return Err(invalid_encoding()),
-        };
-        let mut num: DWORD = 0;
-        match unsafe { WriteConsoleW(self.handle,
-                                     utf16.as_ptr() as LPCVOID,
-                                     utf16.len() as u32,
-                                     &mut num as LPDWORD,
-                                     ptr::mut_null()) } {
-            0 => Err(super::last_error()),
-            _ => Ok(()),
-        }
-    }
-
-    fn set_raw(&mut self, raw: bool) -> IoResult<()> {
-        // FIXME
-        // Somebody needs to decide on which of these flags we want
-        match unsafe { SetConsoleMode(self.handle,
-            match raw {
-                true => 0,
-                false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
-                         ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
-                         ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
-            }) } {
-            0 => Err(super::last_error()),
-            _ => Ok(()),
-        }
-    }
-
-    fn get_winsize(&mut self) -> IoResult<(int, int)> {
-        // FIXME
-        // Get console buffer via CreateFile with CONOUT$
-        // Make a CONSOLE_SCREEN_BUFFER_INFO
-        // Call GetConsoleScreenBufferInfo
-        // Maybe call GetLargestConsoleWindowSize instead?
-        Err(super::unimpl())
-    }
-
-    // Let us magically declare this as a TTY
-    fn isatty(&self) -> bool { true }
-}
diff --git a/src/libnative/io/tty_windows.rs b/src/libnative/io/tty_windows.rs
new file mode 100644 (file)
index 0000000..e98fe1e
--- /dev/null
@@ -0,0 +1,158 @@
+// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// ignore-lexer-test FIXME #15877
+
+//! Windows specific console TTY implementation
+//!
+//! This module contains the implementation of a Windows specific console TTY.
+//! Also converts between UTF-16 and UTF-8. Windows has very poor support for
+//! UTF-8 and some functions will fail. In particular ReadFile and ReadConsole
+//! will fail when the codepage is set to UTF-8 and a unicode character is
+//! entered.
+//!
+//! FIXME
+//! This implementation does not account for codepoints that are split across
+//! multiple reads and writes. Also, this implementation does not expose a way
+//! to read/write UTF-16 directly. When/if Rust receives a Reader/Writer
+//! wrapper that performs encoding/decoding, this implementation should switch
+//! to working in raw UTF-16, with such a wrapper around it.
+
+use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode};
+use super::c::{ERROR_ILLEGAL_CHARACTER};
+use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS};
+use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT};
+use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE};
+use libc::{c_int, HANDLE, LPDWORD, DWORD, LPVOID};
+use libc::{get_osfhandle, CloseHandle};
+use libc::types::os::arch::extra::LPCVOID;
+use std::io::MemReader;
+use std::ptr;
+use std::rt::rtio::{IoResult, IoError, RtioTTY};
+use std::str::{from_utf16, from_utf8};
+
+fn invalid_encoding() -> IoError {
+    IoError {
+        code: ERROR_ILLEGAL_CHARACTER as uint,
+        extra: 0,
+        detail: Some("text was not valid unicode".to_string()),
+    }
+}
+
+pub fn is_tty(fd: c_int) -> bool {
+    let mut out: DWORD = 0;
+    // If this function doesn't fail then fd is a TTY
+    match unsafe { GetConsoleMode(get_osfhandle(fd) as HANDLE,
+                                  &mut out as LPDWORD) } {
+        0 => false,
+        _ => true,
+    }
+}
+
+pub struct WindowsTTY {
+    closeme: bool,
+    handle: HANDLE,
+    utf8: MemReader,
+}
+
+impl WindowsTTY {
+    pub fn new(fd: c_int) -> WindowsTTY {
+        // If the file descriptor is one of stdin, stderr, or stdout
+        // then it should not be closed by us
+        let closeme = match fd {
+            0..2 => false,
+            _ => true,
+        };
+        let handle = unsafe { get_osfhandle(fd) as HANDLE };
+        WindowsTTY {
+            handle: handle,
+            utf8: MemReader::new(Vec::new()),
+            closeme: closeme,
+        }
+    }
+}
+
+impl Drop for WindowsTTY {
+    fn drop(&mut self) {
+        if self.closeme {
+            // Nobody cares about the return value
+            let _ = unsafe { CloseHandle(self.handle) };
+        }
+    }
+}
+
+impl RtioTTY for WindowsTTY {
+    fn read(&mut self, buf: &mut [u8]) -> IoResult<uint> {
+        // Read more if the buffer is empty
+        if self.utf8.eof() {
+            let mut utf16 = Vec::from_elem(0x1000, 0u16);
+            let mut num: DWORD = 0;
+            match unsafe { ReadConsoleW(self.handle,
+                                         utf16.as_mut_ptr() as LPVOID,
+                                         utf16.len() as u32,
+                                         &mut num as LPDWORD,
+                                         ptr::mut_null()) } {
+                0 => return Err(super::last_error()),
+                _ => (),
+            };
+            utf16.truncate(num as uint);
+            let utf8 = match from_utf16(utf16.as_slice()) {
+                Some(utf8) => utf8.into_bytes(),
+                None => return Err(invalid_encoding()),
+            };
+            self.utf8 = MemReader::new(utf8);
+        }
+        // MemReader shouldn't error here since we just filled it
+        Ok(self.utf8.read(buf).unwrap())
+    }
+
+    fn write(&mut self, buf: &[u8]) -> IoResult<()> {
+        let utf16 = match from_utf8(buf) {
+            Some(utf8) => utf8.to_utf16(),
+            None => return Err(invalid_encoding()),
+        };
+        let mut num: DWORD = 0;
+        match unsafe { WriteConsoleW(self.handle,
+                                     utf16.as_ptr() as LPCVOID,
+                                     utf16.len() as u32,
+                                     &mut num as LPDWORD,
+                                     ptr::mut_null()) } {
+            0 => Err(super::last_error()),
+            _ => Ok(()),
+        }
+    }
+
+    fn set_raw(&mut self, raw: bool) -> IoResult<()> {
+        // FIXME
+        // Somebody needs to decide on which of these flags we want
+        match unsafe { SetConsoleMode(self.handle,
+            match raw {
+                true => 0,
+                false => ENABLE_ECHO_INPUT | ENABLE_EXTENDED_FLAGS |
+                         ENABLE_INSERT_MODE | ENABLE_LINE_INPUT |
+                         ENABLE_PROCESSED_INPUT | ENABLE_QUICK_EDIT_MODE,
+            }) } {
+            0 => Err(super::last_error()),
+            _ => Ok(()),
+        }
+    }
+
+    fn get_winsize(&mut self) -> IoResult<(int, int)> {
+        // FIXME
+        // Get console buffer via CreateFile with CONOUT$
+        // Make a CONSOLE_SCREEN_BUFFER_INFO
+        // Call GetConsoleScreenBufferInfo
+        // Maybe call GetLargestConsoleWindowSize instead?
+        Err(super::unimpl())
+    }
+
+    // Let us magically declare this as a TTY
+    fn isatty(&self) -> bool { true }
+}
index b475edf77800d1f0c00836fd713b197546421227..7c2b0ba6168177dceb0e43ccbb3bac10c0345ad9 100644 (file)
@@ -856,7 +856,7 @@ pub fn get_cc_prog(sess: &Session) -> String {
     // In the future, FreeBSD will use clang as default compiler.
     // It would be flexible to use cc (system's default C compiler)
     // instead of hard-coded gcc.
-    // For win32, there is no cc command, so we add a condition to make it use gcc.
+    // For Windows, there is no cc command, so we add a condition to make it use gcc.
     match sess.targ_cfg.os {
         abi::OsWindows => "gcc",
         _ => "cc",
index 483937edd9f7c1962eb65599bfbb08a577295755..bf8caef2e97430ef8d0a26909be64eb8d18a0339 100644 (file)
@@ -876,7 +876,7 @@ pub fn trans_drop_flag_ptr<'b>(mut bcx: &'b Block<'b>, r: &Repr,
  * depending on which case of an enum it is.
  *
  * To understand the alignment situation, consider `enum E { V64(u64),
- * V32(u32, u32) }` on win32.  The type has 8-byte alignment to
+ * V32(u32, u32) }` on Windows.  The type has 8-byte alignment to
  * accommodate the u64, but `V32(x, y)` would have LLVM type `{i32,
  * i32, i32}`, which is 4-byte aligned.
  *
index e93a958acc616e66ee59afd7297d1904eb61074f..dc6478df3605d947e2cbbefad906c6ea2573e87d 100644 (file)
@@ -348,7 +348,7 @@ fn get_err(errno: i32) -> (IoErrorKind, &'static str) {
                 // libuv maps this error code to EISDIR. we do too. if it is found
                 // to be incorrect, we can add in some more machinery to only
                 // return this message when ERROR_INVALID_FUNCTION after certain
-                // win32 calls.
+                // Windows calls.
                 libc::ERROR_INVALID_FUNCTION => (InvalidInput,
                                                  "illegal operation on a directory"),
 
index bcdec2e063110ea39a8ba907527141a0120cd2c0..ad666d70034842a8ac7733ae171c27a24d0b7184 100644 (file)
@@ -139,7 +139,7 @@ pub fn getcwd() -> Path {
 }
 
 #[cfg(windows)]
-pub mod win32 {
+pub mod windows {
     use libc::types::os::arch::extra::DWORD;
     use libc;
     use option::{None, Option};
@@ -362,7 +362,7 @@ pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
 pub fn getenv(n: &str) -> Option<String> {
     unsafe {
         with_env_lock(|| {
-            use os::win32::{fill_utf16_buf_and_decode};
+            use os::windows::{fill_utf16_buf_and_decode};
             let n: Vec<u16> = n.utf16_units().collect();
             let n = n.append_one(0);
             fill_utf16_buf_and_decode(|buf, sz| {
@@ -707,7 +707,7 @@ fn load_self() -> Option<Vec<u8>> {
     #[cfg(windows)]
     fn load_self() -> Option<Vec<u8>> {
         unsafe {
-            use os::win32::fill_utf16_buf_and_decode;
+            use os::windows::fill_utf16_buf_and_decode;
             fill_utf16_buf_and_decode(|buf, sz| {
                 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
             }).map(|s| s.into_string().into_bytes())
@@ -1315,7 +1315,7 @@ pub fn page_size() -> uint {
 
 /// A memory mapped file or chunk of memory. This is a very system-specific
 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
-/// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
+/// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at
 /// abstracting platform differences, besides in error values returned. Consider
 /// yourself warned.
 ///
@@ -1385,7 +1385,7 @@ pub enum MapError {
     ErrZeroLength,
     /// Unrecognized error. The inner value is the unrecognized errno.
     ErrUnknown(int),
-    /// ## The following are win32-specific
+    /// ## The following are Windows-specific
     ///
     /// Unsupported combination of protection flags
     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
@@ -1849,7 +1849,7 @@ pub mod consts {
     pub static FAMILY: &'static str = "windows";
 
     /// A string describing the specific operating system in use: in this
-    /// case, `win32`.
+    /// case, `windows`.
     pub static SYSNAME: &'static str = "windows";
 
     /// Specifies the filename prefix used for shared libraries on this
index 00e90fc3cde64abc3e072d66fcfa546ec15cb42f..64a61cc6b3bdcd8d53fcf21745aa188d24b67285 100644 (file)
@@ -10,7 +10,7 @@
 
 //! Windows console handling
 
-// FIXME (#13400): this is only a tiny fraction of the win32 console api
+// FIXME (#13400): this is only a tiny fraction of the Windows console api
 
 extern crate libc;
 
index 5e9e252cefa5158d75280b0fd554944218eead41..c647a8eb0397f7a45b44ec1a7316a8a524e8c48d 100644 (file)
@@ -10,7 +10,7 @@
 
 // aux-build:linkage-visibility.rs
 // ignore-android: FIXME(#10379)
-// ignore-windows: std::dynamic_lib does not work on win32 well
+// ignore-windows: std::dynamic_lib does not work on Windows well
 
 extern crate foo = "linkage-visibility";