]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
auto merge of #13049 : alexcrichton/rust/io-fill, r=huonw
[rust.git] / src / libstd / os.rs
1 // Copyright 2012-2013 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
31 #[cfg(target_os = "macos")]
32 #[cfg(windows)]
33 use iter::range;
34
35 use clone::Clone;
36 use container::Container;
37 use libc;
38 use libc::{c_char, c_void, c_int};
39 use option::{Some, None, Option};
40 use os;
41 use ops::Drop;
42 use result::{Err, Ok, Result};
43 use ptr;
44 use str;
45 use str::{Str, StrSlice};
46 use fmt;
47 use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
48 use path::{Path, GenericPath};
49 use iter::Iterator;
50 use slice::{Vector, CloneableVector, ImmutableVector, MutableVector, OwnedVector};
51 use ptr::RawPtr;
52
53 #[cfg(unix)]
54 use c_str::ToCStr;
55 #[cfg(windows)]
56 use str::OwnedStr;
57
58 /// Delegates to the libc close() function, returning the same return value.
59 pub fn close(fd: int) -> int {
60     unsafe {
61         libc::close(fd as c_int) as int
62     }
63 }
64
65 pub static TMPBUF_SZ : uint = 1000u;
66 static BUF_BYTES : uint = 2048u;
67
68 #[cfg(unix)]
69 pub fn getcwd() -> Path {
70     use c_str::CString;
71
72     let mut buf = [0 as c_char, ..BUF_BYTES];
73     unsafe {
74         if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
75             fail!()
76         }
77         Path::new(CString::new(buf.as_ptr(), false))
78     }
79 }
80
81 #[cfg(windows)]
82 pub fn getcwd() -> Path {
83     use libc::DWORD;
84     use libc::GetCurrentDirectoryW;
85     let mut buf = [0 as u16, ..BUF_BYTES];
86     unsafe {
87         if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
88             fail!();
89         }
90     }
91     Path::new(str::from_utf16(str::truncate_utf16_at_nul(buf))
92               .expect("GetCurrentDirectoryW returned invalid UTF-16"))
93 }
94
95 #[cfg(windows)]
96 pub mod win32 {
97     use libc::types::os::arch::extra::DWORD;
98     use libc;
99     use option::{None, Option};
100     use option;
101     use os::TMPBUF_SZ;
102     use str::StrSlice;
103     use str;
104     use slice::{MutableVector, ImmutableVector, OwnedVector};
105     use slice;
106
107     pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
108         -> Option<~str> {
109
110         unsafe {
111             let mut n = TMPBUF_SZ as DWORD;
112             let mut res = None;
113             let mut done = false;
114             while !done {
115                 let mut buf = slice::from_elem(n as uint, 0u16);
116                 let k = f(buf.as_mut_ptr(), n);
117                 if k == (0 as DWORD) {
118                     done = true;
119                 } else if k == n &&
120                           libc::GetLastError() ==
121                           libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
122                     n *= 2 as DWORD;
123                 } else if k >= n {
124                     n = k;
125                 } else {
126                     done = true;
127                 }
128                 if k != 0 && done {
129                     let sub = buf.slice(0, k as uint);
130                     // We want to explicitly catch the case when the
131                     // closure returned invalid UTF-16, rather than
132                     // set `res` to None and continue.
133                     let s = str::from_utf16(sub)
134                         .expect("fill_utf16_buf_and_decode: closure created invalid UTF-16");
135                     res = option::Some(s)
136                 }
137             }
138             return res;
139         }
140     }
141
142     pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
143         let mut t = s.to_utf16();
144         // Null terminate before passing on.
145         t.push(0u16);
146         f(t.as_ptr())
147     }
148 }
149
150 /*
151 Accessing environment variables is not generally threadsafe.
152 Serialize access through a global lock.
153 */
154 fn with_env_lock<T>(f: || -> T) -> T {
155     use unstable::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
156
157     static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
158
159     unsafe {
160         let _guard = lock.lock();
161         f()
162     }
163 }
164
165 /// Returns a vector of (variable, value) pairs for all the environment
166 /// variables of the current process.
167 ///
168 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
169 /// for details.
170 pub fn env() -> ~[(~str,~str)] {
171     env_as_bytes().move_iter().map(|(k,v)| {
172         let k = str::from_utf8_lossy(k).into_owned();
173         let v = str::from_utf8_lossy(v).into_owned();
174         (k,v)
175     }).collect()
176 }
177
178 /// Returns a vector of (variable, value) byte-vector pairs for all the
179 /// environment variables of the current process.
180 pub fn env_as_bytes() -> ~[(~[u8],~[u8])] {
181     unsafe {
182         #[cfg(windows)]
183         unsafe fn get_env_pairs() -> ~[~[u8]] {
184             use c_str;
185             use str::StrSlice;
186
187             use libc::funcs::extra::kernel32::{
188                 GetEnvironmentStringsA,
189                 FreeEnvironmentStringsA
190             };
191             let ch = GetEnvironmentStringsA();
192             if ch as uint == 0 {
193                 fail!("os::env() failure getting env string from OS: {}",
194                        os::last_os_error());
195             }
196             let mut result = ~[];
197             c_str::from_c_multistring(ch as *c_char, None, |cstr| {
198                 result.push(cstr.as_bytes_no_nul().to_owned());
199             });
200             FreeEnvironmentStringsA(ch);
201             result
202         }
203         #[cfg(unix)]
204         unsafe fn get_env_pairs() -> ~[~[u8]] {
205             use c_str::CString;
206
207             extern {
208                 fn rust_env_pairs() -> **c_char;
209             }
210             let environ = rust_env_pairs();
211             if environ as uint == 0 {
212                 fail!("os::env() failure getting env string from OS: {}",
213                        os::last_os_error());
214             }
215             let mut result = ~[];
216             ptr::array_each(environ, |e| {
217                 let env_pair = CString::new(e, false).as_bytes_no_nul().to_owned();
218                 result.push(env_pair);
219             });
220             result
221         }
222
223         fn env_convert(input: ~[~[u8]]) -> ~[(~[u8], ~[u8])] {
224             let mut pairs = ~[];
225             for p in input.iter() {
226                 let vs: ~[&[u8]] = p.splitn(1, |b| *b == '=' as u8).collect();
227                 let key = vs[0].to_owned();
228                 let val = if vs.len() < 2 { ~[] } else { vs[1].to_owned() };
229                 pairs.push((key, val));
230             }
231             pairs
232         }
233         with_env_lock(|| {
234             let unparsed_environ = get_env_pairs();
235             env_convert(unparsed_environ)
236         })
237     }
238 }
239
240 #[cfg(unix)]
241 /// Fetches the environment variable `n` from the current process, returning
242 /// None if the variable isn't set.
243 ///
244 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
245 /// `str::from_utf8_lossy()` for details.
246 ///
247 /// # Failure
248 ///
249 /// Fails if `n` has any interior NULs.
250 pub fn getenv(n: &str) -> Option<~str> {
251     getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
252 }
253
254 #[cfg(unix)]
255 /// Fetches the environment variable `n` byte vector from the current process,
256 /// returning None if the variable isn't set.
257 ///
258 /// # Failure
259 ///
260 /// Fails if `n` has any interior NULs.
261 pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
262     use c_str::CString;
263
264     unsafe {
265         with_env_lock(|| {
266             let s = n.with_c_str(|buf| libc::getenv(buf));
267             if s.is_null() {
268                 None
269             } else {
270                 Some(CString::new(s, false).as_bytes_no_nul().to_owned())
271             }
272         })
273     }
274 }
275
276 #[cfg(windows)]
277 /// Fetches the environment variable `n` from the current process, returning
278 /// None if the variable isn't set.
279 pub fn getenv(n: &str) -> Option<~str> {
280     unsafe {
281         with_env_lock(|| {
282             use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
283             as_utf16_p(n, |u| {
284                 fill_utf16_buf_and_decode(|buf, sz| {
285                     libc::GetEnvironmentVariableW(u, buf, sz)
286                 })
287             })
288         })
289     }
290 }
291
292 #[cfg(windows)]
293 /// Fetches the environment variable `n` byte vector from the current process,
294 /// returning None if the variable isn't set.
295 pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
296     getenv(n).map(|s| s.into_bytes())
297 }
298
299
300 #[cfg(unix)]
301 /// Sets the environment variable `n` to the value `v` for the currently running
302 /// process
303 ///
304 /// # Failure
305 ///
306 /// Fails if `n` or `v` have any interior NULs.
307 pub fn setenv(n: &str, v: &str) {
308     unsafe {
309         with_env_lock(|| {
310             n.with_c_str(|nbuf| {
311                 v.with_c_str(|vbuf| {
312                     libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
313                 })
314             })
315         })
316     }
317 }
318
319
320 #[cfg(windows)]
321 /// Sets the environment variable `n` to the value `v` for the currently running
322 /// process
323 pub fn setenv(n: &str, v: &str) {
324     unsafe {
325         with_env_lock(|| {
326             use os::win32::as_utf16_p;
327             as_utf16_p(n, |nbuf| {
328                 as_utf16_p(v, |vbuf| {
329                     libc::SetEnvironmentVariableW(nbuf, vbuf);
330                 })
331             })
332         })
333     }
334 }
335
336 /// Remove a variable from the environment entirely
337 ///
338 /// # Failure
339 ///
340 /// Fails (on unix) if `n` has any interior NULs.
341 pub fn unsetenv(n: &str) {
342     #[cfg(unix)]
343     fn _unsetenv(n: &str) {
344         unsafe {
345             with_env_lock(|| {
346                 n.with_c_str(|nbuf| {
347                     libc::funcs::posix01::unistd::unsetenv(nbuf);
348                 })
349             })
350         }
351     }
352     #[cfg(windows)]
353     fn _unsetenv(n: &str) {
354         unsafe {
355             with_env_lock(|| {
356                 use os::win32::as_utf16_p;
357                 as_utf16_p(n, |nbuf| {
358                     libc::SetEnvironmentVariableW(nbuf, ptr::null());
359                 })
360             })
361         }
362     }
363
364     _unsetenv(n);
365 }
366
367 pub struct Pipe {
368     input: c_int,
369     out: c_int
370 }
371
372 #[cfg(unix)]
373 pub fn pipe() -> Pipe {
374     unsafe {
375         let mut fds = Pipe {input: 0,
376                             out: 0};
377         assert_eq!(libc::pipe(&mut fds.input), 0);
378         return Pipe {input: fds.input, out: fds.out};
379     }
380 }
381
382 #[cfg(windows)]
383 pub fn pipe() -> Pipe {
384     unsafe {
385         // Windows pipes work subtly differently than unix pipes, and their
386         // inheritance has to be handled in a different way that I do not
387         // fully understand. Here we explicitly make the pipe non-inheritable,
388         // which means to pass it to a subprocess they need to be duplicated
389         // first, as in std::run.
390         let mut fds = Pipe {input: 0,
391                     out: 0};
392         let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
393                              (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
394         assert_eq!(res, 0);
395         assert!((fds.input != -1 && fds.input != 0 ));
396         assert!((fds.out != -1 && fds.input != 0));
397         return Pipe {input: fds.input, out: fds.out};
398     }
399 }
400
401 /// Returns the proper dll filename for the given basename of a file.
402 pub fn dll_filename(base: &str) -> ~str {
403     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
404 }
405
406 /// Optionally returns the filesystem path of the current executable which is
407 /// running. If any failure occurs, None is returned.
408 pub fn self_exe_name() -> Option<Path> {
409
410     #[cfg(target_os = "freebsd")]
411     fn load_self() -> Option<~[u8]> {
412         unsafe {
413             use libc::funcs::bsd44::*;
414             use libc::consts::os::extra::*;
415             use slice;
416             let mib = ~[CTL_KERN as c_int,
417                         KERN_PROC as c_int,
418                         KERN_PROC_PATHNAME as c_int, -1 as c_int];
419             let mut sz: libc::size_t = 0;
420             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
421                              ptr::mut_null(), &mut sz, ptr::null(),
422                              0u as libc::size_t);
423             if err != 0 { return None; }
424             if sz == 0 { return None; }
425             let mut v: ~[u8] = slice::with_capacity(sz as uint);
426             let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
427                              v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
428                              0u as libc::size_t);
429             if err != 0 { return None; }
430             if sz == 0 { return None; }
431             v.set_len(sz as uint - 1); // chop off trailing NUL
432             Some(v)
433         }
434     }
435
436     #[cfg(target_os = "linux")]
437     #[cfg(target_os = "android")]
438     fn load_self() -> Option<~[u8]> {
439         use std::io;
440
441         match io::fs::readlink(&Path::new("/proc/self/exe")) {
442             Ok(path) => Some(path.as_vec().to_owned()),
443             Err(..) => None
444         }
445     }
446
447     #[cfg(target_os = "macos")]
448     fn load_self() -> Option<~[u8]> {
449         unsafe {
450             use libc::funcs::extra::_NSGetExecutablePath;
451             use slice;
452             let mut sz: u32 = 0;
453             _NSGetExecutablePath(ptr::mut_null(), &mut sz);
454             if sz == 0 { return None; }
455             let mut v: ~[u8] = slice::with_capacity(sz as uint);
456             let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
457             if err != 0 { return None; }
458             v.set_len(sz as uint - 1); // chop off trailing NUL
459             Some(v)
460         }
461     }
462
463     #[cfg(windows)]
464     fn load_self() -> Option<~[u8]> {
465         use str::OwnedStr;
466
467         unsafe {
468             use os::win32::fill_utf16_buf_and_decode;
469             fill_utf16_buf_and_decode(|buf, sz| {
470                 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
471             }).map(|s| s.into_bytes())
472         }
473     }
474
475     load_self().and_then(Path::new_opt)
476 }
477
478 /// Optionally returns the filesystem path to the current executable which is
479 /// running. Like self_exe_name() but without the binary's name.
480 /// If any failure occurs, None is returned.
481 pub fn self_exe_path() -> Option<Path> {
482     self_exe_name().map(|mut p| { p.pop(); p })
483 }
484
485 /**
486  * Returns the path to the user's home directory, if known.
487  *
488  * On Unix, returns the value of the 'HOME' environment variable if it is set
489  * and not equal to the empty string.
490  *
491  * On Windows, returns the value of the 'HOME' environment variable if it is
492  * set and not equal to the empty string. Otherwise, returns the value of the
493  * 'USERPROFILE' environment variable if it is set and not equal to the empty
494  * string.
495  *
496  * Otherwise, homedir returns option::none.
497  */
498 pub fn homedir() -> Option<Path> {
499     // FIXME (#7188): getenv needs a ~[u8] variant
500     return match getenv("HOME") {
501         Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
502         _ => secondary()
503     };
504
505     #[cfg(unix)]
506     fn secondary() -> Option<Path> {
507         None
508     }
509
510     #[cfg(windows)]
511     fn secondary() -> Option<Path> {
512         getenv("USERPROFILE").and_then(|p| {
513             if !p.is_empty() {
514                 Path::new_opt(p)
515             } else {
516                 None
517             }
518         })
519     }
520 }
521
522 /**
523  * Returns the path to a temporary directory.
524  *
525  * On Unix, returns the value of the 'TMPDIR' environment variable if it is
526  * set and non-empty and '/tmp' otherwise.
527  * On Android, there is no global temporary folder (it is usually allocated
528  * per-app), hence returns '/data/tmp' which is commonly used.
529  *
530  * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
531  * 'USERPROFILE' environment variable  if any are set and not the empty
532  * string. Otherwise, tmpdir returns the path to the Windows directory.
533  */
534 pub fn tmpdir() -> Path {
535     return lookup();
536
537     fn getenv_nonempty(v: &str) -> Option<Path> {
538         match getenv(v) {
539             Some(x) =>
540                 if x.is_empty() {
541                     None
542                 } else {
543                     Path::new_opt(x)
544                 },
545             _ => None
546         }
547     }
548
549     #[cfg(unix)]
550     fn lookup() -> Path {
551         if cfg!(target_os = "android") {
552             Path::new("/data/tmp")
553         } else {
554             getenv_nonempty("TMPDIR").unwrap_or(Path::new("/tmp"))
555         }
556     }
557
558     #[cfg(windows)]
559     fn lookup() -> Path {
560         getenv_nonempty("TMP").or(
561             getenv_nonempty("TEMP").or(
562                 getenv_nonempty("USERPROFILE").or(
563                    getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
564     }
565 }
566
567 /**
568  * Convert a relative path to an absolute path
569  *
570  * If the given path is relative, return it prepended with the current working
571  * directory. If the given path is already an absolute path, return it
572  * as is.
573  */
574 // NB: this is here rather than in path because it is a form of environment
575 // querying; what it does depends on the process working directory, not just
576 // the input paths.
577 pub fn make_absolute(p: &Path) -> Path {
578     if p.is_absolute() {
579         p.clone()
580     } else {
581         let mut ret = getcwd();
582         ret.push(p);
583         ret
584     }
585 }
586
587 /// Changes the current working directory to the specified path, returning
588 /// whether the change was completed successfully or not.
589 pub fn change_dir(p: &Path) -> bool {
590     return chdir(p);
591
592     #[cfg(windows)]
593     fn chdir(p: &Path) -> bool {
594         unsafe {
595             use os::win32::as_utf16_p;
596             return as_utf16_p(p.as_str().unwrap(), |buf| {
597                 libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
598             });
599         }
600     }
601
602     #[cfg(unix)]
603     fn chdir(p: &Path) -> bool {
604         p.with_c_str(|buf| {
605             unsafe {
606                 libc::chdir(buf) == (0 as c_int)
607             }
608         })
609     }
610 }
611
612 #[cfg(unix)]
613 /// Returns the platform-specific value of errno
614 pub fn errno() -> int {
615     #[cfg(target_os = "macos")]
616     #[cfg(target_os = "freebsd")]
617     fn errno_location() -> *c_int {
618         extern {
619             fn __error() -> *c_int;
620         }
621         unsafe {
622             __error()
623         }
624     }
625
626     #[cfg(target_os = "linux")]
627     #[cfg(target_os = "android")]
628     fn errno_location() -> *c_int {
629         extern {
630             fn __errno_location() -> *c_int;
631         }
632         unsafe {
633             __errno_location()
634         }
635     }
636
637     unsafe {
638         (*errno_location()) as int
639     }
640 }
641
642 #[cfg(windows)]
643 /// Returns the platform-specific value of errno
644 pub fn errno() -> uint {
645     use libc::types::os::arch::extra::DWORD;
646
647     #[link_name = "kernel32"]
648     extern "system" {
649         fn GetLastError() -> DWORD;
650     }
651
652     unsafe {
653         GetLastError() as uint
654     }
655 }
656
657 /// Get a string representing the platform-dependent last error
658 pub fn last_os_error() -> ~str {
659     #[cfg(unix)]
660     fn strerror() -> ~str {
661         #[cfg(target_os = "macos")]
662         #[cfg(target_os = "android")]
663         #[cfg(target_os = "freebsd")]
664         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
665                       -> c_int {
666             extern {
667                 fn strerror_r(errnum: c_int, buf: *mut c_char,
668                               buflen: libc::size_t) -> c_int;
669             }
670             unsafe {
671                 strerror_r(errnum, buf, buflen)
672             }
673         }
674
675         // GNU libc provides a non-compliant version of strerror_r by default
676         // and requires macros to instead use the POSIX compliant variant.
677         // So we just use __xpg_strerror_r which is always POSIX compliant
678         #[cfg(target_os = "linux")]
679         fn strerror_r(errnum: c_int, buf: *mut c_char,
680                       buflen: libc::size_t) -> c_int {
681             extern {
682                 fn __xpg_strerror_r(errnum: c_int,
683                                     buf: *mut c_char,
684                                     buflen: libc::size_t)
685                                     -> c_int;
686             }
687             unsafe {
688                 __xpg_strerror_r(errnum, buf, buflen)
689             }
690         }
691
692         let mut buf = [0 as c_char, ..TMPBUF_SZ];
693
694         let p = buf.as_mut_ptr();
695         unsafe {
696             if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
697                 fail!("strerror_r failure");
698             }
699
700             str::raw::from_c_str(p as *c_char)
701         }
702     }
703
704     #[cfg(windows)]
705     fn strerror() -> ~str {
706         use libc::types::os::arch::extra::DWORD;
707         use libc::types::os::arch::extra::LPWSTR;
708         use libc::types::os::arch::extra::LPVOID;
709         use libc::types::os::arch::extra::WCHAR;
710
711         #[link_name = "kernel32"]
712         extern "system" {
713             fn FormatMessageW(flags: DWORD,
714                               lpSrc: LPVOID,
715                               msgId: DWORD,
716                               langId: DWORD,
717                               buf: LPWSTR,
718                               nsize: DWORD,
719                               args: *c_void)
720                               -> DWORD;
721         }
722
723         static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
724         static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
725
726         // This value is calculated from the macro
727         // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
728         let langId = 0x0800 as DWORD;
729         let err = errno() as DWORD;
730
731         let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
732
733         unsafe {
734             let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
735                                      FORMAT_MESSAGE_IGNORE_INSERTS,
736                                      ptr::mut_null(),
737                                      err,
738                                      langId,
739                                      buf.as_mut_ptr(),
740                                      buf.len() as DWORD,
741                                      ptr::null());
742             if res == 0 {
743                 // Sometimes FormatMessageW can fail e.g. system doesn't like langId,
744                 let fm_err = errno();
745                 return format!("OS Error {} (FormatMessageW() returned error {})", err, fm_err);
746             }
747
748             let msg = str::from_utf16(str::truncate_utf16_at_nul(buf));
749             match msg {
750                 Some(msg) => format!("OS Error {}: {}", err, msg),
751                 None => format!("OS Error {} (FormatMessageW() returned invalid UTF-16)", err),
752             }
753         }
754     }
755
756     strerror()
757 }
758
759 static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;
760
761 /**
762  * Sets the process exit code
763  *
764  * Sets the exit code returned by the process if all supervised tasks
765  * terminate successfully (without failing). If the current root task fails
766  * and is supervised by the scheduler then any user-specified exit status is
767  * ignored and the process exits with the default failure status.
768  *
769  * Note that this is not synchronized against modifications of other threads.
770  */
771 pub fn set_exit_status(code: int) {
772     unsafe { EXIT_STATUS.store(code, SeqCst) }
773 }
774
775 /// Fetches the process's current exit code. This defaults to 0 and can change
776 /// by calling `set_exit_status`.
777 pub fn get_exit_status() -> int {
778     unsafe { EXIT_STATUS.load(SeqCst) }
779 }
780
781 #[cfg(target_os = "macos")]
782 unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> ~[~[u8]] {
783     use c_str::CString;
784
785     let mut args = ~[];
786     for i in range(0u, argc as uint) {
787         args.push(CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_owned())
788     }
789     args
790 }
791
792 /**
793  * Returns the command line arguments
794  *
795  * Returns a list of the command line arguments.
796  */
797 #[cfg(target_os = "macos")]
798 fn real_args_as_bytes() -> ~[~[u8]] {
799     unsafe {
800         let (argc, argv) = (*_NSGetArgc() as int,
801                             *_NSGetArgv() as **c_char);
802         load_argc_and_argv(argc, argv)
803     }
804 }
805
806 #[cfg(target_os = "linux")]
807 #[cfg(target_os = "android")]
808 #[cfg(target_os = "freebsd")]
809 fn real_args_as_bytes() -> ~[~[u8]] {
810     use rt;
811
812     match rt::args::clone() {
813         Some(args) => args,
814         None => fail!("process arguments not initialized")
815     }
816 }
817
818 #[cfg(not(windows))]
819 fn real_args() -> ~[~str] {
820     real_args_as_bytes().move_iter().map(|v| str::from_utf8_lossy(v).into_owned()).collect()
821 }
822
823 #[cfg(windows)]
824 fn real_args() -> ~[~str] {
825     use slice;
826
827     let mut nArgs: c_int = 0;
828     let lpArgCount: *mut c_int = &mut nArgs;
829     let lpCmdLine = unsafe { GetCommandLineW() };
830     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
831
832     let mut args = ~[];
833     for i in range(0u, nArgs as uint) {
834         unsafe {
835             // Determine the length of this argument.
836             let ptr = *szArgList.offset(i as int);
837             let mut len = 0;
838             while *ptr.offset(len as int) != 0 { len += 1; }
839
840             // Push it onto the list.
841             let opt_s = slice::raw::buf_as_slice(ptr, len, |buf| {
842                     str::from_utf16(str::truncate_utf16_at_nul(buf))
843                 });
844             args.push(opt_s.expect("CommandLineToArgvW returned invalid UTF-16"));
845         }
846     }
847
848     unsafe {
849         LocalFree(szArgList as *c_void);
850     }
851
852     return args;
853 }
854
855 #[cfg(windows)]
856 fn real_args_as_bytes() -> ~[~[u8]] {
857     real_args().move_iter().map(|s| s.into_bytes()).collect()
858 }
859
860 type LPCWSTR = *u16;
861
862 #[cfg(windows)]
863 #[link_name="kernel32"]
864 extern "system" {
865     fn GetCommandLineW() -> LPCWSTR;
866     fn LocalFree(ptr: *c_void);
867 }
868
869 #[cfg(windows)]
870 #[link_name="shell32"]
871 extern "system" {
872     fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
873 }
874
875 /// Returns the arguments which this program was started with (normally passed
876 /// via the command line).
877 ///
878 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
879 /// See `str::from_utf8_lossy` for details.
880 pub fn args() -> ~[~str] {
881     real_args()
882 }
883
884 /// Returns the arguments which this program was started with (normally passed
885 /// via the command line) as byte vectors.
886 pub fn args_as_bytes() -> ~[~[u8]] {
887     real_args_as_bytes()
888 }
889
890 #[cfg(target_os = "macos")]
891 extern {
892     // These functions are in crt_externs.h.
893     pub fn _NSGetArgc() -> *c_int;
894     pub fn _NSGetArgv() -> ***c_char;
895 }
896
897 // Round up `from` to be divisible by `to`
898 fn round_up(from: uint, to: uint) -> uint {
899     let r = if from % to == 0 {
900         from
901     } else {
902         from + to - (from % to)
903     };
904     if r == 0 {
905         to
906     } else {
907         r
908     }
909 }
910
911 #[cfg(unix)]
912 pub fn page_size() -> uint {
913     unsafe {
914         libc::sysconf(libc::_SC_PAGESIZE) as uint
915     }
916 }
917
918 #[cfg(windows)]
919 pub fn page_size() -> uint {
920     unsafe {
921         let mut info = libc::SYSTEM_INFO::new();
922         libc::GetSystemInfo(&mut info);
923
924         return info.dwPageSize as uint;
925     }
926 }
927
928 /// A memory mapped file or chunk of memory. This is a very system-specific
929 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
930 /// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
931 /// abstracting platform differences, besides in error values returned. Consider
932 /// yourself warned.
933 ///
934 /// The memory map is released (unmapped) when the destructor is run, so don't
935 /// let it leave scope by accident if you want it to stick around.
936 pub struct MemoryMap {
937     /// Pointer to the memory created or modified by this map.
938     data: *mut u8,
939     /// Number of bytes this map applies to
940     len: uint,
941     /// Type of mapping
942     kind: MemoryMapKind
943 }
944
945 /// Type of memory map
946 pub enum MemoryMapKind {
947     /// Virtual memory map. Usually used to change the permissions of a given
948     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
949     MapFile(*u8),
950     /// Virtual memory map. Usually used to change the permissions of a given
951     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
952     /// Windows.
953     MapVirtual
954 }
955
956 /// Options the memory map is created with
957 pub enum MapOption {
958     /// The memory should be readable
959     MapReadable,
960     /// The memory should be writable
961     MapWritable,
962     /// The memory should be executable
963     MapExecutable,
964     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
965     /// POSIX.
966     MapAddr(*u8),
967     /// Create a memory mapping for a file with a given fd.
968     MapFd(c_int),
969     /// When using `MapFd`, the start of the map is `uint` bytes from the start
970     /// of the file.
971     MapOffset(uint),
972     /// On POSIX, this can be used to specify the default flags passed to
973     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
974     /// `MAP_ANON`. This will override both of those. This is platform-specific
975     /// (the exact values used) and ignored on Windows.
976     MapNonStandardFlags(c_int),
977 }
978
979 /// Possible errors when creating a map.
980 pub enum MapError {
981     /// ## The following are POSIX-specific
982     ///
983     /// fd was not open for reading or, if using `MapWritable`, was not open for
984     /// writing.
985     ErrFdNotAvail,
986     /// fd was not valid
987     ErrInvalidFd,
988     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
989     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
990     ErrUnaligned,
991     /// With `MapFd`, the fd does not support mapping.
992     ErrNoMapSupport,
993     /// If using `MapAddr`, the address + `min_len` was outside of the process's
994     /// address space. If using `MapFd`, the target of the fd didn't have enough
995     /// resources to fulfill the request.
996     ErrNoMem,
997     /// A zero-length map was requested. This is invalid according to
998     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
999     /// Not all platforms obey this, but this wrapper does.
1000     ErrZeroLength,
1001     /// Unrecognized error. The inner value is the unrecognized errno.
1002     ErrUnknown(int),
1003     /// ## The following are win32-specific
1004     ///
1005     /// Unsupported combination of protection flags
1006     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
1007     ErrUnsupProt,
1008     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
1009     /// at all)
1010     ErrUnsupOffset,
1011     /// When using `MapFd`, there was already a mapping to the file.
1012     ErrAlreadyExists,
1013     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
1014     /// value of GetLastError.
1015     ErrVirtualAlloc(uint),
1016     /// Unrecognized error from `CreateFileMapping`. The inner value is the
1017     /// return value of `GetLastError`.
1018     ErrCreateFileMappingW(uint),
1019     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
1020     /// value of `GetLastError`.
1021     ErrMapViewOfFile(uint)
1022 }
1023
1024 impl fmt::Show for MapError {
1025     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
1026         let str = match *self {
1027             ErrFdNotAvail => "fd not available for reading or writing",
1028             ErrInvalidFd => "Invalid fd",
1029             ErrUnaligned => {
1030                 "Unaligned address, invalid flags, negative length or \
1031                  unaligned offset"
1032             }
1033             ErrNoMapSupport=> "File doesn't support mapping",
1034             ErrNoMem => "Invalid address, or not enough available memory",
1035             ErrUnsupProt => "Protection mode unsupported",
1036             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
1037             ErrAlreadyExists => "File mapping for specified file already exists",
1038             ErrZeroLength => "Zero-length mapping not allowed",
1039             ErrUnknown(code) => {
1040                 return write!(out.buf, "Unknown error = {}", code)
1041             },
1042             ErrVirtualAlloc(code) => {
1043                 return write!(out.buf, "VirtualAlloc failure = {}", code)
1044             },
1045             ErrCreateFileMappingW(code) => {
1046                 return write!(out.buf, "CreateFileMappingW failure = {}", code)
1047             },
1048             ErrMapViewOfFile(code) => {
1049                 return write!(out.buf, "MapViewOfFile failure = {}", code)
1050             }
1051         };
1052         write!(out.buf, "{}", str)
1053     }
1054 }
1055
1056 #[cfg(unix)]
1057 impl MemoryMap {
1058     /// Create a new mapping with the given `options`, at least `min_len` bytes
1059     /// long. `min_len` must be greater than zero; see the note on
1060     /// `ErrZeroLength`.
1061     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1062         use libc::off_t;
1063         use cmp::Equiv;
1064
1065         if min_len == 0 {
1066             return Err(ErrZeroLength)
1067         }
1068         let mut addr: *u8 = ptr::null();
1069         let mut prot = 0;
1070         let mut flags = libc::MAP_PRIVATE;
1071         let mut fd = -1;
1072         let mut offset = 0;
1073         let mut custom_flags = false;
1074         let len = round_up(min_len, page_size());
1075
1076         for &o in options.iter() {
1077             match o {
1078                 MapReadable => { prot |= libc::PROT_READ; },
1079                 MapWritable => { prot |= libc::PROT_WRITE; },
1080                 MapExecutable => { prot |= libc::PROT_EXEC; },
1081                 MapAddr(addr_) => {
1082                     flags |= libc::MAP_FIXED;
1083                     addr = addr_;
1084                 },
1085                 MapFd(fd_) => {
1086                     flags |= libc::MAP_FILE;
1087                     fd = fd_;
1088                 },
1089                 MapOffset(offset_) => { offset = offset_ as off_t; },
1090                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1091             }
1092         }
1093         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1094
1095         let r = unsafe {
1096             libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
1097                        offset)
1098         };
1099         if r.equiv(&libc::MAP_FAILED) {
1100             Err(match errno() as c_int {
1101                 libc::EACCES => ErrFdNotAvail,
1102                 libc::EBADF => ErrInvalidFd,
1103                 libc::EINVAL => ErrUnaligned,
1104                 libc::ENODEV => ErrNoMapSupport,
1105                 libc::ENOMEM => ErrNoMem,
1106                 code => ErrUnknown(code as int)
1107             })
1108         } else {
1109             Ok(MemoryMap {
1110                data: r as *mut u8,
1111                len: len,
1112                kind: if fd == -1 {
1113                    MapVirtual
1114                } else {
1115                    MapFile(ptr::null())
1116                }
1117             })
1118         }
1119     }
1120
1121     /// Granularity that the offset or address must be for `MapOffset` and
1122     /// `MapAddr` respectively.
1123     pub fn granularity() -> uint {
1124         page_size()
1125     }
1126 }
1127
1128 #[cfg(unix)]
1129 impl Drop for MemoryMap {
1130     /// Unmap the mapping. Fails the task if `munmap` fails.
1131     fn drop(&mut self) {
1132         if self.len == 0 { /* workaround for dummy_stack */ return; }
1133
1134         unsafe {
1135             // FIXME: what to do if this fails?
1136             let _ = libc::munmap(self.data as *c_void, self.len as libc::size_t);
1137         }
1138     }
1139 }
1140
1141 #[cfg(windows)]
1142 impl MemoryMap {
1143     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1144     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1145         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1146
1147         let mut lpAddress: LPVOID = ptr::mut_null();
1148         let mut readable = false;
1149         let mut writable = false;
1150         let mut executable = false;
1151         let mut fd: c_int = -1;
1152         let mut offset: uint = 0;
1153         let len = round_up(min_len, page_size());
1154
1155         for &o in options.iter() {
1156             match o {
1157                 MapReadable => { readable = true; },
1158                 MapWritable => { writable = true; },
1159                 MapExecutable => { executable = true; }
1160                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1161                 MapFd(fd_) => { fd = fd_; },
1162                 MapOffset(offset_) => { offset = offset_; },
1163                 MapNonStandardFlags(..) => {}
1164             }
1165         }
1166
1167         let flProtect = match (executable, readable, writable) {
1168             (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1169             (false, true, false) => libc::PAGE_READONLY,
1170             (false, true, true) => libc::PAGE_READWRITE,
1171             (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1172             (true, true, false) => libc::PAGE_EXECUTE_READ,
1173             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1174             _ => return Err(ErrUnsupProt)
1175         };
1176
1177         if fd == -1 {
1178             if offset != 0 {
1179                 return Err(ErrUnsupOffset);
1180             }
1181             let r = unsafe {
1182                 libc::VirtualAlloc(lpAddress,
1183                                    len as SIZE_T,
1184                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1185                                    flProtect)
1186             };
1187             match r as uint {
1188                 0 => Err(ErrVirtualAlloc(errno())),
1189                 _ => Ok(MemoryMap {
1190                    data: r as *mut u8,
1191                    len: len,
1192                    kind: MapVirtual
1193                 })
1194             }
1195         } else {
1196             let dwDesiredAccess = match (executable, readable, writable) {
1197                 (false, true, false) => libc::FILE_MAP_READ,
1198                 (false, true, true) => libc::FILE_MAP_WRITE,
1199                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1200                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1201                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1202                                               // we should never get here.
1203             };
1204             unsafe {
1205                 let hFile = libc::get_osfhandle(fd) as HANDLE;
1206                 let mapping = libc::CreateFileMappingW(hFile,
1207                                                        ptr::mut_null(),
1208                                                        flProtect,
1209                                                        0,
1210                                                        0,
1211                                                        ptr::null());
1212                 if mapping == ptr::mut_null() {
1213                     return Err(ErrCreateFileMappingW(errno()));
1214                 }
1215                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1216                     return Err(ErrAlreadyExists);
1217                 }
1218                 let r = libc::MapViewOfFile(mapping,
1219                                             dwDesiredAccess,
1220                                             ((len as u64) >> 32) as DWORD,
1221                                             (offset & 0xffff_ffff) as DWORD,
1222                                             0);
1223                 match r as uint {
1224                     0 => Err(ErrMapViewOfFile(errno())),
1225                     _ => Ok(MemoryMap {
1226                        data: r as *mut u8,
1227                        len: len,
1228                        kind: MapFile(mapping as *u8)
1229                     })
1230                 }
1231             }
1232         }
1233     }
1234
1235     /// Granularity of MapAddr() and MapOffset() parameter values.
1236     /// This may be greater than the value returned by page_size().
1237     pub fn granularity() -> uint {
1238         unsafe {
1239             let mut info = libc::SYSTEM_INFO::new();
1240             libc::GetSystemInfo(&mut info);
1241
1242             return info.dwAllocationGranularity as uint;
1243         }
1244     }
1245 }
1246
1247 #[cfg(windows)]
1248 impl Drop for MemoryMap {
1249     /// Unmap the mapping. Fails the task if any of `VirtualFree`,
1250     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1251     fn drop(&mut self) {
1252         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1253         use libc::consts::os::extra::FALSE;
1254         if self.len == 0 { return }
1255
1256         unsafe {
1257             match self.kind {
1258                 MapVirtual => {
1259                     if libc::VirtualFree(self.data as *mut c_void, 0,
1260                                          libc::MEM_RELEASE) == 0 {
1261                         println!("VirtualFree failed: {}", errno());
1262                     }
1263                 },
1264                 MapFile(mapping) => {
1265                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1266                         println!("UnmapViewOfFile failed: {}", errno());
1267                     }
1268                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1269                         println!("CloseHandle failed: {}", errno());
1270                     }
1271                 }
1272             }
1273         }
1274     }
1275 }
1276
1277 pub mod consts {
1278
1279     #[cfg(unix)]
1280     pub use os::consts::unix::*;
1281
1282     #[cfg(windows)]
1283     pub use os::consts::windows::*;
1284
1285     #[cfg(target_os = "macos")]
1286     pub use os::consts::macos::*;
1287
1288     #[cfg(target_os = "freebsd")]
1289     pub use os::consts::freebsd::*;
1290
1291     #[cfg(target_os = "linux")]
1292     pub use os::consts::linux::*;
1293
1294     #[cfg(target_os = "android")]
1295     pub use os::consts::android::*;
1296
1297     #[cfg(target_os = "win32")]
1298     pub use os::consts::win32::*;
1299
1300     #[cfg(target_arch = "x86")]
1301     pub use os::consts::x86::*;
1302
1303     #[cfg(target_arch = "x86_64")]
1304     pub use os::consts::x86_64::*;
1305
1306     #[cfg(target_arch = "arm")]
1307     pub use os::consts::arm::*;
1308
1309     #[cfg(target_arch = "mips")]
1310     pub use os::consts::mips::*;
1311
1312     pub mod unix {
1313         pub static FAMILY: &'static str = "unix";
1314     }
1315
1316     pub mod windows {
1317         pub static FAMILY: &'static str = "windows";
1318     }
1319
1320     pub mod macos {
1321         pub static SYSNAME: &'static str = "macos";
1322         pub static DLL_PREFIX: &'static str = "lib";
1323         pub static DLL_SUFFIX: &'static str = ".dylib";
1324         pub static DLL_EXTENSION: &'static str = "dylib";
1325         pub static EXE_SUFFIX: &'static str = "";
1326         pub static EXE_EXTENSION: &'static str = "";
1327     }
1328
1329     pub mod freebsd {
1330         pub static SYSNAME: &'static str = "freebsd";
1331         pub static DLL_PREFIX: &'static str = "lib";
1332         pub static DLL_SUFFIX: &'static str = ".so";
1333         pub static DLL_EXTENSION: &'static str = "so";
1334         pub static EXE_SUFFIX: &'static str = "";
1335         pub static EXE_EXTENSION: &'static str = "";
1336     }
1337
1338     pub mod linux {
1339         pub static SYSNAME: &'static str = "linux";
1340         pub static DLL_PREFIX: &'static str = "lib";
1341         pub static DLL_SUFFIX: &'static str = ".so";
1342         pub static DLL_EXTENSION: &'static str = "so";
1343         pub static EXE_SUFFIX: &'static str = "";
1344         pub static EXE_EXTENSION: &'static str = "";
1345     }
1346
1347     pub mod android {
1348         pub static SYSNAME: &'static str = "android";
1349         pub static DLL_PREFIX: &'static str = "lib";
1350         pub static DLL_SUFFIX: &'static str = ".so";
1351         pub static DLL_EXTENSION: &'static str = "so";
1352         pub static EXE_SUFFIX: &'static str = "";
1353         pub static EXE_EXTENSION: &'static str = "";
1354     }
1355
1356     pub mod win32 {
1357         pub static SYSNAME: &'static str = "win32";
1358         pub static DLL_PREFIX: &'static str = "";
1359         pub static DLL_SUFFIX: &'static str = ".dll";
1360         pub static DLL_EXTENSION: &'static str = "dll";
1361         pub static EXE_SUFFIX: &'static str = ".exe";
1362         pub static EXE_EXTENSION: &'static str = "exe";
1363     }
1364
1365
1366     pub mod x86 {
1367         pub static ARCH: &'static str = "x86";
1368     }
1369     pub mod x86_64 {
1370         pub static ARCH: &'static str = "x86_64";
1371     }
1372     pub mod arm {
1373         pub static ARCH: &'static str = "arm";
1374     }
1375     pub mod mips {
1376         pub static ARCH: &'static str = "mips";
1377     }
1378 }
1379
1380 #[cfg(test)]
1381 mod tests {
1382     use prelude::*;
1383     use c_str::ToCStr;
1384     use option;
1385     use os::{env, getcwd, getenv, make_absolute, args};
1386     use os::{setenv, unsetenv};
1387     use os;
1388     use rand::Rng;
1389     use rand;
1390
1391     #[test]
1392     pub fn last_os_error() {
1393         debug!("{}", os::last_os_error());
1394     }
1395
1396     #[test]
1397     pub fn test_args() {
1398         let a = args();
1399         assert!(a.len() >= 1);
1400     }
1401
1402     fn make_rand_name() -> ~str {
1403         let mut rng = rand::task_rng();
1404         let n = ~"TEST" + rng.gen_ascii_str(10u);
1405         assert!(getenv(n).is_none());
1406         n
1407     }
1408
1409     #[test]
1410     fn test_setenv() {
1411         let n = make_rand_name();
1412         setenv(n, "VALUE");
1413         assert_eq!(getenv(n), option::Some(~"VALUE"));
1414     }
1415
1416     #[test]
1417     fn test_unsetenv() {
1418         let n = make_rand_name();
1419         setenv(n, "VALUE");
1420         unsetenv(n);
1421         assert_eq!(getenv(n), option::None);
1422     }
1423
1424     #[test]
1425     #[ignore]
1426     fn test_setenv_overwrite() {
1427         let n = make_rand_name();
1428         setenv(n, "1");
1429         setenv(n, "2");
1430         assert_eq!(getenv(n), option::Some(~"2"));
1431         setenv(n, "");
1432         assert_eq!(getenv(n), option::Some(~""));
1433     }
1434
1435     // Windows GetEnvironmentVariable requires some extra work to make sure
1436     // the buffer the variable is copied into is the right size
1437     #[test]
1438     #[ignore]
1439     fn test_getenv_big() {
1440         let mut s = ~"";
1441         let mut i = 0;
1442         while i < 100 {
1443             s = s + "aaaaaaaaaa";
1444             i += 1;
1445         }
1446         let n = make_rand_name();
1447         setenv(n, s);
1448         debug!("{}", s.clone());
1449         assert_eq!(getenv(n), option::Some(s));
1450     }
1451
1452     #[test]
1453     fn test_self_exe_name() {
1454         let path = os::self_exe_name();
1455         assert!(path.is_some());
1456         let path = path.unwrap();
1457         debug!("{:?}", path.clone());
1458
1459         // Hard to test this function
1460         assert!(path.is_absolute());
1461     }
1462
1463     #[test]
1464     fn test_self_exe_path() {
1465         let path = os::self_exe_path();
1466         assert!(path.is_some());
1467         let path = path.unwrap();
1468         debug!("{:?}", path.clone());
1469
1470         // Hard to test this function
1471         assert!(path.is_absolute());
1472     }
1473
1474     #[test]
1475     #[ignore]
1476     fn test_env_getenv() {
1477         let e = env();
1478         assert!(e.len() > 0u);
1479         for p in e.iter() {
1480             let (n, v) = (*p).clone();
1481             debug!("{:?}", n.clone());
1482             let v2 = getenv(n);
1483             // MingW seems to set some funky environment variables like
1484             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1485             // from env() but not visible from getenv().
1486             assert!(v2.is_none() || v2 == option::Some(v));
1487         }
1488     }
1489
1490     #[test]
1491     fn test_env_set_get_huge() {
1492         let n = make_rand_name();
1493         let s = "x".repeat(10000);
1494         setenv(n, s);
1495         assert_eq!(getenv(n), Some(s));
1496         unsetenv(n);
1497         assert_eq!(getenv(n), None);
1498     }
1499
1500     #[test]
1501     fn test_env_setenv() {
1502         let n = make_rand_name();
1503
1504         let mut e = env();
1505         setenv(n, "VALUE");
1506         assert!(!e.contains(&(n.clone(), ~"VALUE")));
1507
1508         e = env();
1509         assert!(e.contains(&(n, ~"VALUE")));
1510     }
1511
1512     #[test]
1513     fn test() {
1514         assert!((!Path::new("test-path").is_absolute()));
1515
1516         let cwd = getcwd();
1517         debug!("Current working directory: {}", cwd.display());
1518
1519         debug!("{:?}", make_absolute(&Path::new("test-path")));
1520         debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1521     }
1522
1523     #[test]
1524     #[cfg(unix)]
1525     fn homedir() {
1526         let oldhome = getenv("HOME");
1527
1528         setenv("HOME", "/home/MountainView");
1529         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1530
1531         setenv("HOME", "");
1532         assert!(os::homedir().is_none());
1533
1534         for s in oldhome.iter() { setenv("HOME", *s) }
1535     }
1536
1537     #[test]
1538     #[cfg(windows)]
1539     fn homedir() {
1540
1541         let oldhome = getenv("HOME");
1542         let olduserprofile = getenv("USERPROFILE");
1543
1544         setenv("HOME", "");
1545         setenv("USERPROFILE", "");
1546
1547         assert!(os::homedir().is_none());
1548
1549         setenv("HOME", "/home/MountainView");
1550         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1551
1552         setenv("HOME", "");
1553
1554         setenv("USERPROFILE", "/home/MountainView");
1555         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1556
1557         setenv("HOME", "/home/MountainView");
1558         setenv("USERPROFILE", "/home/PaloAlto");
1559         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1560
1561         for s in oldhome.iter() { setenv("HOME", *s) }
1562         for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
1563     }
1564
1565     #[test]
1566     fn memory_map_rw() {
1567         use result::{Ok, Err};
1568
1569         let chunk = match os::MemoryMap::new(16, [
1570             os::MapReadable,
1571             os::MapWritable
1572         ]) {
1573             Ok(chunk) => chunk,
1574             Err(msg) => fail!("{}", msg)
1575         };
1576         assert!(chunk.len >= 16);
1577
1578         unsafe {
1579             *chunk.data = 0xBE;
1580             assert!(*chunk.data == 0xBE);
1581         }
1582     }
1583
1584     #[test]
1585     fn memory_map_file() {
1586         use result::{Ok, Err};
1587         use os::*;
1588         use libc::*;
1589         use io::fs;
1590
1591         #[cfg(unix)]
1592         fn lseek_(fd: c_int, size: uint) {
1593             unsafe {
1594                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
1595             }
1596         }
1597         #[cfg(windows)]
1598         fn lseek_(fd: c_int, size: uint) {
1599            unsafe {
1600                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
1601            }
1602         }
1603
1604         let mut path = tmpdir();
1605         path.push("mmap_file.tmp");
1606         let size = MemoryMap::granularity() * 2;
1607
1608         let fd = unsafe {
1609             let fd = path.with_c_str(|path| {
1610                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1611             });
1612             lseek_(fd, size);
1613             "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1614             fd
1615         };
1616         let chunk = match MemoryMap::new(size / 2, [
1617             MapReadable,
1618             MapWritable,
1619             MapFd(fd),
1620             MapOffset(size / 2)
1621         ]) {
1622             Ok(chunk) => chunk,
1623             Err(msg) => fail!("{}", msg)
1624         };
1625         assert!(chunk.len > 0);
1626
1627         unsafe {
1628             *chunk.data = 0xbe;
1629             assert!(*chunk.data == 0xbe);
1630             close(fd);
1631         }
1632         drop(chunk);
1633
1634         fs::unlink(&path).unwrap();
1635     }
1636
1637     // More recursive_mkdir tests are in extra::tempfile
1638 }