]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
f6b1c04dd34c604b5beec2a99e601f5caadf62c3
[rust.git] / src / libstd / os.rs
1 // Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 /*!
12  * Higher-level interfaces to libc::* functions and operating system services.
13  *
14  * In general these take and return rust types, use rust idioms (enums,
15  * closures, vectors) rather than C idioms, and do more extensive safety
16  * checks.
17  *
18  * This module is not meant to only contain 1:1 mappings to libc entries; any
19  * os-interface code that is reasonably useful and broadly applicable can go
20  * here. Including utility routines that merely build on other os code.
21  *
22  * We assume the general case is that users do not care, and do not want to
23  * be made to care, which operating system they are on. While they may want
24  * to special case various special cases -- and so we will not _hide_ the
25  * facts of which OS the user is on -- they should be given the opportunity
26  * to write OS-ignorant code by default.
27  */
28
29 #![allow(missing_doc)]
30 #![allow(non_snake_case_functions)]
31
32 use clone::Clone;
33 use collections::Collection;
34 use fmt;
35 use iter::Iterator;
36 use libc::{c_void, c_int};
37 use libc;
38 use ops::Drop;
39 use option::{Some, None, Option};
40 use os;
41 use path::{Path, GenericPath, BytesContainer};
42 use ptr::RawPtr;
43 use ptr;
44 use result::{Err, Ok, Result};
45 use slice::{Vector, ImmutableVector, MutableVector};
46 use str::{Str, StrSlice, StrAllocating};
47 use str;
48 use string::String;
49 use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
50 use vec::Vec;
51
52 #[cfg(unix)]
53 use c_str::ToCStr;
54 #[cfg(unix)]
55 use libc::c_char;
56 #[cfg(windows)]
57 use str::OwnedStr;
58
59
60 pub static TMPBUF_SZ : uint = 1000u;
61 static BUF_BYTES : uint = 2048u;
62
63 /// Returns the current working directory as a Path.
64 ///
65 /// # Failure
66 ///
67 /// Fails if the current working directory value is invalid:
68 /// Possibles cases:
69 ///
70 /// * Current directory does not exist.
71 /// * There are insufficient permissions to access the current directory.
72 ///
73 /// # Example
74 ///
75 /// ```rust
76 /// use std::os;
77 ///
78 /// // We assume that we are in a valid directory like "/home".
79 /// let current_working_directory = os::getcwd();
80 /// println!("The current directory is {}", current_working_directory.display());
81 /// // /home
82 /// ```
83 #[cfg(unix)]
84 pub fn getcwd() -> Path {
85     use c_str::CString;
86
87     let mut buf = [0 as c_char, ..BUF_BYTES];
88     unsafe {
89         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
90             fail!()
91         }
92         Path::new(CString::new(buf.as_ptr(), false))
93     }
94 }
95
96 /// Returns the current working directory as a Path.
97 ///
98 /// # Failure
99 ///
100 /// Fails if the current working directory value is invalid.
101 /// Possibles cases:
102 ///
103 /// * Current directory does not exist.
104 /// * There are insufficient permissions to access the current directory.
105 ///
106 /// # Example
107 ///
108 /// ```rust
109 /// use std::os;
110 ///
111 /// // We assume that we are in a valid directory like "C:\\Windows".
112 /// let current_working_directory = os::getcwd();
113 /// println!("The current directory is {}", current_working_directory.display());
114 /// // C:\\Windows
115 /// ```
116 #[cfg(windows)]
117 pub fn getcwd() -> Path {
118     use libc::DWORD;
119     use libc::GetCurrentDirectoryW;
120
121     let mut buf = [0 as u16, ..BUF_BYTES];
122     unsafe {
123         if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
124             fail!();
125         }
126     }
127     Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
128               .expect("GetCurrentDirectoryW returned invalid UTF-16"))
129 }
130
131 #[cfg(windows)]
132 pub mod win32 {
133     use libc::types::os::arch::extra::DWORD;
134     use libc;
135     use option::{None, Option};
136     use option;
137     use os::TMPBUF_SZ;
138     use slice::{MutableVector, ImmutableVector};
139     use string::String;
140     use str::StrSlice;
141     use str;
142     use vec::Vec;
143
144     pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
145         -> Option<String> {
146
147         unsafe {
148             let mut n = TMPBUF_SZ as DWORD;
149             let mut res = None;
150             let mut done = false;
151             while !done {
152                 let mut buf = Vec::from_elem(n as uint, 0u16);
153                 let k = f(buf.as_mut_ptr(), n);
154                 if k == (0 as DWORD) {
155                     done = true;
156                 } else if k == n &&
157                           libc::GetLastError() ==
158                           libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
159                     n *= 2 as DWORD;
160                 } else if k >= n {
161                     n = k;
162                 } else {
163                     done = true;
164                 }
165                 if k != 0 && done {
166                     let sub = buf.slice(0, k as uint);
167                     // We want to explicitly catch the case when the
168                     // closure returned invalid UTF-16, rather than
169                     // set `res` to None and continue.
170                     let s = str::from_utf16(sub)
171                         .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
172                     res = option::Some(s)
173                 }
174             }
175             return res;
176         }
177     }
178 }
179
180 /*
181 Accessing environment variables is not generally threadsafe.
182 Serialize access through a global lock.
183 */
184 fn with_env_lock<T>(f: || -> T) -> T {
185     use rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
186
187     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
188
189     unsafe {
190         let _guard = lock.lock();
191         f()
192     }
193 }
194
195 /// Returns a vector of (variable, value) pairs, for all the environment
196 /// variables of the current process.
197 ///
198 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
199 /// for details.
200 ///
201 /// # Example
202 ///
203 /// ```rust
204 /// use std::os;
205 ///
206 /// // We will iterate through the references to the element returned by os::env();
207 /// for &(ref key, ref value) in os::env().iter() {
208 ///     println!("'{}': '{}'", key, value );
209 /// }
210 /// ```
211 pub fn env() -> Vec<(String,String)> {
212     env_as_bytes().move_iter().map(|(k,v)| {
213         let k = str::from_utf8_lossy(k.as_slice()).to_string();
214         let v = str::from_utf8_lossy(v.as_slice()).to_string();
215         (k,v)
216     }).collect()
217 }
218
219 /// Returns a vector of (variable, value) byte-vector pairs for all the
220 /// environment variables of the current process.
221 pub fn env_as_bytes() -> Vec<(Vec<u8>,Vec<u8>)> {
222     unsafe {
223         #[cfg(windows)]
224         unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
225             use slice::raw;
226
227             use libc::funcs::extra::kernel32::{
228                 GetEnvironmentStringsW,
229                 FreeEnvironmentStringsW
230             };
231             let ch = GetEnvironmentStringsW();
232             if ch as uint == 0 {
233                 fail!("os::env() failure getting env string from OS: {}",
234                        os::last_os_error());
235             }
236             // Here, we lossily decode the string as UTF16.
237             //
238             // The docs suggest that the result should be in Unicode, but
239             // Windows doesn't guarantee it's actually UTF16 -- it doesn't
240             // validate the environment string passed to CreateProcess nor
241             // SetEnvironmentVariable.  Yet, it's unlikely that returning a
242             // raw u16 buffer would be of practical use since the result would
243             // be inherently platform-dependent and introduce additional
244             // complexity to this code.
245             //
246             // Using the non-Unicode version of GetEnvironmentStrings is even
247             // worse since the result is in an OEM code page.  Characters that
248             // can't be encoded in the code page would be turned into question
249             // marks.
250             let mut result = Vec::new();
251             let mut i = 0;
252             while *ch.offset(i) != 0 {
253                 let p = &*ch.offset(i);
254                 let len = ptr::position(p, |c| *c == 0);
255                 raw::buf_as_slice(p, len, |s| {
256                     result.push(str::from_utf16_lossy(s).into_bytes());
257                 });
258                 i += len as int + 1;
259             }
260             FreeEnvironmentStringsW(ch);
261             result
262         }
263         #[cfg(unix)]
264         unsafe fn get_env_pairs() -> Vec<Vec<u8>> {
265             use c_str::CString;
266
267             extern {
268                 fn rust_env_pairs() -> **c_char;
269             }
270             let environ = rust_env_pairs();
271             if environ as uint == 0 {
272                 fail!("os::env() failure getting env string from OS: {}",
273                        os::last_os_error());
274             }
275             let mut result = Vec::new();
276             ptr::array_each(environ, |e| {
277                 let env_pair =
278                     Vec::from_slice(CString::new(e, false).as_bytes_no_nul());
279                 result.push(env_pair);
280             });
281             result
282         }
283
284         fn env_convert(input: Vec<Vec<u8>>) -> Vec<(Vec<u8>, Vec<u8>)> {
285             let mut pairs = Vec::new();
286             for p in input.iter() {
287                 let mut it = p.as_slice().splitn(1, |b| *b == '=' as u8);
288                 let key = Vec::from_slice(it.next().unwrap());
289                 let val = Vec::from_slice(it.next().unwrap_or(&[]));
290                 pairs.push((key, val));
291             }
292             pairs
293         }
294         with_env_lock(|| {
295             let unparsed_environ = get_env_pairs();
296             env_convert(unparsed_environ)
297         })
298     }
299 }
300
301 #[cfg(unix)]
302 /// Fetches the environment variable `n` from the current process, returning
303 /// None if the variable isn't set.
304 ///
305 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
306 /// `str::from_utf8_lossy()` for details.
307 ///
308 /// # Failure
309 ///
310 /// Fails if `n` has any interior NULs.
311 ///
312 /// # Example
313 ///
314 /// ```rust
315 /// use std::os;
316 ///
317 /// let key = "HOME";
318 /// match os::getenv(key) {
319 ///     Some(val) => println!("{}: {}", key, val),
320 ///     None => println!("{} is not defined in the environment.", key)
321 /// }
322 /// ```
323 pub fn getenv(n: &str) -> Option<String> {
324     getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v.as_slice()).to_string())
325 }
326
327 #[cfg(unix)]
328 /// Fetches the environment variable `n` byte vector from the current process,
329 /// returning None if the variable isn't set.
330 ///
331 /// # Failure
332 ///
333 /// Fails if `n` has any interior NULs.
334 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
335     use c_str::CString;
336
337     unsafe {
338         with_env_lock(|| {
339             let s = n.with_c_str(|buf| libc::getenv(buf));
340             if s.is_null() {
341                 None
342             } else {
343                 Some(Vec::from_slice(CString::new(s,
344                                                   false).as_bytes_no_nul()))
345             }
346         })
347     }
348 }
349
350 #[cfg(windows)]
351 /// Fetches the environment variable `n` from the current process, returning
352 /// None if the variable isn't set.
353 pub fn getenv(n: &str) -> Option<String> {
354     unsafe {
355         with_env_lock(|| {
356             use os::win32::{fill_utf16_buf_and_decode};
357             let n = n.to_utf16().append_one(0);
358             fill_utf16_buf_and_decode(|buf, sz| {
359                 libc::GetEnvironmentVariableW(n.as_ptr(), buf, sz)
360             })
361         })
362     }
363 }
364
365 #[cfg(windows)]
366 /// Fetches the environment variable `n` byte vector from the current process,
367 /// returning None if the variable isn't set.
368 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
369     getenv(n).map(|s| s.into_bytes())
370 }
371
372 /// Sets the environment variable `n` to the value `v` for the currently running
373 /// process.
374 ///
375 /// # Example
376 ///
377 /// ```rust
378 /// use std::os;
379 ///
380 /// let key = "KEY";
381 /// os::setenv(key, "VALUE");
382 /// match os::getenv(key) {
383 ///     Some(ref val) => println!("{}: {}", key, val),
384 ///     None => println!("{} is not defined in the environment.", key)
385 /// }
386 /// ```
387 pub fn setenv(n: &str, v: &str) {
388     #[cfg(unix)]
389     fn _setenv(n: &str, v: &str) {
390         unsafe {
391             with_env_lock(|| {
392                 n.with_c_str(|nbuf| {
393                     v.with_c_str(|vbuf| {
394                         libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
395                     })
396                 })
397             })
398         }
399     }
400
401     #[cfg(windows)]
402     fn _setenv(n: &str, v: &str) {
403         let n = n.to_utf16().append_one(0);
404         let v = v.to_utf16().append_one(0);
405         unsafe {
406             with_env_lock(|| {
407                 libc::SetEnvironmentVariableW(n.as_ptr(), v.as_ptr());
408             })
409         }
410     }
411     _setenv(n, v)
412 }
413
414 /// Remove a variable from the environment entirely.
415 pub fn unsetenv(n: &str) {
416     #[cfg(unix)]
417     fn _unsetenv(n: &str) {
418         unsafe {
419             with_env_lock(|| {
420                 n.with_c_str(|nbuf| {
421                     libc::funcs::posix01::unistd::unsetenv(nbuf);
422                 })
423             })
424         }
425     }
426
427     #[cfg(windows)]
428     fn _unsetenv(n: &str) {
429         let n = n.to_utf16().append_one(0);
430         unsafe {
431             with_env_lock(|| {
432                 libc::SetEnvironmentVariableW(n.as_ptr(), ptr::null());
433             })
434         }
435     }
436     _unsetenv(n);
437 }
438
439 #[cfg(unix)]
440 /// Parse a string or vector according to the platform's conventions
441 /// for the `PATH` environment variable and return a Vec<Path>.
442 /// Drops empty paths.
443 ///
444 /// # Example
445 /// ```rust
446 /// use std::os;
447 ///
448 /// let key = "PATH";
449 /// match os::getenv(key) {
450 ///     Some(paths) => {
451 ///         for path in os::split_paths(paths).iter() {
452 ///             println!("'{}'", path.display());
453 ///         }
454 ///     }
455 ///     None => println!("{} is not defined in the environnement.", key)
456 /// }
457 /// ```
458 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
459     unparsed.container_as_bytes()
460             .split(|b| *b == ':' as u8)
461             .filter(|s| s.len() > 0)
462             .map(Path::new)
463             .collect()
464 }
465
466 #[cfg(windows)]
467 /// Parse a string or vector according to the platform's conventions
468 /// for the `PATH` environment variable. Drops empty paths.
469 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
470     // On Windows, the PATH environment variable is semicolon separated.  Double
471     // quotes are used as a way of introducing literal semicolons (since
472     // c:\some;dir is a valid Windows path). Double quotes are not themselves
473     // permitted in path names, so there is no way to escape a double quote.
474     // Quoted regions can appear in arbitrary locations, so
475     //
476     //   c:\foo;c:\som"e;di"r;c:\bar
477     //
478     // Should parse as [c:\foo, c:\some;dir, c:\bar].
479     //
480     // (The above is based on testing; there is no clear reference available
481     // for the grammar.)
482
483     let mut parsed = Vec::new();
484     let mut in_progress = Vec::new();
485     let mut in_quote = false;
486
487     for b in unparsed.container_as_bytes().iter() {
488         match *b as char {
489             ';' if !in_quote => {
490                 // ignore zero-length path strings
491                 if in_progress.len() > 0 {
492                     parsed.push(Path::new(in_progress.as_slice()));
493                 }
494                 in_progress.truncate(0)
495             }
496             '\"' => {
497                 in_quote = !in_quote;
498             }
499             _  => {
500                 in_progress.push(*b);
501             }
502         }
503     }
504
505     if in_progress.len() > 0 {
506         parsed.push(Path::new(in_progress));
507     }
508
509     parsed
510 }
511
512 /// A low-level OS in-memory pipe.
513 pub struct Pipe {
514     /// A file descriptor representing the reading end of the pipe. Data written
515     /// on the `out` file descriptor can be read from this file descriptor.
516     pub input: c_int,
517     /// A file descriptor representing the write end of the pipe. Data written
518     /// to this file descriptor can be read from the `input` file descriptor.
519     pub out: c_int,
520 }
521
522 /// Creates a new low-level OS in-memory pipe represented as a Pipe struct.
523 #[cfg(unix)]
524 pub fn pipe() -> Pipe {
525     unsafe {
526         let mut fds = Pipe {input: 0,
527                             out: 0};
528         assert_eq!(libc::pipe(&mut fds.input), 0);
529         return Pipe {input: fds.input, out: fds.out};
530     }
531 }
532
533 /// Creates a new low-level OS in-memory pipe represented as a Pipe struct.
534 #[cfg(windows)]
535 pub fn pipe() -> Pipe {
536     unsafe {
537         // Windows pipes work subtly differently than unix pipes, and their
538         // inheritance has to be handled in a different way that I do not
539         // fully understand. Here we explicitly make the pipe non-inheritable,
540         // which means to pass it to a subprocess they need to be duplicated
541         // first, as in std::run.
542         let mut fds = Pipe {input: 0,
543                     out: 0};
544         let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
545                              (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
546         assert_eq!(res, 0);
547         assert!((fds.input != -1 && fds.input != 0 ));
548         assert!((fds.out != -1 && fds.input != 0));
549         return Pipe {input: fds.input, out: fds.out};
550     }
551 }
552
553 /// Returns the proper dll filename for the given basename of a file
554 /// as a String.
555 #[cfg(not(target_os="ios"))]
556 pub fn dll_filename(base: &str) -> String {
557     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
558 }
559
560 /// Optionally returns the filesystem path to the current executable which is
561 /// running but with the executable name.
562 ///
563 /// # Examples
564 ///
565 /// ```rust
566 /// use std::os;
567 ///
568 /// match os::self_exe_name() {
569 ///     Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
570 ///     None => println!("Unable to get the path of this executable!")
571 /// };
572 /// ```
573 pub fn self_exe_name() -> Option<Path> {
574
575     #[cfg(target_os = "freebsd")]
576     fn load_self() -> Option<Vec<u8>> {
577         unsafe {
578             use libc::funcs::bsd44::*;
579             use libc::consts::os::extra::*;
580             let mib = vec![CTL_KERN as c_int,
581                         KERN_PROC as c_int,
582                         KERN_PROC_PATHNAME as c_int, -1 as c_int];
583             let mut sz: libc::size_t = 0;
584             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
585                              ptr::mut_null(), &mut sz, ptr::null(),
586                              0u as libc::size_t);
587             if err != 0 { return None; }
588             if sz == 0 { return None; }
589             let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
590             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
591                              v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
592                              0u as libc::size_t);
593             if err != 0 { return None; }
594             if sz == 0 { return None; }
595             v.set_len(sz as uint - 1); // chop off trailing NUL
596             Some(v)
597         }
598     }
599
600     #[cfg(target_os = "linux")]
601     #[cfg(target_os = "android")]
602     fn load_self() -> Option<Vec<u8>> {
603         use std::io;
604
605         match io::fs::readlink(&Path::new("/proc/self/exe")) {
606             Ok(path) => Some(path.into_vec()),
607             Err(..) => None
608         }
609     }
610
611     #[cfg(target_os = "macos")]
612     #[cfg(target_os = "ios")]
613     fn load_self() -> Option<Vec<u8>> {
614         unsafe {
615             use libc::funcs::extra::_NSGetExecutablePath;
616             let mut sz: u32 = 0;
617             _NSGetExecutablePath(ptr::mut_null(), &mut sz);
618             if sz == 0 { return None; }
619             let mut v: Vec<u8> = Vec::with_capacity(sz as uint);
620             let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
621             if err != 0 { return None; }
622             v.set_len(sz as uint - 1); // chop off trailing NUL
623             Some(v)
624         }
625     }
626
627     #[cfg(windows)]
628     fn load_self() -> Option<Vec<u8>> {
629         use str::OwnedStr;
630
631         unsafe {
632             use os::win32::fill_utf16_buf_and_decode;
633             fill_utf16_buf_and_decode(|buf, sz| {
634                 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
635             }).map(|s| s.into_string().into_bytes())
636         }
637     }
638
639     load_self().and_then(Path::new_opt)
640 }
641
642 /// Optionally returns the filesystem path to the current executable which is
643 /// running.
644 ///
645 /// Like self_exe_name() but without the binary's name.
646 ///
647 /// # Example
648 ///
649 /// ```rust
650 /// use std::os;
651 ///
652 /// match os::self_exe_path() {
653 ///     Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
654 ///     None => println!("Impossible to fetch the path of this executable.")
655 /// };
656 /// ```
657 pub fn self_exe_path() -> Option<Path> {
658     self_exe_name().map(|mut p| { p.pop(); p })
659 }
660
661 /// Optionally returns the path to the current user's home directory if known.
662 ///
663 /// # Unix
664 ///
665 /// Returns the value of the 'HOME' environment variable if it is set
666 /// and not equal to the empty string.
667 ///
668 /// # Windows
669 ///
670 /// Returns the value of the 'HOME' environment variable if it is
671 /// set and not equal to the empty string. Otherwise, returns the value of the
672 /// 'USERPROFILE' environment variable if it is set and not equal to the empty
673 /// string.
674 ///
675 /// # Example
676 ///
677 /// ```rust
678 /// use std::os;
679 ///
680 /// match os::homedir() {
681 ///     Some(ref p) => println!("{}", p.display()),
682 ///     None => println!("Impossible to get your home dir!")
683 /// }
684 /// ```
685 pub fn homedir() -> Option<Path> {
686     #[inline]
687     #[cfg(unix)]
688     fn _homedir() -> Option<Path> {
689         aux_homedir("HOME")
690     }
691
692     #[inline]
693     #[cfg(windows)]
694     fn _homedir() -> Option<Path> {
695         aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
696     }
697
698     #[inline]
699     fn aux_homedir(home_name: &str) -> Option<Path> {
700         match getenv_as_bytes(home_name) {
701             Some(p)  => {
702                 if p.is_empty() { None } else { Path::new_opt(p) }
703             },
704             _ => None
705         }
706     }
707     _homedir()
708 }
709
710 /**
711  * Returns the path to a temporary directory.
712  *
713  * On Unix, returns the value of the 'TMPDIR' environment variable if it is
714  * set, otherwise for non-Android it returns '/tmp'. If Android, since there
715  * is no global temporary folder (it is usually allocated per-app), we return
716  * '/data/local/tmp'.
717  *
718  * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
719  * 'USERPROFILE' environment variable  if any are set and not the empty
720  * string. Otherwise, tmpdir returns the path to the Windows directory.
721  */
722 pub fn tmpdir() -> Path {
723     return lookup();
724
725     fn getenv_nonempty(v: &str) -> Option<Path> {
726         match getenv(v) {
727             Some(x) =>
728                 if x.is_empty() {
729                     None
730                 } else {
731                     Path::new_opt(x)
732                 },
733             _ => None
734         }
735     }
736
737     #[cfg(unix)]
738     fn lookup() -> Path {
739         let default = if cfg!(target_os = "android") {
740             Path::new("/data/local/tmp")
741         } else {
742             Path::new("/tmp")
743         };
744
745         getenv_nonempty("TMPDIR").unwrap_or(default)
746     }
747
748     #[cfg(windows)]
749     fn lookup() -> Path {
750         getenv_nonempty("TMP").or(
751             getenv_nonempty("TEMP").or(
752                 getenv_nonempty("USERPROFILE").or(
753                    getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
754     }
755 }
756
757 /**
758  * Convert a relative path to an absolute path
759  *
760  * If the given path is relative, return it prepended with the current working
761  * directory. If the given path is already an absolute path, return it
762  * as is.
763  */
764 // NB: this is here rather than in path because it is a form of environment
765 // querying; what it does depends on the process working directory, not just
766 // the input paths.
767 pub fn make_absolute(p: &Path) -> Path {
768     if p.is_absolute() {
769         p.clone()
770     } else {
771         let mut ret = getcwd();
772         ret.push(p);
773         ret
774     }
775 }
776
777 /// Changes the current working directory to the specified path, returning
778 /// whether the change was completed successfully or not.
779 pub fn change_dir(p: &Path) -> bool {
780     return chdir(p);
781
782     #[cfg(windows)]
783     fn chdir(p: &Path) -> bool {
784         let p = match p.as_str() {
785             Some(s) => s.to_utf16().append_one(0),
786             None => return false,
787         };
788         unsafe {
789             libc::SetCurrentDirectoryW(p.as_ptr()) != (0 as libc::BOOL)
790         }
791     }
792
793     #[cfg(unix)]
794     fn chdir(p: &Path) -> bool {
795         p.with_c_str(|buf| {
796             unsafe {
797                 libc::chdir(buf) == (0 as c_int)
798             }
799         })
800     }
801 }
802
803 #[cfg(unix)]
804 /// Returns the platform-specific value of errno
805 pub fn errno() -> int {
806     #[cfg(target_os = "macos")]
807     #[cfg(target_os = "ios")]
808     #[cfg(target_os = "freebsd")]
809     fn errno_location() -> *c_int {
810         extern {
811             fn __error() -> *c_int;
812         }
813         unsafe {
814             __error()
815         }
816     }
817
818     #[cfg(target_os = "linux")]
819     #[cfg(target_os = "android")]
820     fn errno_location() -> *c_int {
821         extern {
822             fn __errno_location() -> *c_int;
823         }
824         unsafe {
825             __errno_location()
826         }
827     }
828
829     unsafe {
830         (*errno_location()) as int
831     }
832 }
833
834 #[cfg(windows)]
835 /// Returns the platform-specific value of errno
836 pub fn errno() -> uint {
837     use libc::types::os::arch::extra::DWORD;
838
839     #[link_name = "kernel32"]
840     extern "system" {
841         fn GetLastError() -> DWORD;
842     }
843
844     unsafe {
845         GetLastError() as uint
846     }
847 }
848
849 /// Return the string corresponding to an `errno()` value of `errnum`.
850 pub fn error_string(errnum: uint) -> String {
851     return strerror(errnum);
852
853     #[cfg(unix)]
854     fn strerror(errnum: uint) -> String {
855         #[cfg(target_os = "macos")]
856         #[cfg(target_os = "ios")]
857         #[cfg(target_os = "android")]
858         #[cfg(target_os = "freebsd")]
859         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
860                       -> c_int {
861             extern {
862                 fn strerror_r(errnum: c_int, buf: *mut c_char,
863                               buflen: libc::size_t) -> c_int;
864             }
865             unsafe {
866                 strerror_r(errnum, buf, buflen)
867             }
868         }
869
870         // GNU libc provides a non-compliant version of strerror_r by default
871         // and requires macros to instead use the POSIX compliant variant.
872         // So we just use __xpg_strerror_r which is always POSIX compliant
873         #[cfg(target_os = "linux")]
874         fn strerror_r(errnum: c_int, buf: *mut c_char,
875                       buflen: libc::size_t) -> c_int {
876             extern {
877                 fn __xpg_strerror_r(errnum: c_int,
878                                     buf: *mut c_char,
879                                     buflen: libc::size_t)
880                                     -> c_int;
881             }
882             unsafe {
883                 __xpg_strerror_r(errnum, buf, buflen)
884             }
885         }
886
887         let mut buf = [0 as c_char, ..TMPBUF_SZ];
888
889         let p = buf.as_mut_ptr();
890         unsafe {
891             if strerror_r(errnum as c_int, p, buf.len() as libc::size_t) < 0 {
892                 fail!("strerror_r failure");
893             }
894
895             str::raw::from_c_str(p as *c_char).into_string()
896         }
897     }
898
899     #[cfg(windows)]
900     fn strerror(errnum: uint) -> String {
901         use libc::types::os::arch::extra::DWORD;
902         use libc::types::os::arch::extra::LPWSTR;
903         use libc::types::os::arch::extra::LPVOID;
904         use libc::types::os::arch::extra::WCHAR;
905
906         #[link_name = "kernel32"]
907         extern "system" {
908             fn FormatMessageW(flags: DWORD,
909                               lpSrc: LPVOID,
910                               msgId: DWORD,
911                               langId: DWORD,
912                               buf: LPWSTR,
913                               nsize: DWORD,
914                               args: *c_void)
915                               -> DWORD;
916         }
917
918         static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
919         static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
920
921         // This value is calculated from the macro
922         // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
923         let langId = 0x0800 as DWORD;
924
925         let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
926
927         unsafe {
928             let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
929                                      FORMAT_MESSAGE_IGNORE_INSERTS,
930                                      ptr::mut_null(),
931                                      errnum as DWORD,
932                                      langId,
933                                      buf.as_mut_ptr(),
934                                      buf.len() as DWORD,
935                                      ptr::null());
936             if res == 0 {
937                 // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
938                 let fm_err = errno();
939                 return format!("OS Error {} (FormatMessageW() returned error {})", errnum, fm_err);
940             }
941
942             let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
943             match msg {
944                 Some(msg) => format!("OS Error {}: {}", errnum, msg),
945                 None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", errnum),
946             }
947         }
948     }
949 }
950
951 /// Get a string representing the platform-dependent last error
952 pub fn last_os_error() -> String {
953     error_string(errno() as uint)
954 }
955
956 static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
957
958 /**
959  * Sets the process exit code
960  *
961  * Sets the exit code returned by the process if all supervised tasks
962  * terminate successfully (without failing). If the current root task fails
963  * and is supervised by the scheduler then any user-specified exit status is
964  * ignored and the process exits with the default failure status.
965  *
966  * Note that this is not synchronized against modifications of other threads.
967  */
968 pub fn set_exit_status(code: int) {
969     unsafe { EXIT_STATUS.store(code, SeqCst) }
970 }
971
972 /// Fetches the process's current exit code. This defaults to 0 and can change
973 /// by calling `set_exit_status`.
974 pub fn get_exit_status() -> int {
975     unsafe { EXIT_STATUS.load(SeqCst) }
976 }
977
978 #[cfg(target_os = "macos")]
979 unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> Vec<Vec<u8>> {
980     use c_str::CString;
981
982     Vec::from_fn(argc as uint, |i| {
983         Vec::from_slice(CString::new(*argv.offset(i as int),
984                                      false).as_bytes_no_nul())
985     })
986 }
987
988 /**
989  * Returns the command line arguments
990  *
991  * Returns a list of the command line arguments.
992  */
993 #[cfg(target_os = "macos")]
994 fn real_args_as_bytes() -> Vec<Vec<u8>> {
995     unsafe {
996         let (argc, argv) = (*_NSGetArgc() as int,
997                             *_NSGetArgv() as **c_char);
998         load_argc_and_argv(argc, argv)
999     }
1000 }
1001
1002 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
1003 // and use underscores in their names - they're most probably
1004 // are considered private and therefore should be avoided
1005 // Here is another way to get arguments using Objective C
1006 // runtime
1007 //
1008 // In general it looks like:
1009 // res = Vec::new()
1010 // let args = [[NSProcessInfo processInfo] arguments]
1011 // for i in range(0, [args count])
1012 //      res.push([args objectAtIndex:i])
1013 // res
1014 #[cfg(target_os = "ios")]
1015 fn real_args_as_bytes() -> Vec<Vec<u8>> {
1016     use c_str::CString;
1017     use iter::range;
1018     use mem;
1019
1020     #[link(name = "objc")]
1021     extern {
1022         fn sel_registerName(name: *libc::c_uchar) -> Sel;
1023         fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
1024         fn objc_getClass(class_name: *libc::c_uchar) -> NsId;
1025     }
1026
1027     #[link(name = "Foundation", kind = "framework")]
1028     extern {}
1029
1030     type Sel = *libc::c_void;
1031     type NsId = *libc::c_void;
1032
1033     let mut res = Vec::new();
1034
1035     unsafe {
1036         let processInfoSel = sel_registerName("processInfo\0".as_ptr());
1037         let argumentsSel = sel_registerName("arguments\0".as_ptr());
1038         let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
1039         let countSel = sel_registerName("count\0".as_ptr());
1040         let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
1041
1042         let klass = objc_getClass("NSProcessInfo\0".as_ptr());
1043         let info = objc_msgSend(klass, processInfoSel);
1044         let args = objc_msgSend(info, argumentsSel);
1045
1046         let cnt: int = mem::transmute(objc_msgSend(args, countSel));
1047         for i in range(0, cnt) {
1048             let tmp = objc_msgSend(args, objectAtSel, i);
1049             let utf_c_str: *libc::c_char = mem::transmute(objc_msgSend(tmp, utf8Sel));
1050             let s = CString::new(utf_c_str, false);
1051             if s.is_not_null() {
1052                 res.push(Vec::from_slice(s.as_bytes_no_nul()))
1053             }
1054         }
1055     }
1056
1057     res
1058 }
1059
1060 #[cfg(target_os = "linux")]
1061 #[cfg(target_os = "android")]
1062 #[cfg(target_os = "freebsd")]
1063 fn real_args_as_bytes() -> Vec<Vec<u8>> {
1064     use rt;
1065
1066     match rt::args::clone() {
1067         Some(args) => args,
1068         None => fail!("process arguments not initialized")
1069     }
1070 }
1071
1072 #[cfg(not(windows))]
1073 fn real_args() -> Vec<String> {
1074     real_args_as_bytes().move_iter()
1075                         .map(|v| {
1076                             str::from_utf8_lossy(v.as_slice()).into_string()
1077                         }).collect()
1078 }
1079
1080 #[cfg(windows)]
1081 fn real_args() -> Vec<String> {
1082     use slice;
1083
1084     let mut nArgs: c_int = 0;
1085     let lpArgCount: *mut c_int = &mut nArgs;
1086     let lpCmdLine = unsafe { GetCommandLineW() };
1087     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
1088
1089     let args = Vec::from_fn(nArgs as uint, |i| unsafe {
1090         // Determine the length of this argument.
1091         let ptr = *szArgList.offset(i as int);
1092         let mut len = 0;
1093         while *ptr.offset(len as int) != 0 { len += 1; }
1094
1095         // Push it onto the list.
1096         let opt_s = slice::raw::buf_as_slice(ptr, len, |buf| {
1097             str::from_utf16(str::truncate_utf16_at_nul(buf))
1098         });
1099         opt_s.expect("CommandLineToArgvW returned invalid UTF-16")
1100     });
1101
1102     unsafe {
1103         LocalFree(szArgList as *c_void);
1104     }
1105
1106     return args
1107 }
1108
1109 #[cfg(windows)]
1110 fn real_args_as_bytes() -> Vec<Vec<u8>> {
1111     real_args().move_iter().map(|s| s.into_bytes()).collect()
1112 }
1113
1114 type LPCWSTR = *u16;
1115
1116 #[cfg(windows)]
1117 #[link_name="kernel32"]
1118 extern "system" {
1119     fn GetCommandLineW() -> LPCWSTR;
1120     fn LocalFree(ptr: *c_void);
1121 }
1122
1123 #[cfg(windows)]
1124 #[link_name="shell32"]
1125 extern "system" {
1126     fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
1127 }
1128
1129 /// Returns the arguments which this program was started with (normally passed
1130 /// via the command line).
1131 ///
1132 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
1133 /// See `str::from_utf8_lossy` for details.
1134 pub fn args() -> Vec<String> {
1135     real_args()
1136 }
1137
1138 /// Returns the arguments which this program was started with (normally passed
1139 /// via the command line) as byte vectors.
1140 pub fn args_as_bytes() -> Vec<Vec<u8>> {
1141     real_args_as_bytes()
1142 }
1143
1144 #[cfg(target_os = "macos")]
1145 extern {
1146     // These functions are in crt_externs.h.
1147     pub fn _NSGetArgc() -> *c_int;
1148     pub fn _NSGetArgv() -> ***c_char;
1149 }
1150
1151 // Round up `from` to be divisible by `to`
1152 fn round_up(from: uint, to: uint) -> uint {
1153     let r = if from % to == 0 {
1154         from
1155     } else {
1156         from + to - (from % to)
1157     };
1158     if r == 0 {
1159         to
1160     } else {
1161         r
1162     }
1163 }
1164
1165 /// Returns the page size of the current architecture in bytes.
1166 #[cfg(unix)]
1167 pub fn page_size() -> uint {
1168     unsafe {
1169         libc::sysconf(libc::_SC_PAGESIZE) as uint
1170     }
1171 }
1172
1173 /// Returns the page size of the current architecture in bytes.
1174 #[cfg(windows)]
1175 pub fn page_size() -> uint {
1176     use mem;
1177     unsafe {
1178         let mut info = mem::zeroed();
1179         libc::GetSystemInfo(&mut info);
1180
1181         return info.dwPageSize as uint;
1182     }
1183 }
1184
1185 /// A memory mapped file or chunk of memory. This is a very system-specific
1186 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
1187 /// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
1188 /// abstracting platform differences, besides in error values returned. Consider
1189 /// yourself warned.
1190 ///
1191 /// The memory map is released (unmapped) when the destructor is run, so don't
1192 /// let it leave scope by accident if you want it to stick around.
1193 pub struct MemoryMap {
1194     /// Pointer to the memory created or modified by this map.
1195     pub data: *mut u8,
1196     /// Number of bytes this map applies to
1197     pub len: uint,
1198     /// Type of mapping
1199     pub kind: MemoryMapKind,
1200 }
1201
1202 /// Type of memory map
1203 pub enum MemoryMapKind {
1204     /// Virtual memory map. Usually used to change the permissions of a given
1205     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
1206     MapFile(*u8),
1207     /// Virtual memory map. Usually used to change the permissions of a given
1208     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
1209     /// Windows.
1210     MapVirtual
1211 }
1212
1213 /// Options the memory map is created with
1214 pub enum MapOption {
1215     /// The memory should be readable
1216     MapReadable,
1217     /// The memory should be writable
1218     MapWritable,
1219     /// The memory should be executable
1220     MapExecutable,
1221     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
1222     /// POSIX.
1223     MapAddr(*u8),
1224     /// Create a memory mapping for a file with a given fd.
1225     MapFd(c_int),
1226     /// When using `MapFd`, the start of the map is `uint` bytes from the start
1227     /// of the file.
1228     MapOffset(uint),
1229     /// On POSIX, this can be used to specify the default flags passed to
1230     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
1231     /// `MAP_ANON`. This will override both of those. This is platform-specific
1232     /// (the exact values used) and ignored on Windows.
1233     MapNonStandardFlags(c_int),
1234 }
1235
1236 /// Possible errors when creating a map.
1237 pub enum MapError {
1238     /// ## The following are POSIX-specific
1239     ///
1240     /// fd was not open for reading or, if using `MapWritable`, was not open for
1241     /// writing.
1242     ErrFdNotAvail,
1243     /// fd was not valid
1244     ErrInvalidFd,
1245     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
1246     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
1247     ErrUnaligned,
1248     /// With `MapFd`, the fd does not support mapping.
1249     ErrNoMapSupport,
1250     /// If using `MapAddr`, the address + `min_len` was outside of the process's
1251     /// address space. If using `MapFd`, the target of the fd didn't have enough
1252     /// resources to fulfill the request.
1253     ErrNoMem,
1254     /// A zero-length map was requested. This is invalid according to
1255     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
1256     /// Not all platforms obey this, but this wrapper does.
1257     ErrZeroLength,
1258     /// Unrecognized error. The inner value is the unrecognized errno.
1259     ErrUnknown(int),
1260     /// ## The following are win32-specific
1261     ///
1262     /// Unsupported combination of protection flags
1263     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
1264     ErrUnsupProt,
1265     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
1266     /// at all)
1267     ErrUnsupOffset,
1268     /// When using `MapFd`, there was already a mapping to the file.
1269     ErrAlreadyExists,
1270     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
1271     /// value of GetLastError.
1272     ErrVirtualAlloc(uint),
1273     /// Unrecognized error from `CreateFileMapping`. The inner value is the
1274     /// return value of `GetLastError`.
1275     ErrCreateFileMappingW(uint),
1276     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
1277     /// value of `GetLastError`.
1278     ErrMapViewOfFile(uint)
1279 }
1280
1281 impl fmt::Show for MapError {
1282     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1283         let str = match *self {
1284             ErrFdNotAvail => "fd not available for reading or writing",
1285             ErrInvalidFd => "Invalid fd",
1286             ErrUnaligned => {
1287                 "Unaligned address, invalid flags, negative length or \
1288                  unaligned offset"
1289             }
1290             ErrNoMapSupport=> "File doesn't support mapping",
1291             ErrNoMem => "Invalid address, or not enough available memory",
1292             ErrUnsupProt => "Protection mode unsupported",
1293             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
1294             ErrAlreadyExists => "File mapping for specified file already exists",
1295             ErrZeroLength => "Zero-length mapping not allowed",
1296             ErrUnknown(code) => {
1297                 return write!(out, "Unknown error = {}", code)
1298             },
1299             ErrVirtualAlloc(code) => {
1300                 return write!(out, "VirtualAlloc failure = {}", code)
1301             },
1302             ErrCreateFileMappingW(code) => {
1303                 return write!(out, "CreateFileMappingW failure = {}", code)
1304             },
1305             ErrMapViewOfFile(code) => {
1306                 return write!(out, "MapViewOfFile failure = {}", code)
1307             }
1308         };
1309         write!(out, "{}", str)
1310     }
1311 }
1312
1313 #[cfg(unix)]
1314 impl MemoryMap {
1315     /// Create a new mapping with the given `options`, at least `min_len` bytes
1316     /// long. `min_len` must be greater than zero; see the note on
1317     /// `ErrZeroLength`.
1318     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1319         use libc::off_t;
1320         use cmp::Equiv;
1321
1322         if min_len == 0 {
1323             return Err(ErrZeroLength)
1324         }
1325         let mut addr: *u8 = ptr::null();
1326         let mut prot = 0;
1327         let mut flags = libc::MAP_PRIVATE;
1328         let mut fd = -1;
1329         let mut offset = 0;
1330         let mut custom_flags = false;
1331         let len = round_up(min_len, page_size());
1332
1333         for &o in options.iter() {
1334             match o {
1335                 MapReadable => { prot |= libc::PROT_READ; },
1336                 MapWritable => { prot |= libc::PROT_WRITE; },
1337                 MapExecutable => { prot |= libc::PROT_EXEC; },
1338                 MapAddr(addr_) => {
1339                     flags |= libc::MAP_FIXED;
1340                     addr = addr_;
1341                 },
1342                 MapFd(fd_) => {
1343                     flags |= libc::MAP_FILE;
1344                     fd = fd_;
1345                 },
1346                 MapOffset(offset_) => { offset = offset_ as off_t; },
1347                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1348             }
1349         }
1350         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1351
1352         let r = unsafe {
1353             libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
1354                        offset)
1355         };
1356         if r.equiv(&libc::MAP_FAILED) {
1357             Err(match errno() as c_int {
1358                 libc::EACCES => ErrFdNotAvail,
1359                 libc::EBADF => ErrInvalidFd,
1360                 libc::EINVAL => ErrUnaligned,
1361                 libc::ENODEV => ErrNoMapSupport,
1362                 libc::ENOMEM => ErrNoMem,
1363                 code => ErrUnknown(code as int)
1364             })
1365         } else {
1366             Ok(MemoryMap {
1367                data: r as *mut u8,
1368                len: len,
1369                kind: if fd == -1 {
1370                    MapVirtual
1371                } else {
1372                    MapFile(ptr::null())
1373                }
1374             })
1375         }
1376     }
1377
1378     /// Granularity that the offset or address must be for `MapOffset` and
1379     /// `MapAddr` respectively.
1380     pub fn granularity() -> uint {
1381         page_size()
1382     }
1383 }
1384
1385 #[cfg(unix)]
1386 impl Drop for MemoryMap {
1387     /// Unmap the mapping. Fails the task if `munmap` fails.
1388     fn drop(&mut self) {
1389         if self.len == 0 { /* workaround for dummy_stack */ return; }
1390
1391         unsafe {
1392             // FIXME: what to do if this fails?
1393             let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t);
1394         }
1395     }
1396 }
1397
1398 #[cfg(windows)]
1399 impl MemoryMap {
1400     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1401     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1402         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1403
1404         let mut lpAddress: LPVOID = ptr::mut_null();
1405         let mut readable = false;
1406         let mut writable = false;
1407         let mut executable = false;
1408         let mut fd: c_int = -1;
1409         let mut offset: uint = 0;
1410         let len = round_up(min_len, page_size());
1411
1412         for &o in options.iter() {
1413             match o {
1414                 MapReadable => { readable = true; },
1415                 MapWritable => { writable = true; },
1416                 MapExecutable => { executable = true; }
1417                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1418                 MapFd(fd_) => { fd = fd_; },
1419                 MapOffset(offset_) => { offset = offset_; },
1420                 MapNonStandardFlags(..) => {}
1421             }
1422         }
1423
1424         let flProtect = match (executable, readable, writable) {
1425             (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1426             (false, true, false) => libc::PAGE_READONLY,
1427             (false, true, true) => libc::PAGE_READWRITE,
1428             (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1429             (true, true, false) => libc::PAGE_EXECUTE_READ,
1430             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1431             _ => return Err(ErrUnsupProt)
1432         };
1433
1434         if fd == -1 {
1435             if offset != 0 {
1436                 return Err(ErrUnsupOffset);
1437             }
1438             let r = unsafe {
1439                 libc::VirtualAlloc(lpAddress,
1440                                    len as SIZE_T,
1441                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1442                                    flProtect)
1443             };
1444             match r as uint {
1445                 0 => Err(ErrVirtualAlloc(errno())),
1446                 _ => Ok(MemoryMap {
1447                    data: r as *mut u8,
1448                    len: len,
1449                    kind: MapVirtual
1450                 })
1451             }
1452         } else {
1453             let dwDesiredAccess = match (executable, readable, writable) {
1454                 (false, true, false) => libc::FILE_MAP_READ,
1455                 (false, true, true) => libc::FILE_MAP_WRITE,
1456                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1457                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1458                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1459                                               // we should never get here.
1460             };
1461             unsafe {
1462                 let hFile = libc::get_osfhandle(fd) as HANDLE;
1463                 let mapping = libc::CreateFileMappingW(hFile,
1464                                                        ptr::mut_null(),
1465                                                        flProtect,
1466                                                        0,
1467                                                        0,
1468                                                        ptr::null());
1469                 if mapping == ptr::mut_null() {
1470                     return Err(ErrCreateFileMappingW(errno()));
1471                 }
1472                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1473                     return Err(ErrAlreadyExists);
1474                 }
1475                 let r = libc::MapViewOfFile(mapping,
1476                                             dwDesiredAccess,
1477                                             ((len as u64) >> 32) as DWORD,
1478                                             (offset & 0xffff_ffff) as DWORD,
1479                                             0);
1480                 match r as uint {
1481                     0 => Err(ErrMapViewOfFile(errno())),
1482                     _ => Ok(MemoryMap {
1483                        data: r as *mut u8,
1484                        len: len,
1485                        kind: MapFile(mapping as *u8)
1486                     })
1487                 }
1488             }
1489         }
1490     }
1491
1492     /// Granularity of MapAddr() and MapOffset() parameter values.
1493     /// This may be greater than the value returned by page_size().
1494     pub fn granularity() -> uint {
1495         use mem;
1496         unsafe {
1497             let mut info = mem::zeroed();
1498             libc::GetSystemInfo(&mut info);
1499
1500             return info.dwAllocationGranularity as uint;
1501         }
1502     }
1503 }
1504
1505 #[cfg(windows)]
1506 impl Drop for MemoryMap {
1507     /// Unmap the mapping. Fails the task if any of `VirtualFree`,
1508     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1509     fn drop(&mut self) {
1510         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1511         use libc::consts::os::extra::FALSE;
1512         if self.len == 0 { return }
1513
1514         unsafe {
1515             match self.kind {
1516                 MapVirtual => {
1517                     if libc::VirtualFree(self.data as *mut c_void, 0,
1518                                          libc::MEM_RELEASE) == 0 {
1519                         println!("VirtualFree failed: {}", errno());
1520                     }
1521                 },
1522                 MapFile(mapping) => {
1523                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1524                         println!("UnmapViewOfFile failed: {}", errno());
1525                     }
1526                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1527                         println!("CloseHandle failed: {}", errno());
1528                     }
1529                 }
1530             }
1531         }
1532     }
1533 }
1534
1535 #[cfg(target_os = "linux")]
1536 pub mod consts {
1537     pub use os::arch_consts::ARCH;
1538
1539     pub static FAMILY: &'static str = "unix";
1540
1541     /// A string describing the specific operating system in use: in this
1542     /// case, `linux`.
1543     pub static SYSNAME: &'static str = "linux";
1544
1545     /// Specifies the filename prefix used for shared libraries on this
1546     /// platform: in this case, `lib`.
1547     pub static DLL_PREFIX: &'static str = "lib";
1548
1549     /// Specifies the filename suffix used for shared libraries on this
1550     /// platform: in this case, `.so`.
1551     pub static DLL_SUFFIX: &'static str = ".so";
1552
1553     /// Specifies the file extension used for shared libraries on this
1554     /// platform that goes after the dot: in this case, `so`.
1555     pub static DLL_EXTENSION: &'static str = "so";
1556
1557     /// Specifies the filename suffix used for executable binaries on this
1558     /// platform: in this case, the empty string.
1559     pub static EXE_SUFFIX: &'static str = "";
1560
1561     /// Specifies the file extension, if any, used for executable binaries
1562     /// on this platform: in this case, the empty string.
1563     pub static EXE_EXTENSION: &'static str = "";
1564 }
1565
1566 #[cfg(target_os = "macos")]
1567 pub mod consts {
1568     pub use os::arch_consts::ARCH;
1569
1570     pub static FAMILY: &'static str = "unix";
1571
1572     /// A string describing the specific operating system in use: in this
1573     /// case, `macos`.
1574     pub static SYSNAME: &'static str = "macos";
1575
1576     /// Specifies the filename prefix used for shared libraries on this
1577     /// platform: in this case, `lib`.
1578     pub static DLL_PREFIX: &'static str = "lib";
1579
1580     /// Specifies the filename suffix used for shared libraries on this
1581     /// platform: in this case, `.dylib`.
1582     pub static DLL_SUFFIX: &'static str = ".dylib";
1583
1584     /// Specifies the file extension used for shared libraries on this
1585     /// platform that goes after the dot: in this case, `dylib`.
1586     pub static DLL_EXTENSION: &'static str = "dylib";
1587
1588     /// Specifies the filename suffix used for executable binaries on this
1589     /// platform: in this case, the empty string.
1590     pub static EXE_SUFFIX: &'static str = "";
1591
1592     /// Specifies the file extension, if any, used for executable binaries
1593     /// on this platform: in this case, the empty string.
1594     pub static EXE_EXTENSION: &'static str = "";
1595 }
1596
1597 #[cfg(target_os = "ios")]
1598 pub mod consts {
1599     pub use os::arch_consts::ARCH;
1600
1601     pub static FAMILY: &'static str = "unix";
1602
1603     /// A string describing the specific operating system in use: in this
1604     /// case, `ios`.
1605     pub static SYSNAME: &'static str = "ios";
1606
1607     /// Specifies the filename suffix used for executable binaries on this
1608     /// platform: in this case, the empty string.
1609     pub static EXE_SUFFIX: &'static str = "";
1610
1611     /// Specifies the file extension, if any, used for executable binaries
1612     /// on this platform: in this case, the empty string.
1613     pub static EXE_EXTENSION: &'static str = "";
1614 }
1615
1616 #[cfg(target_os = "freebsd")]
1617 pub mod consts {
1618     pub use os::arch_consts::ARCH;
1619
1620     pub static FAMILY: &'static str = "unix";
1621
1622     /// A string describing the specific operating system in use: in this
1623     /// case, `freebsd`.
1624     pub static SYSNAME: &'static str = "freebsd";
1625
1626     /// Specifies the filename prefix used for shared libraries on this
1627     /// platform: in this case, `lib`.
1628     pub static DLL_PREFIX: &'static str = "lib";
1629
1630     /// Specifies the filename suffix used for shared libraries on this
1631     /// platform: in this case, `.so`.
1632     pub static DLL_SUFFIX: &'static str = ".so";
1633
1634     /// Specifies the file extension used for shared libraries on this
1635     /// platform that goes after the dot: in this case, `so`.
1636     pub static DLL_EXTENSION: &'static str = "so";
1637
1638     /// Specifies the filename suffix used for executable binaries on this
1639     /// platform: in this case, the empty string.
1640     pub static EXE_SUFFIX: &'static str = "";
1641
1642     /// Specifies the file extension, if any, used for executable binaries
1643     /// on this platform: in this case, the empty string.
1644     pub static EXE_EXTENSION: &'static str = "";
1645 }
1646
1647 #[cfg(target_os = "android")]
1648 pub mod consts {
1649     pub use os::arch_consts::ARCH;
1650
1651     pub static FAMILY: &'static str = "unix";
1652
1653     /// A string describing the specific operating system in use: in this
1654     /// case, `android`.
1655     pub static SYSNAME: &'static str = "android";
1656
1657     /// Specifies the filename prefix used for shared libraries on this
1658     /// platform: in this case, `lib`.
1659     pub static DLL_PREFIX: &'static str = "lib";
1660
1661     /// Specifies the filename suffix used for shared libraries on this
1662     /// platform: in this case, `.so`.
1663     pub static DLL_SUFFIX: &'static str = ".so";
1664
1665     /// Specifies the file extension used for shared libraries on this
1666     /// platform that goes after the dot: in this case, `so`.
1667     pub static DLL_EXTENSION: &'static str = "so";
1668
1669     /// Specifies the filename suffix used for executable binaries on this
1670     /// platform: in this case, the empty string.
1671     pub static EXE_SUFFIX: &'static str = "";
1672
1673     /// Specifies the file extension, if any, used for executable binaries
1674     /// on this platform: in this case, the empty string.
1675     pub static EXE_EXTENSION: &'static str = "";
1676 }
1677
1678 #[cfg(target_os = "win32")]
1679 pub mod consts {
1680     pub use os::arch_consts::ARCH;
1681
1682     pub static FAMILY: &'static str = "windows";
1683
1684     /// A string describing the specific operating system in use: in this
1685     /// case, `win32`.
1686     pub static SYSNAME: &'static str = "win32";
1687
1688     /// Specifies the filename prefix used for shared libraries on this
1689     /// platform: in this case, the empty string.
1690     pub static DLL_PREFIX: &'static str = "";
1691
1692     /// Specifies the filename suffix used for shared libraries on this
1693     /// platform: in this case, `.dll`.
1694     pub static DLL_SUFFIX: &'static str = ".dll";
1695
1696     /// Specifies the file extension used for shared libraries on this
1697     /// platform that goes after the dot: in this case, `dll`.
1698     pub static DLL_EXTENSION: &'static str = "dll";
1699
1700     /// Specifies the filename suffix used for executable binaries on this
1701     /// platform: in this case, `.exe`.
1702     pub static EXE_SUFFIX: &'static str = ".exe";
1703
1704     /// Specifies the file extension, if any, used for executable binaries
1705     /// on this platform: in this case, `exe`.
1706     pub static EXE_EXTENSION: &'static str = "exe";
1707 }
1708
1709 #[cfg(target_arch = "x86")]
1710 mod arch_consts {
1711     pub static ARCH: &'static str = "x86";
1712 }
1713
1714 #[cfg(target_arch = "x86_64")]
1715 mod arch_consts {
1716     pub static ARCH: &'static str = "x86_64";
1717 }
1718
1719 #[cfg(target_arch = "arm")]
1720 mod arch_consts {
1721     pub static ARCH: &'static str = "arm";
1722 }
1723
1724 #[cfg(target_arch = "mips")]
1725 mod arch_consts {
1726     pub static ARCH: &'static str = "mips";
1727 }
1728
1729
1730 #[cfg(test)]
1731 mod tests {
1732     use prelude::*;
1733     use c_str::ToCStr;
1734     use option;
1735     use os::{env, getcwd, getenv, make_absolute};
1736     use os::{split_paths, setenv, unsetenv};
1737     use os;
1738     use rand::Rng;
1739     use rand;
1740
1741     #[test]
1742     pub fn last_os_error() {
1743         debug!("{}", os::last_os_error());
1744     }
1745
1746     fn make_rand_name() -> String {
1747         let mut rng = rand::task_rng();
1748         let n = format!("TEST{}", rng.gen_ascii_chars().take(10u)
1749                                      .collect::<String>());
1750         assert!(getenv(n.as_slice()).is_none());
1751         n
1752     }
1753
1754     #[test]
1755     fn test_setenv() {
1756         let n = make_rand_name();
1757         setenv(n.as_slice(), "VALUE");
1758         assert_eq!(getenv(n.as_slice()), option::Some("VALUE".to_string()));
1759     }
1760
1761     #[test]
1762     fn test_unsetenv() {
1763         let n = make_rand_name();
1764         setenv(n.as_slice(), "VALUE");
1765         unsetenv(n.as_slice());
1766         assert_eq!(getenv(n.as_slice()), option::None);
1767     }
1768
1769     #[test]
1770     #[ignore]
1771     fn test_setenv_overwrite() {
1772         let n = make_rand_name();
1773         setenv(n.as_slice(), "1");
1774         setenv(n.as_slice(), "2");
1775         assert_eq!(getenv(n.as_slice()), option::Some("2".to_string()));
1776         setenv(n.as_slice(), "");
1777         assert_eq!(getenv(n.as_slice()), option::Some("".to_string()));
1778     }
1779
1780     // Windows GetEnvironmentVariable requires some extra work to make sure
1781     // the buffer the variable is copied into is the right size
1782     #[test]
1783     #[ignore]
1784     fn test_getenv_big() {
1785         let mut s = "".to_string();
1786         let mut i = 0;
1787         while i < 100 {
1788             s.push_str("aaaaaaaaaa");
1789             i += 1;
1790         }
1791         let n = make_rand_name();
1792         setenv(n.as_slice(), s.as_slice());
1793         debug!("{}", s.clone());
1794         assert_eq!(getenv(n.as_slice()), option::Some(s));
1795     }
1796
1797     #[test]
1798     fn test_self_exe_name() {
1799         let path = os::self_exe_name();
1800         assert!(path.is_some());
1801         let path = path.unwrap();
1802         debug!("{:?}", path.clone());
1803
1804         // Hard to test this function
1805         assert!(path.is_absolute());
1806     }
1807
1808     #[test]
1809     fn test_self_exe_path() {
1810         let path = os::self_exe_path();
1811         assert!(path.is_some());
1812         let path = path.unwrap();
1813         debug!("{:?}", path.clone());
1814
1815         // Hard to test this function
1816         assert!(path.is_absolute());
1817     }
1818
1819     #[test]
1820     #[ignore]
1821     fn test_env_getenv() {
1822         let e = env();
1823         assert!(e.len() > 0u);
1824         for p in e.iter() {
1825             let (n, v) = (*p).clone();
1826             debug!("{:?}", n.clone());
1827             let v2 = getenv(n.as_slice());
1828             // MingW seems to set some funky environment variables like
1829             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1830             // from env() but not visible from getenv().
1831             assert!(v2.is_none() || v2 == option::Some(v));
1832         }
1833     }
1834
1835     #[test]
1836     fn test_env_set_get_huge() {
1837         let n = make_rand_name();
1838         let s = "x".repeat(10000).to_string();
1839         setenv(n.as_slice(), s.as_slice());
1840         assert_eq!(getenv(n.as_slice()), Some(s));
1841         unsetenv(n.as_slice());
1842         assert_eq!(getenv(n.as_slice()), None);
1843     }
1844
1845     #[test]
1846     fn test_env_setenv() {
1847         let n = make_rand_name();
1848
1849         let mut e = env();
1850         setenv(n.as_slice(), "VALUE");
1851         assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
1852
1853         e = env();
1854         assert!(e.contains(&(n, "VALUE".to_string())));
1855     }
1856
1857     #[test]
1858     fn test() {
1859         assert!((!Path::new("test-path").is_absolute()));
1860
1861         let cwd = getcwd();
1862         debug!("Current working directory: {}", cwd.display());
1863
1864         debug!("{:?}", make_absolute(&Path::new("test-path")));
1865         debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1866     }
1867
1868     #[test]
1869     #[cfg(unix)]
1870     fn homedir() {
1871         let oldhome = getenv("HOME");
1872
1873         setenv("HOME", "/home/MountainView");
1874         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1875
1876         setenv("HOME", "");
1877         assert!(os::homedir().is_none());
1878
1879         for s in oldhome.iter() {
1880             setenv("HOME", s.as_slice());
1881         }
1882     }
1883
1884     #[test]
1885     #[cfg(windows)]
1886     fn homedir() {
1887
1888         let oldhome = getenv("HOME");
1889         let olduserprofile = getenv("USERPROFILE");
1890
1891         setenv("HOME", "");
1892         setenv("USERPROFILE", "");
1893
1894         assert!(os::homedir().is_none());
1895
1896         setenv("HOME", "/home/MountainView");
1897         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1898
1899         setenv("HOME", "");
1900
1901         setenv("USERPROFILE", "/home/MountainView");
1902         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1903
1904         setenv("HOME", "/home/MountainView");
1905         setenv("USERPROFILE", "/home/PaloAlto");
1906         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1907
1908         for s in oldhome.iter() {
1909             setenv("HOME", s.as_slice());
1910         }
1911         for s in olduserprofile.iter() {
1912             setenv("USERPROFILE", s.as_slice());
1913         }
1914     }
1915
1916     #[test]
1917     fn memory_map_rw() {
1918         use result::{Ok, Err};
1919
1920         let chunk = match os::MemoryMap::new(16, [
1921             os::MapReadable,
1922             os::MapWritable
1923         ]) {
1924             Ok(chunk) => chunk,
1925             Err(msg) => fail!("{}", msg)
1926         };
1927         assert!(chunk.len >= 16);
1928
1929         unsafe {
1930             *chunk.data = 0xBE;
1931             assert!(*chunk.data == 0xBE);
1932         }
1933     }
1934
1935     #[test]
1936     fn memory_map_file() {
1937         use result::{Ok, Err};
1938         use os::*;
1939         use libc::*;
1940         use io::fs;
1941
1942         #[cfg(unix)]
1943         fn lseek_(fd: c_int, size: uint) {
1944             unsafe {
1945                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
1946             }
1947         }
1948         #[cfg(windows)]
1949         fn lseek_(fd: c_int, size: uint) {
1950            unsafe {
1951                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
1952            }
1953         }
1954
1955         let mut path = tmpdir();
1956         path.push("mmap_file.tmp");
1957         let size = MemoryMap::granularity() * 2;
1958
1959         let fd = unsafe {
1960             let fd = path.with_c_str(|path| {
1961                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1962             });
1963             lseek_(fd, size);
1964             "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1965             fd
1966         };
1967         let chunk = match MemoryMap::new(size / 2, [
1968             MapReadable,
1969             MapWritable,
1970             MapFd(fd),
1971             MapOffset(size / 2)
1972         ]) {
1973             Ok(chunk) => chunk,
1974             Err(msg) => fail!("{}", msg)
1975         };
1976         assert!(chunk.len > 0);
1977
1978         unsafe {
1979             *chunk.data = 0xbe;
1980             assert!(*chunk.data == 0xbe);
1981             close(fd);
1982         }
1983         drop(chunk);
1984
1985         fs::unlink(&path).unwrap();
1986     }
1987
1988     #[test]
1989     #[cfg(windows)]
1990     fn split_paths_windows() {
1991         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1992             split_paths(unparsed) ==
1993                 parsed.iter().map(|s| Path::new(*s)).collect()
1994         }
1995
1996         assert!(check_parse("", []));
1997         assert!(check_parse(r#""""#, []));
1998         assert!(check_parse(";;", []));
1999         assert!(check_parse(r"c:\", [r"c:\"]));
2000         assert!(check_parse(r"c:\;", [r"c:\"]));
2001         assert!(check_parse(r"c:\;c:\Program Files\",
2002                             [r"c:\", r"c:\Program Files\"]));
2003         assert!(check_parse(r#"c:\;c:\"foo"\"#, [r"c:\", r"c:\foo\"]));
2004         assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
2005                             [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
2006     }
2007
2008     #[test]
2009     #[cfg(unix)]
2010     fn split_paths_unix() {
2011         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
2012             split_paths(unparsed) ==
2013                 parsed.iter().map(|s| Path::new(*s)).collect()
2014         }
2015
2016         assert!(check_parse("", []));
2017         assert!(check_parse("::", []));
2018         assert!(check_parse("/", ["/"]));
2019         assert!(check_parse("/:", ["/"]));
2020         assert!(check_parse("/:/usr/local", ["/", "/usr/local"]));
2021     }
2022
2023     // More recursive_mkdir tests are in extra::tempfile
2024 }