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