]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
Merge remote-tracking branch 'remotes/origin/master' into str-remove-null
[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 use c_str::ToCStr;
32 use clone::Clone;
33 use container::Container;
34 use io;
35 use iterator::{IteratorUtil, range};
36 use libc;
37 use libc::{c_char, c_void, c_int, size_t};
38 use libc::FILE;
39 use local_data;
40 use option::{Some, None};
41 use os;
42 use prelude::*;
43 use ptr;
44 use str;
45 use to_str;
46 use unstable::finally::Finally;
47 use vec;
48
49 pub use libc::fclose;
50 pub use os::consts::*;
51
52 /// Delegates to the libc close() function, returning the same return value.
53 pub fn close(fd: c_int) -> c_int {
54     unsafe {
55         libc::close(fd)
56     }
57 }
58
59 pub mod rustrt {
60     use libc::{c_char, c_int};
61     use libc;
62
63     extern {
64         pub fn rust_get_argc() -> c_int;
65         pub fn rust_get_argv() -> **c_char;
66         pub fn rust_path_is_dir(path: *libc::c_char) -> c_int;
67         pub fn rust_path_exists(path: *libc::c_char) -> c_int;
68         pub fn rust_set_exit_status(code: libc::intptr_t);
69     }
70 }
71
72 pub static TMPBUF_SZ : uint = 1000u;
73 static BUF_BYTES : uint = 2048u;
74
75 pub fn getcwd() -> Path {
76     let mut buf = [0 as libc::c_char, ..BUF_BYTES];
77     do buf.as_mut_buf |buf, len| {
78         unsafe {
79             if libc::getcwd(buf, len as size_t).is_null() {
80                 fail!()
81             }
82
83             Path(str::raw::from_c_str(buf as *c_char))
84         }
85     }
86 }
87
88 // FIXME: move these to str perhaps? #2620
89
90 pub fn fill_charp_buf(f: &fn(*mut c_char, size_t) -> bool) -> Option<~str> {
91     let mut buf = [0 as c_char, .. TMPBUF_SZ];
92     do buf.as_mut_buf |b, sz| {
93         if f(b, sz as size_t) {
94             unsafe {
95                 Some(str::raw::from_c_str(b as *c_char))
96             }
97         } else {
98             None
99         }
100     }
101 }
102
103 #[cfg(windows)]
104 pub mod win32 {
105     use libc;
106     use vec;
107     use str;
108     use option::{None, Option};
109     use option;
110     use os::TMPBUF_SZ;
111     use libc::types::os::arch::extra::DWORD;
112
113     pub fn fill_utf16_buf_and_decode(f: &fn(*mut u16, DWORD) -> DWORD)
114         -> Option<~str> {
115         unsafe {
116             let mut n = TMPBUF_SZ as DWORD;
117             let mut res = None;
118             let mut done = false;
119             while !done {
120                 let mut k: DWORD = 0;
121                 let mut buf = vec::from_elem(n as uint, 0u16);
122                 do buf.as_mut_buf |b, _sz| {
123                     k = f(b, TMPBUF_SZ as DWORD);
124                     if k == (0 as DWORD) {
125                         done = true;
126                     } else if (k == n &&
127                                libc::GetLastError() ==
128                                libc::ERROR_INSUFFICIENT_BUFFER as DWORD) {
129                         n *= (2 as DWORD);
130                     } else {
131                         done = true;
132                     }
133                 }
134                 if k != 0 && done {
135                     let sub = buf.slice(0, k as uint);
136                     res = option::Some(str::from_utf16(sub));
137                 }
138             }
139             return res;
140         }
141     }
142
143     pub fn as_utf16_p<T>(s: &str, f: &fn(*u16) -> T) -> T {
144         let mut t = s.to_utf16();
145         // Null terminate before passing on.
146         t.push(0u16);
147         t.as_imm_buf(|buf, _len| f(buf))
148     }
149 }
150
151 /*
152 Accessing environment variables is not generally threadsafe.
153 Serialize access through a global lock.
154 */
155 fn with_env_lock<T>(f: &fn() -> T) -> T {
156     use unstable::finally::Finally;
157
158     unsafe {
159         return do (|| {
160             rust_take_env_lock();
161             f()
162         }).finally {
163             rust_drop_env_lock();
164         };
165     }
166
167     extern {
168         #[fast_ffi]
169         fn rust_take_env_lock();
170         #[fast_ffi]
171         fn rust_drop_env_lock();
172     }
173 }
174
175 /// Returns a vector of (variable, value) pairs for all the environment
176 /// variables of the current process.
177 pub fn env() -> ~[(~str,~str)] {
178     unsafe {
179         #[cfg(windows)]
180         unsafe fn get_env_pairs() -> ~[~str] {
181             use libc::funcs::extra::kernel32::{
182                 GetEnvironmentStringsA,
183                 FreeEnvironmentStringsA
184             };
185             let ch = GetEnvironmentStringsA();
186             if (ch as uint == 0) {
187                 fail!("os::env() failure getting env string from OS: %s", os::last_os_error());
188             }
189             let mut curr_ptr: uint = ch as uint;
190             let mut result = ~[];
191             while(*(curr_ptr as *libc::c_char) != 0 as libc::c_char) {
192                 let env_pair = str::raw::from_c_str(
193                     curr_ptr as *libc::c_char);
194                 result.push(env_pair);
195                 curr_ptr +=
196                     libc::strlen(curr_ptr as *libc::c_char) as uint
197                     + 1;
198             }
199             FreeEnvironmentStringsA(ch);
200             result
201         }
202         #[cfg(unix)]
203         unsafe fn get_env_pairs() -> ~[~str] {
204             extern {
205                 fn rust_env_pairs() -> **libc::c_char;
206             }
207             let environ = rust_env_pairs();
208             if (environ as uint == 0) {
209                 fail!("os::env() failure getting env string from OS: %s", os::last_os_error());
210             }
211             let mut result = ~[];
212             ptr::array_each(environ, |e| {
213                 let env_pair = str::raw::from_c_str(e);
214                 debug!("get_env_pairs: %s",
215                        env_pair);
216                 result.push(env_pair);
217             });
218             result
219         }
220
221         fn env_convert(input: ~[~str]) -> ~[(~str, ~str)] {
222             let mut pairs = ~[];
223             for p in input.iter() {
224                 let vs: ~[&str] = p.splitn_iter('=', 1).collect();
225                 debug!("splitting: len: %u",
226                     vs.len());
227                 assert_eq!(vs.len(), 2);
228                 pairs.push((vs[0].to_owned(), vs[1].to_owned()));
229             }
230             pairs
231         }
232         do with_env_lock {
233             let unparsed_environ = get_env_pairs();
234             env_convert(unparsed_environ)
235         }
236     }
237 }
238
239 #[cfg(unix)]
240 /// Fetches the environment variable `n` from the current process, returning
241 /// None if the variable isn't set.
242 pub fn getenv(n: &str) -> Option<~str> {
243     unsafe {
244         do with_env_lock {
245             let s = do n.to_c_str().with_ref |buf| {
246                 libc::getenv(buf)
247             };
248             if s.is_null() {
249                 None
250             } else {
251                 Some(str::raw::from_c_str(s))
252             }
253         }
254     }
255 }
256
257 #[cfg(windows)]
258 /// Fetches the environment variable `n` from the current process, returning
259 /// None if the variable isn't set.
260 pub fn getenv(n: &str) -> Option<~str> {
261     unsafe {
262         do with_env_lock {
263             use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
264             do as_utf16_p(n) |u| {
265                 do fill_utf16_buf_and_decode() |buf, sz| {
266                     libc::GetEnvironmentVariableW(u, buf, sz)
267                 }
268             }
269         }
270     }
271 }
272
273
274 #[cfg(unix)]
275 /// Sets the environment variable `n` to the value `v` for the currently running
276 /// process
277 pub fn setenv(n: &str, v: &str) {
278     unsafe {
279         do with_env_lock {
280             do n.to_c_str().with_ref |nbuf| {
281                 do v.to_c_str().with_ref |vbuf| {
282                     libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
283                 }
284             }
285         }
286     }
287 }
288
289
290 #[cfg(windows)]
291 /// Sets the environment variable `n` to the value `v` for the currently running
292 /// process
293 pub fn setenv(n: &str, v: &str) {
294     unsafe {
295         do with_env_lock {
296             use os::win32::as_utf16_p;
297             do as_utf16_p(n) |nbuf| {
298                 do as_utf16_p(v) |vbuf| {
299                     libc::SetEnvironmentVariableW(nbuf, vbuf);
300                 }
301             }
302         }
303     }
304 }
305
306 /// Remove a variable from the environment entirely
307 pub fn unsetenv(n: &str) {
308     #[cfg(unix)]
309     fn _unsetenv(n: &str) {
310         unsafe {
311             do with_env_lock {
312                 do n.to_c_str().with_ref |nbuf| {
313                     libc::funcs::posix01::unistd::unsetenv(nbuf);
314                 }
315             }
316         }
317     }
318     #[cfg(windows)]
319     fn _unsetenv(n: &str) {
320         unsafe {
321             do with_env_lock {
322                 use os::win32::as_utf16_p;
323                 do as_utf16_p(n) |nbuf| {
324                     libc::SetEnvironmentVariableW(nbuf, ptr::null());
325                 }
326             }
327         }
328     }
329
330     _unsetenv(n);
331 }
332
333 pub fn fdopen(fd: c_int) -> *FILE {
334     do "r".to_c_str().with_ref |modebuf| {
335         unsafe {
336             libc::fdopen(fd, modebuf)
337         }
338     }
339 }
340
341
342 // fsync related
343
344 #[cfg(windows)]
345 pub fn fsync_fd(fd: c_int, _level: io::fsync::Level) -> c_int {
346     unsafe {
347         use libc::funcs::extra::msvcrt::*;
348         return commit(fd);
349     }
350 }
351
352 #[cfg(target_os = "linux")]
353 #[cfg(target_os = "android")]
354 pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
355     unsafe {
356         use libc::funcs::posix01::unistd::*;
357         match level {
358           io::fsync::FSync
359           | io::fsync::FullFSync => return fsync(fd),
360           io::fsync::FDataSync => return fdatasync(fd)
361         }
362     }
363 }
364
365 #[cfg(target_os = "macos")]
366 pub fn fsync_fd(fd: c_int, level: io::fsync::Level) -> c_int {
367     unsafe {
368         use libc::consts::os::extra::*;
369         use libc::funcs::posix88::fcntl::*;
370         use libc::funcs::posix01::unistd::*;
371         match level {
372           io::fsync::FSync => return fsync(fd),
373           _ => {
374             // According to man fnctl, the ok retval is only specified to be
375             // !=-1
376             if (fcntl(F_FULLFSYNC as c_int, fd) == -1 as c_int)
377                 { return -1 as c_int; }
378             else
379                 { return 0 as c_int; }
380           }
381         }
382     }
383 }
384
385 #[cfg(target_os = "freebsd")]
386 pub fn fsync_fd(fd: c_int, _l: io::fsync::Level) -> c_int {
387     unsafe {
388         use libc::funcs::posix01::unistd::*;
389         return fsync(fd);
390     }
391 }
392
393 pub struct Pipe {
394     input: c_int,
395     out: c_int
396 }
397
398 #[cfg(unix)]
399 pub fn pipe() -> Pipe {
400     unsafe {
401         let mut fds = Pipe {input: 0 as c_int,
402                             out: 0 as c_int };
403         assert_eq!(libc::pipe(&mut fds.input), (0 as c_int));
404         return Pipe {input: fds.input, out: fds.out};
405     }
406 }
407
408
409
410 #[cfg(windows)]
411 pub fn pipe() -> Pipe {
412     unsafe {
413         // Windows pipes work subtly differently than unix pipes, and their
414         // inheritance has to be handled in a different way that I do not
415         // fully understand. Here we explicitly make the pipe non-inheritable,
416         // which means to pass it to a subprocess they need to be duplicated
417         // first, as in core::run.
418         let mut fds = Pipe {input: 0 as c_int,
419                     out: 0 as c_int };
420         let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
421                              (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
422         assert_eq!(res, 0 as c_int);
423         assert!((fds.input != -1 as c_int && fds.input != 0 as c_int));
424         assert!((fds.out != -1 as c_int && fds.input != 0 as c_int));
425         return Pipe {input: fds.input, out: fds.out};
426     }
427 }
428
429 fn dup2(src: c_int, dst: c_int) -> c_int {
430     unsafe {
431         libc::dup2(src, dst)
432     }
433 }
434
435 /// Returns the proper dll filename for the given basename of a file.
436 pub fn dll_filename(base: &str) -> ~str {
437     fmt!("%s%s%s", DLL_PREFIX, base, DLL_SUFFIX)
438 }
439
440 /// Optionally returns the filesystem path to the current executable which is
441 /// running. If any failure occurs, None is returned.
442 pub fn self_exe_path() -> Option<Path> {
443
444     #[cfg(target_os = "freebsd")]
445     fn load_self() -> Option<~str> {
446         unsafe {
447             use libc::funcs::bsd44::*;
448             use libc::consts::os::extra::*;
449             do fill_charp_buf() |buf, sz| {
450                 let mib = ~[CTL_KERN as c_int,
451                            KERN_PROC as c_int,
452                            KERN_PROC_PATHNAME as c_int, -1 as c_int];
453                 let mut sz = sz;
454                 sysctl(vec::raw::to_ptr(mib), mib.len() as ::libc::c_uint,
455                        buf as *mut c_void, &mut sz, ptr::null(),
456                        0u as size_t) == (0 as c_int)
457             }
458         }
459     }
460
461     #[cfg(target_os = "linux")]
462     #[cfg(target_os = "android")]
463     fn load_self() -> Option<~str> {
464         unsafe {
465             use libc::funcs::posix01::unistd::readlink;
466
467             let mut path = [0 as c_char, .. TMPBUF_SZ];
468
469             do path.as_mut_buf |buf, len| {
470                 let len = do "/proc/self/exe".to_c_str.with_ref |proc_self_buf| {
471                     readlink(proc_self_buf, buf, len as size_t) as uint
472                 };
473
474                 if len == -1 {
475                     None
476                 } else {
477                     Some(str::raw::from_buf_len(buf as *u8, len))
478                 }
479             }
480         }
481     }
482
483     #[cfg(target_os = "macos")]
484     fn load_self() -> Option<~str> {
485         unsafe {
486             do fill_charp_buf() |buf, sz| {
487                 let mut sz = sz as u32;
488                 libc::funcs::extra::_NSGetExecutablePath(
489                     buf, &mut sz) == (0 as c_int)
490             }
491         }
492     }
493
494     #[cfg(windows)]
495     fn load_self() -> Option<~str> {
496         unsafe {
497             use os::win32::fill_utf16_buf_and_decode;
498             do fill_utf16_buf_and_decode() |buf, sz| {
499                 libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
500             }
501         }
502     }
503
504     do load_self().map |pth| {
505         Path(*pth).dir_path()
506     }
507 }
508
509
510 /**
511  * Returns the path to the user's home directory, if known.
512  *
513  * On Unix, returns the value of the 'HOME' environment variable if it is set
514  * and not equal to the empty string.
515  *
516  * On Windows, returns the value of the 'HOME' environment variable if it is
517  * set and not equal to the empty string. Otherwise, returns the value of the
518  * 'USERPROFILE' environment variable if it is set and not equal to the empty
519  * string.
520  *
521  * Otherwise, homedir returns option::none.
522  */
523 pub fn homedir() -> Option<Path> {
524     return match getenv("HOME") {
525         Some(ref p) => if !p.is_empty() {
526           Some(Path(*p))
527         } else {
528           secondary()
529         },
530         None => secondary()
531     };
532
533     #[cfg(unix)]
534     fn secondary() -> Option<Path> {
535         None
536     }
537
538     #[cfg(windows)]
539     fn secondary() -> Option<Path> {
540         do getenv("USERPROFILE").chain |p| {
541             if !p.is_empty() {
542                 Some(Path(p))
543             } else {
544                 None
545             }
546         }
547     }
548 }
549
550 /**
551  * Returns the path to a temporary directory.
552  *
553  * On Unix, returns the value of the 'TMPDIR' environment variable if it is
554  * set and non-empty and '/tmp' otherwise.
555  *
556  * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
557  * 'USERPROFILE' environment variable  if any are set and not the empty
558  * string. Otherwise, tmpdir returns the path to the Windows directory.
559  */
560 pub fn tmpdir() -> Path {
561     return lookup();
562
563     fn getenv_nonempty(v: &str) -> Option<Path> {
564         match getenv(v) {
565             Some(x) =>
566                 if x.is_empty() {
567                     None
568                 } else {
569                     Some(Path(x))
570                 },
571             _ => None
572         }
573     }
574
575     #[cfg(unix)]
576     fn lookup() -> Path {
577         getenv_nonempty("TMPDIR").get_or_default(Path("/tmp"))
578     }
579
580     #[cfg(windows)]
581     fn lookup() -> Path {
582         getenv_nonempty("TMP").or(
583             getenv_nonempty("TEMP").or(
584                 getenv_nonempty("USERPROFILE").or(
585                    getenv_nonempty("WINDIR")))).get_or_default(Path("C:\\Windows"))
586     }
587 }
588
589 /// Recursively walk a directory structure
590 pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
591     let r = list_dir(p);
592     r.iter().advance(|q| {
593         let path = &p.push(*q);
594         f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p)))
595     })
596 }
597
598 /// Indicates whether a path represents a directory
599 pub fn path_is_dir(p: &Path) -> bool {
600     unsafe {
601         do p.to_c_str().with_ref |buf| {
602             rustrt::rust_path_is_dir(buf) != 0 as c_int
603         }
604     }
605 }
606
607 /// Indicates whether a path exists
608 pub fn path_exists(p: &Path) -> bool {
609     unsafe {
610         do p.to_c_str().with_ref |buf| {
611             rustrt::rust_path_exists(buf) != 0 as c_int
612         }
613     }
614 }
615
616 /**
617  * Convert a relative path to an absolute path
618  *
619  * If the given path is relative, return it prepended with the current working
620  * directory. If the given path is already an absolute path, return it
621  * as is.
622  */
623 // NB: this is here rather than in path because it is a form of environment
624 // querying; what it does depends on the process working directory, not just
625 // the input paths.
626 pub fn make_absolute(p: &Path) -> Path {
627     if p.is_absolute {
628         (*p).clone()
629     } else {
630         getcwd().push_many(p.components)
631     }
632 }
633
634
635 /// Creates a directory at the specified path
636 pub fn make_dir(p: &Path, mode: c_int) -> bool {
637     return mkdir(p, mode);
638
639     #[cfg(windows)]
640     fn mkdir(p: &Path, _mode: c_int) -> bool {
641         unsafe {
642             use os::win32::as_utf16_p;
643             // FIXME: turn mode into something useful? #2623
644             do as_utf16_p(p.to_str()) |buf| {
645                 libc::CreateDirectoryW(buf, ptr::null()) != (0 as libc::BOOL)
646             }
647         }
648     }
649
650     #[cfg(unix)]
651     fn mkdir(p: &Path, mode: c_int) -> bool {
652         do p.to_c_str().with_ref |buf| {
653             unsafe {
654                 libc::mkdir(buf, mode as libc::mode_t) == (0 as c_int)
655             }
656         }
657     }
658 }
659
660 /// Creates a directory with a given mode.
661 /// Returns true iff creation
662 /// succeeded. Also creates all intermediate subdirectories
663 /// if they don't already exist, giving all of them the same mode.
664
665 // tjc: if directory exists but with different permissions,
666 // should we return false?
667 pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool {
668     if path_is_dir(p) {
669         return true;
670     }
671     else if p.components.is_empty() {
672         return false;
673     }
674     else if p.components.len() == 1 {
675         // No parent directories to create
676         path_is_dir(p) || make_dir(p, mode)
677     }
678     else {
679         mkdir_recursive(&p.pop(), mode) && make_dir(p, mode)
680     }
681 }
682
683 /// Lists the contents of a directory
684 pub fn list_dir(p: &Path) -> ~[~str] {
685     if p.components.is_empty() && !p.is_absolute() {
686         // Not sure what the right behavior is here, but this
687         // prevents a bounds check failure later
688         return ~[];
689     }
690     unsafe {
691         #[cfg(target_os = "linux")]
692         #[cfg(target_os = "android")]
693         #[cfg(target_os = "freebsd")]
694         #[cfg(target_os = "macos")]
695         unsafe fn get_list(p: &Path) -> ~[~str] {
696             use libc::{dirent_t};
697             use libc::{opendir, readdir, closedir};
698             extern {
699                 fn rust_list_dir_val(ptr: *dirent_t) -> *libc::c_char;
700             }
701             let mut strings = ~[];
702             debug!("os::list_dir -- BEFORE OPENDIR");
703
704             let dir_ptr = do p.to_c_str().with_ref |buf| {
705                 opendir(buf)
706             };
707
708             if (dir_ptr as uint != 0) {
709                 debug!("os::list_dir -- opendir() SUCCESS");
710                 let mut entry_ptr = readdir(dir_ptr);
711                 while (entry_ptr as uint != 0) {
712                     strings.push(str::raw::from_c_str(rust_list_dir_val(
713                         entry_ptr)));
714                     entry_ptr = readdir(dir_ptr);
715                 }
716                 closedir(dir_ptr);
717             }
718             else {
719                 debug!("os::list_dir -- opendir() FAILURE");
720             }
721             debug!(
722                 "os::list_dir -- AFTER -- #: %?",
723                      strings.len());
724             strings
725         }
726         #[cfg(windows)]
727         unsafe fn get_list(p: &Path) -> ~[~str] {
728             use libc::consts::os::extra::INVALID_HANDLE_VALUE;
729             use libc::{wcslen, free};
730             use libc::funcs::extra::kernel32::{
731                 FindFirstFileW,
732                 FindNextFileW,
733                 FindClose,
734             };
735             use os::win32::{
736                 as_utf16_p
737             };
738             use rt::global_heap::malloc_raw;
739
740             #[nolink]
741             extern {
742                 fn rust_list_dir_wfd_size() -> libc::size_t;
743                 fn rust_list_dir_wfd_fp_buf(wfd: *libc::c_void) -> *u16;
744             }
745             fn star(p: &Path) -> Path { p.push("*") }
746             do as_utf16_p(star(p).to_str()) |path_ptr| {
747                 let mut strings = ~[];
748                 let wfd_ptr = malloc_raw(rust_list_dir_wfd_size() as uint);
749                 let find_handle = FindFirstFileW(path_ptr, wfd_ptr as HANDLE);
750                 if find_handle as libc::c_int != INVALID_HANDLE_VALUE {
751                     let mut more_files = 1 as libc::c_int;
752                     while more_files != 0 {
753                         let fp_buf = rust_list_dir_wfd_fp_buf(wfd_ptr);
754                         if fp_buf as uint == 0 {
755                             fail!("os::list_dir() failure: got null ptr from wfd");
756                         }
757                         else {
758                             let fp_vec = vec::from_buf(
759                                 fp_buf, wcslen(fp_buf) as uint);
760                             let fp_str = str::from_utf16(fp_vec);
761                             strings.push(fp_str);
762                         }
763                         more_files = FindNextFileW(find_handle, wfd_ptr as HANDLE);
764                     }
765                     FindClose(find_handle);
766                     free(wfd_ptr)
767                 }
768                 strings
769             }
770         }
771         do get_list(p).consume_iter().filter |filename| {
772             "." != *filename && ".." != *filename
773         }.collect()
774     }
775 }
776
777 /**
778  * Lists the contents of a directory
779  *
780  * This version prepends each entry with the directory.
781  */
782 pub fn list_dir_path(p: &Path) -> ~[Path] {
783     list_dir(p).map(|f| p.push(*f))
784 }
785
786 /// Removes a directory at the specified path, after removing
787 /// all its contents. Use carefully!
788 pub fn remove_dir_recursive(p: &Path) -> bool {
789     let mut error_happened = false;
790     do walk_dir(p) |inner| {
791         if !error_happened {
792             if path_is_dir(inner) {
793                 if !remove_dir_recursive(inner) {
794                     error_happened = true;
795                 }
796             }
797             else {
798                 if !remove_file(inner) {
799                     error_happened = true;
800                 }
801             }
802         }
803         true
804     };
805     // Directory should now be empty
806     !error_happened && remove_dir(p)
807 }
808
809 /// Removes a directory at the specified path
810 pub fn remove_dir(p: &Path) -> bool {
811    return rmdir(p);
812
813     #[cfg(windows)]
814     fn rmdir(p: &Path) -> bool {
815         unsafe {
816             use os::win32::as_utf16_p;
817             return do as_utf16_p(p.to_str()) |buf| {
818                 libc::RemoveDirectoryW(buf) != (0 as libc::BOOL)
819             };
820         }
821     }
822
823     #[cfg(unix)]
824     fn rmdir(p: &Path) -> bool {
825         do p.to_c_str().with_ref |buf| {
826             unsafe {
827                 libc::rmdir(buf) == (0 as c_int)
828             }
829         }
830     }
831 }
832
833 /// Changes the current working directory to the specified path, returning
834 /// whether the change was completed successfully or not.
835 pub fn change_dir(p: &Path) -> bool {
836     return chdir(p);
837
838     #[cfg(windows)]
839     fn chdir(p: &Path) -> bool {
840         unsafe {
841             use os::win32::as_utf16_p;
842             return do as_utf16_p(p.to_str()) |buf| {
843                 libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
844             };
845         }
846     }
847
848     #[cfg(unix)]
849     fn chdir(p: &Path) -> bool {
850         do p.to_c_str().with_ref |buf| {
851             unsafe {
852                 libc::chdir(buf) == (0 as c_int)
853             }
854         }
855     }
856 }
857
858 /// Copies a file from one location to another
859 pub fn copy_file(from: &Path, to: &Path) -> bool {
860     return do_copy_file(from, to);
861
862     #[cfg(windows)]
863     fn do_copy_file(from: &Path, to: &Path) -> bool {
864         unsafe {
865             use os::win32::as_utf16_p;
866             return do as_utf16_p(from.to_str()) |fromp| {
867                 do as_utf16_p(to.to_str()) |top| {
868                     libc::CopyFileW(fromp, top, (0 as libc::BOOL)) !=
869                         (0 as libc::BOOL)
870                 }
871             }
872         }
873     }
874
875     #[cfg(unix)]
876     fn do_copy_file(from: &Path, to: &Path) -> bool {
877         unsafe {
878             let istream = do from.to_c_str().with_ref |fromp| {
879                 do "rb".to_c_str().with_ref |modebuf| {
880                     libc::fopen(fromp, modebuf)
881                 }
882             };
883             if istream as uint == 0u {
884                 return false;
885             }
886             // Preserve permissions
887             let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \
888                                                     for source file");
889
890             let ostream = do to.to_c_str().with_ref |top| {
891                 do "w+b".to_c_str().with_ref |modebuf| {
892                     libc::fopen(top, modebuf)
893                 }
894             };
895             if ostream as uint == 0u {
896                 fclose(istream);
897                 return false;
898             }
899             let bufsize = 8192u;
900             let mut buf = vec::with_capacity::<u8>(bufsize);
901             let mut done = false;
902             let mut ok = true;
903             while !done {
904                 do buf.as_mut_buf |b, _sz| {
905                   let nread = libc::fread(b as *mut c_void, 1u as size_t,
906                                           bufsize as size_t,
907                                           istream);
908                   if nread > 0 as size_t {
909                       if libc::fwrite(b as *c_void, 1u as size_t, nread,
910                                       ostream) != nread {
911                           ok = false;
912                           done = true;
913                       }
914                   } else {
915                       done = true;
916                   }
917               }
918             }
919             fclose(istream);
920             fclose(ostream);
921
922             // Give the new file the old file's permissions
923             if do to.to_c_str().with_ref |to_buf| {
924                 libc::chmod(to_buf, from_mode as libc::mode_t)
925             } != 0 {
926                 return false; // should be a condition...
927             }
928             return ok;
929         }
930     }
931 }
932
933 /// Deletes an existing file
934 pub fn remove_file(p: &Path) -> bool {
935     return unlink(p);
936
937     #[cfg(windows)]
938     fn unlink(p: &Path) -> bool {
939         unsafe {
940             use os::win32::as_utf16_p;
941             return do as_utf16_p(p.to_str()) |buf| {
942                 libc::DeleteFileW(buf) != (0 as libc::BOOL)
943             };
944         }
945     }
946
947     #[cfg(unix)]
948     fn unlink(p: &Path) -> bool {
949         unsafe {
950             do p.to_c_str().with_ref |buf| {
951                 libc::unlink(buf) == (0 as c_int)
952             }
953         }
954     }
955 }
956
957 #[cfg(unix)]
958 /// Returns the platform-specific value of errno
959 pub fn errno() -> int {
960     #[cfg(target_os = "macos")]
961     #[cfg(target_os = "freebsd")]
962     fn errno_location() -> *c_int {
963         #[nolink]
964         extern {
965             fn __error() -> *c_int;
966         }
967         unsafe {
968             __error()
969         }
970     }
971
972     #[cfg(target_os = "linux")]
973     #[cfg(target_os = "android")]
974     fn errno_location() -> *c_int {
975         #[nolink]
976         extern {
977             fn __errno_location() -> *c_int;
978         }
979         unsafe {
980             __errno_location()
981         }
982     }
983
984     unsafe {
985         (*errno_location()) as int
986     }
987 }
988
989 #[cfg(windows)]
990 /// Returns the platform-specific value of errno
991 pub fn errno() -> uint {
992     use libc::types::os::arch::extra::DWORD;
993
994     #[link_name = "kernel32"]
995     #[abi = "stdcall"]
996     extern "stdcall" {
997         fn GetLastError() -> DWORD;
998     }
999
1000     unsafe {
1001         GetLastError() as uint
1002     }
1003 }
1004
1005 /// Get a string representing the platform-dependent last error
1006 pub fn last_os_error() -> ~str {
1007     #[cfg(unix)]
1008     fn strerror() -> ~str {
1009         #[cfg(target_os = "macos")]
1010         #[cfg(target_os = "android")]
1011         #[cfg(target_os = "freebsd")]
1012         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
1013                       -> c_int {
1014             #[nolink]
1015             extern {
1016                 fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t)
1017                               -> c_int;
1018             }
1019             unsafe {
1020                 strerror_r(errnum, buf, buflen)
1021             }
1022         }
1023
1024         // GNU libc provides a non-compliant version of strerror_r by default
1025         // and requires macros to instead use the POSIX compliant variant.
1026         // So we just use __xpg_strerror_r which is always POSIX compliant
1027         #[cfg(target_os = "linux")]
1028         fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: size_t) -> c_int {
1029             #[nolink]
1030             extern {
1031                 fn __xpg_strerror_r(errnum: c_int,
1032                                     buf: *mut c_char,
1033                                     buflen: size_t)
1034                                     -> c_int;
1035             }
1036             unsafe {
1037                 __xpg_strerror_r(errnum, buf, buflen)
1038             }
1039         }
1040
1041         let mut buf = [0 as c_char, ..TMPBUF_SZ];
1042
1043         do buf.as_mut_buf |buf, len| {
1044             unsafe {
1045                 if strerror_r(errno() as c_int, buf, len as size_t) < 0 {
1046                     fail!("strerror_r failure");
1047                 }
1048
1049                 str::raw::from_c_str(buf as *c_char)
1050             }
1051         }
1052     }
1053
1054     #[cfg(windows)]
1055     fn strerror() -> ~str {
1056         use libc::types::os::arch::extra::DWORD;
1057         use libc::types::os::arch::extra::LPSTR;
1058         use libc::types::os::arch::extra::LPVOID;
1059
1060         #[link_name = "kernel32"]
1061         #[abi = "stdcall"]
1062         extern "stdcall" {
1063             fn FormatMessageA(flags: DWORD,
1064                               lpSrc: LPVOID,
1065                               msgId: DWORD,
1066                               langId: DWORD,
1067                               buf: LPSTR,
1068                               nsize: DWORD,
1069                               args: *c_void)
1070                               -> DWORD;
1071         }
1072
1073         static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
1074         static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
1075
1076         // This value is calculated from the macro
1077         // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
1078         let langId = 0x0800 as DWORD;
1079         let err = errno() as DWORD;
1080
1081         let mut buf = [0 as c_char, ..TMPBUF_SZ];
1082
1083         do buf.as_imm_buf |buf, len| {
1084             unsafe {
1085                 let res = FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
1086                                          FORMAT_MESSAGE_IGNORE_INSERTS,
1087                                          ptr::mut_null(),
1088                                          err,
1089                                          langId,
1090                                          buf,
1091                                          len as DWORD,
1092                                          ptr::null());
1093                 if res == 0 {
1094                     fail!("[%?] FormatMessage failure", errno());
1095                 }
1096
1097                 str::raw::from_c_str(buf)
1098             }
1099         }
1100     }
1101
1102     strerror()
1103 }
1104
1105 /**
1106  * Sets the process exit code
1107  *
1108  * Sets the exit code returned by the process if all supervised tasks
1109  * terminate successfully (without failing). If the current root task fails
1110  * and is supervised by the scheduler then any user-specified exit status is
1111  * ignored and the process exits with the default failure status
1112  */
1113 pub fn set_exit_status(code: int) {
1114     use rt;
1115     use rt::OldTaskContext;
1116
1117     if rt::context() == OldTaskContext {
1118         unsafe {
1119             rustrt::rust_set_exit_status(code as libc::intptr_t);
1120         }
1121     } else {
1122         rt::util::set_exit_status(code);
1123     }
1124 }
1125
1126 unsafe fn load_argc_and_argv(argc: c_int, argv: **c_char) -> ~[~str] {
1127     let mut args = ~[];
1128     for i in range(0u, argc as uint) {
1129         args.push(str::raw::from_c_str(*argv.offset(i as int)));
1130     }
1131     args
1132 }
1133
1134 /**
1135  * Returns the command line arguments
1136  *
1137  * Returns a list of the command line arguments.
1138  */
1139 #[cfg(target_os = "macos")]
1140 pub fn real_args() -> ~[~str] {
1141     unsafe {
1142         let (argc, argv) = (*_NSGetArgc() as c_int,
1143                             *_NSGetArgv() as **c_char);
1144         load_argc_and_argv(argc, argv)
1145     }
1146 }
1147
1148 #[cfg(target_os = "linux")]
1149 #[cfg(target_os = "android")]
1150 #[cfg(target_os = "freebsd")]
1151 pub fn real_args() -> ~[~str] {
1152     use rt;
1153     use rt::TaskContext;
1154
1155     if rt::context() == TaskContext {
1156         match rt::args::clone() {
1157             Some(args) => args,
1158             None => fail!("process arguments not initialized")
1159         }
1160     } else {
1161         unsafe {
1162             let argc = rustrt::rust_get_argc();
1163             let argv = rustrt::rust_get_argv();
1164             load_argc_and_argv(argc, argv)
1165         }
1166     }
1167 }
1168
1169 #[cfg(windows)]
1170 pub fn real_args() -> ~[~str] {
1171     let mut nArgs: c_int = 0;
1172     let lpArgCount: *mut c_int = &mut nArgs;
1173     let lpCmdLine = unsafe { GetCommandLineW() };
1174     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
1175
1176     let mut args = ~[];
1177     for i in range(0u, nArgs as uint) {
1178         unsafe {
1179             // Determine the length of this argument.
1180             let ptr = *szArgList.offset(i as int);
1181             let mut len = 0;
1182             while *ptr.offset(len as int) != 0 { len += 1; }
1183
1184             // Push it onto the list.
1185             args.push(vec::raw::buf_as_slice(ptr, len,
1186                                              str::from_utf16));
1187         }
1188     }
1189
1190     unsafe {
1191         LocalFree(szArgList as *c_void);
1192     }
1193
1194     return args;
1195 }
1196
1197 type LPCWSTR = *u16;
1198
1199 #[cfg(windows)]
1200 #[link_name="kernel32"]
1201 #[abi="stdcall"]
1202 extern "stdcall" {
1203     fn GetCommandLineW() -> LPCWSTR;
1204     fn LocalFree(ptr: *c_void);
1205 }
1206
1207 #[cfg(windows)]
1208 #[link_name="shell32"]
1209 #[abi="stdcall"]
1210 extern "stdcall" {
1211     fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
1212 }
1213
1214 struct OverriddenArgs {
1215     val: ~[~str]
1216 }
1217
1218 static overridden_arg_key: local_data::Key<@OverriddenArgs> = &local_data::Key;
1219
1220 /// Returns the arguments which this program was started with (normally passed
1221 /// via the command line).
1222 ///
1223 /// The return value of the function can be changed by invoking the
1224 /// `os::set_args` function.
1225 pub fn args() -> ~[~str] {
1226     match local_data::get(overridden_arg_key, |k| k.map(|&k| *k)) {
1227         None => real_args(),
1228         Some(args) => args.val.clone()
1229     }
1230 }
1231
1232 /// For the current task, overrides the task-local cache of the arguments this
1233 /// program had when it started. These new arguments are only available to the
1234 /// current task via the `os::args` method.
1235 pub fn set_args(new_args: ~[~str]) {
1236     let overridden_args = @OverriddenArgs {
1237         val: new_args.clone()
1238     };
1239     local_data::set(overridden_arg_key, overridden_args);
1240 }
1241
1242 // FIXME #6100 we should really use an internal implementation of this - using
1243 // the POSIX glob functions isn't portable to windows, probably has slight
1244 // inconsistencies even where it is implemented, and makes extending
1245 // functionality a lot more difficult
1246 // FIXME #6101 also provide a non-allocating version - each_glob or so?
1247 /// Returns a vector of Path objects that match the given glob pattern
1248 #[cfg(target_os = "linux")]
1249 #[cfg(target_os = "android")]
1250 #[cfg(target_os = "freebsd")]
1251 #[cfg(target_os = "macos")]
1252 pub fn glob(pattern: &str) -> ~[Path] {
1253     #[cfg(target_os = "linux")]
1254     #[cfg(target_os = "android")]
1255     fn default_glob_t () -> libc::glob_t {
1256         libc::glob_t {
1257             gl_pathc: 0,
1258             gl_pathv: ptr::null(),
1259             gl_offs: 0,
1260             __unused1: ptr::null(),
1261             __unused2: ptr::null(),
1262             __unused3: ptr::null(),
1263             __unused4: ptr::null(),
1264             __unused5: ptr::null(),
1265         }
1266     }
1267
1268     #[cfg(target_os = "freebsd")]
1269     fn default_glob_t () -> libc::glob_t {
1270         libc::glob_t {
1271             gl_pathc: 0,
1272             __unused1: 0,
1273             gl_offs: 0,
1274             __unused2: 0,
1275             gl_pathv: ptr::null(),
1276             __unused3: ptr::null(),
1277             __unused4: ptr::null(),
1278             __unused5: ptr::null(),
1279             __unused6: ptr::null(),
1280             __unused7: ptr::null(),
1281             __unused8: ptr::null(),
1282         }
1283     }
1284
1285     #[cfg(target_os = "macos")]
1286     fn default_glob_t () -> libc::glob_t {
1287         libc::glob_t {
1288             gl_pathc: 0,
1289             __unused1: 0,
1290             gl_offs: 0,
1291             __unused2: 0,
1292             gl_pathv: ptr::null(),
1293             __unused3: ptr::null(),
1294             __unused4: ptr::null(),
1295             __unused5: ptr::null(),
1296             __unused6: ptr::null(),
1297             __unused7: ptr::null(),
1298             __unused8: ptr::null(),
1299         }
1300     }
1301
1302     let mut g = default_glob_t();
1303     do pattern.to_c_str().with_ref |c_pattern| {
1304         unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) }
1305     };
1306     do(|| {
1307         let paths = unsafe {
1308             vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint)
1309         };
1310         do paths.map |&c_str| {
1311             Path(unsafe { str::raw::from_c_str(c_str) })
1312         }
1313     }).finally {
1314         unsafe { libc::globfree(&mut g) };
1315     }
1316 }
1317
1318 /// Returns a vector of Path objects that match the given glob pattern
1319 #[cfg(target_os = "win32")]
1320 pub fn glob(_pattern: &str) -> ~[Path] {
1321     fail!("glob() is unimplemented on Windows")
1322 }
1323
1324 #[cfg(target_os = "macos")]
1325 extern {
1326     // These functions are in crt_externs.h.
1327     pub fn _NSGetArgc() -> *c_int;
1328     pub fn _NSGetArgv() -> ***c_char;
1329 }
1330
1331 // Round up `from` to be divisible by `to`
1332 fn round_up(from: uint, to: uint) -> uint {
1333     let r = if from % to == 0 {
1334         from
1335     } else {
1336         from + to - (from % to)
1337     };
1338     if r == 0 {
1339         to
1340     } else {
1341         r
1342     }
1343 }
1344
1345 #[cfg(unix)]
1346 pub fn page_size() -> uint {
1347     unsafe {
1348         libc::sysconf(libc::_SC_PAGESIZE) as uint
1349     }
1350 }
1351
1352 #[cfg(windows)]
1353 pub fn page_size() -> uint {
1354   unsafe {
1355     let mut info = libc::SYSTEM_INFO::new();
1356     libc::GetSystemInfo(&mut info);
1357
1358     return info.dwPageSize as uint;
1359   }
1360 }
1361
1362 pub struct MemoryMap {
1363     data: *mut u8,
1364     len: size_t,
1365     kind: MemoryMapKind
1366 }
1367
1368 pub enum MemoryMapKind {
1369     MapFile(*c_void),
1370     MapVirtual
1371 }
1372
1373 pub enum MapOption {
1374     MapReadable,
1375     MapWritable,
1376     MapExecutable,
1377     MapAddr(*c_void),
1378     MapFd(c_int),
1379     MapOffset(uint)
1380 }
1381
1382 pub enum MapError {
1383     // Linux-specific errors
1384     ErrFdNotAvail,
1385     ErrInvalidFd,
1386     ErrUnaligned,
1387     ErrNoMapSupport,
1388     ErrNoMem,
1389     ErrUnknown(libc::c_int),
1390
1391     // Windows-specific errors
1392     ErrUnsupProt,
1393     ErrUnsupOffset,
1394     ErrNeedRW,
1395     ErrAlreadyExists,
1396     ErrVirtualAlloc(uint),
1397     ErrCreateFileMappingW(uint),
1398     ErrMapViewOfFile(uint)
1399 }
1400
1401 impl to_str::ToStr for MapError {
1402     fn to_str(&self) -> ~str {
1403         match *self {
1404             ErrFdNotAvail => ~"fd not available for reading or writing",
1405             ErrInvalidFd => ~"Invalid fd",
1406             ErrUnaligned => ~"Unaligned address, invalid flags, \
1407                               negative length or unaligned offset",
1408             ErrNoMapSupport=> ~"File doesn't support mapping",
1409             ErrNoMem => ~"Invalid address, or not enough available memory",
1410             ErrUnknown(code) => fmt!("Unknown error=%?", code),
1411             ErrUnsupProt => ~"Protection mode unsupported",
1412             ErrUnsupOffset => ~"Offset in virtual memory mode is unsupported",
1413             ErrNeedRW => ~"File mapping should be at least readable/writable",
1414             ErrAlreadyExists => ~"File mapping for specified file already exists",
1415             ErrVirtualAlloc(code) => fmt!("VirtualAlloc failure=%?", code),
1416             ErrCreateFileMappingW(code) => fmt!("CreateFileMappingW failure=%?", code),
1417             ErrMapViewOfFile(code) => fmt!("MapViewOfFile failure=%?", code)
1418         }
1419     }
1420 }
1421
1422 #[cfg(unix)]
1423 impl MemoryMap {
1424     pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
1425         use libc::off_t;
1426
1427         let mut addr: *c_void = ptr::null();
1428         let mut prot: c_int = 0;
1429         let mut flags: c_int = libc::MAP_PRIVATE;
1430         let mut fd: c_int = -1;
1431         let mut offset: off_t = 0;
1432         let len = round_up(min_len, page_size()) as size_t;
1433
1434         for &o in options.iter() {
1435             match o {
1436                 MapReadable => { prot |= libc::PROT_READ; },
1437                 MapWritable => { prot |= libc::PROT_WRITE; },
1438                 MapExecutable => { prot |= libc::PROT_EXEC; },
1439                 MapAddr(addr_) => {
1440                     flags |= libc::MAP_FIXED;
1441                     addr = addr_;
1442                 },
1443                 MapFd(fd_) => {
1444                     flags |= libc::MAP_FILE;
1445                     fd = fd_;
1446                 },
1447                 MapOffset(offset_) => { offset = offset_ as off_t; }
1448             }
1449         }
1450         if fd == -1 { flags |= libc::MAP_ANON; }
1451
1452         let r = unsafe {
1453             libc::mmap(addr, len, prot, flags, fd, offset)
1454         };
1455         if r == libc::MAP_FAILED {
1456             Err(match errno() as c_int {
1457                 libc::EACCES => ErrFdNotAvail,
1458                 libc::EBADF => ErrInvalidFd,
1459                 libc::EINVAL => ErrUnaligned,
1460                 libc::ENODEV => ErrNoMapSupport,
1461                 libc::ENOMEM => ErrNoMem,
1462                 code => ErrUnknown(code)
1463             })
1464         } else {
1465             Ok(~MemoryMap {
1466                data: r as *mut u8,
1467                len: len,
1468                kind: if fd == -1 {
1469                    MapVirtual
1470                } else {
1471                    MapFile(ptr::null())
1472                }
1473             })
1474         }
1475     }
1476 }
1477
1478 #[cfg(unix)]
1479 impl Drop for MemoryMap {
1480     fn drop(&self) {
1481         unsafe {
1482             match libc::munmap(self.data as *c_void, self.len) {
1483                 0 => (),
1484                 -1 => error!(match errno() as c_int {
1485                     libc::EINVAL => ~"invalid addr or len",
1486                     e => fmt!("unknown errno=%?", e)
1487                 }),
1488                 r => error!(fmt!("Unexpected result %?", r))
1489             }
1490         }
1491     }
1492 }
1493
1494 #[cfg(windows)]
1495 impl MemoryMap {
1496     pub fn new(min_len: uint, options: ~[MapOption]) -> Result<~MemoryMap, MapError> {
1497         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
1498
1499         let mut lpAddress: LPVOID = ptr::mut_null();
1500         let mut readable = false;
1501         let mut writable = false;
1502         let mut executable = false;
1503         let mut fd: c_int = -1;
1504         let mut offset: uint = 0;
1505         let len = round_up(min_len, page_size()) as SIZE_T;
1506
1507         for &o in options.iter() {
1508             match o {
1509                 MapReadable => { readable = true; },
1510                 MapWritable => { writable = true; },
1511                 MapExecutable => { executable = true; }
1512                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1513                 MapFd(fd_) => { fd = fd_; },
1514                 MapOffset(offset_) => { offset = offset_; }
1515             }
1516         }
1517
1518         let flProtect = match (executable, readable, writable) {
1519             (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
1520             (false, true, false) => libc::PAGE_READONLY,
1521             (false, true, true) => libc::PAGE_READWRITE,
1522             (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
1523             (true, true, false) => libc::PAGE_EXECUTE_READ,
1524             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1525             _ => return Err(ErrUnsupProt)
1526         };
1527
1528         if fd == -1 {
1529             if offset != 0 {
1530                 return Err(ErrUnsupOffset);
1531             }
1532             let r = unsafe {
1533                 libc::VirtualAlloc(lpAddress,
1534                                    len,
1535                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1536                                    flProtect)
1537             };
1538             match r as uint {
1539                 0 => Err(ErrVirtualAlloc(errno())),
1540                 _ => Ok(~MemoryMap {
1541                    data: r as *mut u8,
1542                    len: len,
1543                    kind: MapVirtual
1544                 })
1545             }
1546         } else {
1547             let dwDesiredAccess = match (readable, writable) {
1548                 (true, true) => libc::FILE_MAP_ALL_ACCESS,
1549                 (true, false) => libc::FILE_MAP_READ,
1550                 (false, true) => libc::FILE_MAP_WRITE,
1551                 _ => {
1552                     return Err(ErrNeedRW);
1553                 }
1554             };
1555             unsafe {
1556                 let hFile = libc::get_osfhandle(fd) as HANDLE;
1557                 let mapping = libc::CreateFileMappingW(hFile,
1558                                                        ptr::mut_null(),
1559                                                        flProtect,
1560                                                        (len >> 32) as DWORD,
1561                                                        (len & 0xffff_ffff) as DWORD,
1562                                                        ptr::null());
1563                 if mapping == ptr::mut_null() {
1564                     return Err(ErrCreateFileMappingW(errno()));
1565                 }
1566                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1567                     return Err(ErrAlreadyExists);
1568                 }
1569                 let r = libc::MapViewOfFile(mapping,
1570                                             dwDesiredAccess,
1571                                             (offset >> 32) as DWORD,
1572                                             (offset & 0xffff_ffff) as DWORD,
1573                                             0);
1574                 match r as uint {
1575                     0 => Err(ErrMapViewOfFile(errno())),
1576                     _ => Ok(~MemoryMap {
1577                        data: r as *mut u8,
1578                        len: len,
1579                        kind: MapFile(mapping as *c_void)
1580                     })
1581                 }
1582             }
1583         }
1584     }
1585 }
1586
1587 #[cfg(windows)]
1588 impl Drop for MemoryMap {
1589     fn drop(&self) {
1590         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1591
1592         unsafe {
1593             match self.kind {
1594                 MapVirtual => match libc::VirtualFree(self.data as *mut c_void,
1595                                                       self.len,
1596                                                       libc::MEM_RELEASE) {
1597                     0 => error!(fmt!("VirtualFree failed: %?", errno())),
1598                     _ => ()
1599                 },
1600                 MapFile(mapping) => {
1601                     if libc::UnmapViewOfFile(self.data as LPCVOID) != 0 {
1602                         error!(fmt!("UnmapViewOfFile failed: %?", errno()));
1603                     }
1604                     if libc::CloseHandle(mapping as HANDLE) != 0 {
1605                         error!(fmt!("CloseHandle failed: %?", errno()));
1606                     }
1607                 }
1608             }
1609         }
1610     }
1611 }
1612
1613 pub mod consts {
1614
1615     #[cfg(unix)]
1616     pub use os::consts::unix::*;
1617
1618     #[cfg(windows)]
1619     pub use os::consts::windows::*;
1620
1621     #[cfg(target_os = "macos")]
1622     pub use os::consts::macos::*;
1623
1624     #[cfg(target_os = "freebsd")]
1625     pub use os::consts::freebsd::*;
1626
1627     #[cfg(target_os = "linux")]
1628     pub use os::consts::linux::*;
1629
1630     #[cfg(target_os = "android")]
1631     pub use os::consts::android::*;
1632
1633     #[cfg(target_os = "win32")]
1634     pub use os::consts::win32::*;
1635
1636     #[cfg(target_arch = "x86")]
1637     pub use os::consts::x86::*;
1638
1639     #[cfg(target_arch = "x86_64")]
1640     pub use os::consts::x86_64::*;
1641
1642     #[cfg(target_arch = "arm")]
1643     pub use os::consts::arm::*;
1644
1645     #[cfg(target_arch = "mips")]
1646     use os::consts::mips::*;
1647
1648     pub mod unix {
1649         pub static FAMILY: &'static str = "unix";
1650     }
1651
1652     pub mod windows {
1653         pub static FAMILY: &'static str = "windows";
1654     }
1655
1656     pub mod macos {
1657         pub static SYSNAME: &'static str = "macos";
1658         pub static DLL_PREFIX: &'static str = "lib";
1659         pub static DLL_SUFFIX: &'static str = ".dylib";
1660         pub static EXE_SUFFIX: &'static str = "";
1661     }
1662
1663     pub mod freebsd {
1664         pub static SYSNAME: &'static str = "freebsd";
1665         pub static DLL_PREFIX: &'static str = "lib";
1666         pub static DLL_SUFFIX: &'static str = ".so";
1667         pub static EXE_SUFFIX: &'static str = "";
1668     }
1669
1670     pub mod linux {
1671         pub static SYSNAME: &'static str = "linux";
1672         pub static DLL_PREFIX: &'static str = "lib";
1673         pub static DLL_SUFFIX: &'static str = ".so";
1674         pub static EXE_SUFFIX: &'static str = "";
1675     }
1676
1677     pub mod android {
1678         pub static SYSNAME: &'static str = "android";
1679         pub static DLL_PREFIX: &'static str = "lib";
1680         pub static DLL_SUFFIX: &'static str = ".so";
1681         pub static EXE_SUFFIX: &'static str = "";
1682     }
1683
1684     pub mod win32 {
1685         pub static SYSNAME: &'static str = "win32";
1686         pub static DLL_PREFIX: &'static str = "";
1687         pub static DLL_SUFFIX: &'static str = ".dll";
1688         pub static EXE_SUFFIX: &'static str = ".exe";
1689     }
1690
1691
1692     pub mod x86 {
1693         pub static ARCH: &'static str = "x86";
1694     }
1695     pub mod x86_64 {
1696         pub static ARCH: &'static str = "x86_64";
1697     }
1698     pub mod arm {
1699         pub static ARCH: &'static str = "arm";
1700     }
1701     pub mod mips {
1702         pub static ARCH: &'static str = "mips";
1703     }
1704 }
1705
1706 #[cfg(test)]
1707 mod tests {
1708     use c_str::ToCStr;
1709     use libc::{c_int, c_void, size_t};
1710     use libc;
1711     use option::Some;
1712     use option;
1713     use os::{env, getcwd, getenv, make_absolute, real_args};
1714     use os::{remove_file, setenv, unsetenv};
1715     use os;
1716     use path::Path;
1717     use rand::RngUtil;
1718     use rand;
1719     use run;
1720     use str::StrSlice;
1721     use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
1722
1723
1724     #[test]
1725     pub fn last_os_error() {
1726         debug!(os::last_os_error());
1727     }
1728
1729     #[test]
1730     pub fn test_args() {
1731         let a = real_args();
1732         assert!(a.len() >= 1);
1733     }
1734
1735     fn make_rand_name() -> ~str {
1736         let mut rng = rand::rng();
1737         let n = ~"TEST" + rng.gen_str(10u);
1738         assert!(getenv(n).is_none());
1739         n
1740     }
1741
1742     #[test]
1743     fn test_setenv() {
1744         let n = make_rand_name();
1745         setenv(n, "VALUE");
1746         assert_eq!(getenv(n), option::Some(~"VALUE"));
1747     }
1748
1749     #[test]
1750     fn test_unsetenv() {
1751         let n = make_rand_name();
1752         setenv(n, "VALUE");
1753         unsetenv(n);
1754         assert_eq!(getenv(n), option::None);
1755     }
1756
1757     #[test]
1758     #[ignore(cfg(windows))]
1759     #[ignore]
1760     fn test_setenv_overwrite() {
1761         let n = make_rand_name();
1762         setenv(n, "1");
1763         setenv(n, "2");
1764         assert_eq!(getenv(n), option::Some(~"2"));
1765         setenv(n, "");
1766         assert_eq!(getenv(n), option::Some(~""));
1767     }
1768
1769     // Windows GetEnvironmentVariable requires some extra work to make sure
1770     // the buffer the variable is copied into is the right size
1771     #[test]
1772     #[ignore(cfg(windows))]
1773     #[ignore]
1774     fn test_getenv_big() {
1775         let mut s = ~"";
1776         let mut i = 0;
1777         while i < 100 {
1778             s = s + "aaaaaaaaaa";
1779             i += 1;
1780         }
1781         let n = make_rand_name();
1782         setenv(n, s);
1783         debug!(s.clone());
1784         assert_eq!(getenv(n), option::Some(s));
1785     }
1786
1787     #[test]
1788     fn test_self_exe_path() {
1789         let path = os::self_exe_path();
1790         assert!(path.is_some());
1791         let path = path.get();
1792         debug!(path.clone());
1793
1794         // Hard to test this function
1795         assert!(path.is_absolute);
1796     }
1797
1798     #[test]
1799     #[ignore]
1800     fn test_env_getenv() {
1801         let e = env();
1802         assert!(e.len() > 0u);
1803         for p in e.iter() {
1804             let (n, v) = (*p).clone();
1805             debug!(n.clone());
1806             let v2 = getenv(n);
1807             // MingW seems to set some funky environment variables like
1808             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1809             // from env() but not visible from getenv().
1810             assert!(v2.is_none() || v2 == option::Some(v));
1811         }
1812     }
1813
1814     #[test]
1815     fn test_env_setenv() {
1816         let n = make_rand_name();
1817
1818         let mut e = env();
1819         setenv(n, "VALUE");
1820         assert!(!e.contains(&(n.clone(), ~"VALUE")));
1821
1822         e = env();
1823         assert!(e.contains(&(n, ~"VALUE")));
1824     }
1825
1826     #[test]
1827     fn test() {
1828         assert!((!Path("test-path").is_absolute));
1829
1830         debug!("Current working directory: %s", getcwd().to_str());
1831
1832         debug!(make_absolute(&Path("test-path")));
1833         debug!(make_absolute(&Path("/usr/bin")));
1834     }
1835
1836     #[test]
1837     #[cfg(unix)]
1838     fn homedir() {
1839         let oldhome = getenv("HOME");
1840
1841         setenv("HOME", "/home/MountainView");
1842         assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
1843
1844         setenv("HOME", "");
1845         assert!(os::homedir().is_none());
1846
1847         for s in oldhome.iter() { setenv("HOME", *s) }
1848     }
1849
1850     #[test]
1851     #[cfg(windows)]
1852     fn homedir() {
1853
1854         let oldhome = getenv("HOME");
1855         let olduserprofile = getenv("USERPROFILE");
1856
1857         setenv("HOME", "");
1858         setenv("USERPROFILE", "");
1859
1860         assert!(os::homedir().is_none());
1861
1862         setenv("HOME", "/home/MountainView");
1863         assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
1864
1865         setenv("HOME", "");
1866
1867         setenv("USERPROFILE", "/home/MountainView");
1868         assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
1869
1870         setenv("HOME", "/home/MountainView");
1871         setenv("USERPROFILE", "/home/PaloAlto");
1872         assert_eq!(os::homedir(), Some(Path("/home/MountainView")));
1873
1874         oldhome.iter().advance(|s| { setenv("HOME", *s); true });
1875         olduserprofile.iter().advance(|s| { setenv("USERPROFILE", *s); true });
1876     }
1877
1878     #[test]
1879     fn tmpdir() {
1880         assert!(!os::tmpdir().to_str().is_empty());
1881     }
1882
1883     // Issue #712
1884     #[test]
1885     fn test_list_dir_no_invalid_memory_access() {
1886         os::list_dir(&Path("."));
1887     }
1888
1889     #[test]
1890     fn list_dir() {
1891         let dirs = os::list_dir(&Path("."));
1892         // Just assuming that we've got some contents in the current directory
1893         assert!(dirs.len() > 0u);
1894
1895         for dir in dirs.iter() {
1896             debug!((*dir).clone());
1897         }
1898     }
1899
1900     #[test]
1901     fn list_dir_empty_path() {
1902         let dirs = os::list_dir(&Path(""));
1903         assert!(dirs.is_empty());
1904     }
1905
1906     #[test]
1907     #[cfg(not(windows))]
1908     fn list_dir_root() {
1909         let dirs = os::list_dir(&Path("/"));
1910         assert!(dirs.len() > 1);
1911     }
1912     #[test]
1913     #[cfg(windows)]
1914     fn list_dir_root() {
1915         let dirs = os::list_dir(&Path("C:\\"));
1916         assert!(dirs.len() > 1);
1917     }
1918
1919
1920     #[test]
1921     fn path_is_dir() {
1922         assert!((os::path_is_dir(&Path("."))));
1923         assert!((!os::path_is_dir(&Path("test/stdtest/fs.rs"))));
1924     }
1925
1926     #[test]
1927     fn path_exists() {
1928         assert!((os::path_exists(&Path("."))));
1929         assert!((!os::path_exists(&Path(
1930                      "test/nonexistent-bogus-path"))));
1931     }
1932
1933     #[test]
1934     fn copy_file_does_not_exist() {
1935       assert!(!os::copy_file(&Path("test/nonexistent-bogus-path"),
1936                             &Path("test/other-bogus-path")));
1937       assert!(!os::path_exists(&Path("test/other-bogus-path")));
1938     }
1939
1940     #[test]
1941     fn copy_file_ok() {
1942         unsafe {
1943             let tempdir = getcwd(); // would like to use $TMPDIR,
1944                                     // doesn't seem to work on Linux
1945             assert!((tempdir.to_str().len() > 0u));
1946             let input = tempdir.push("in.txt");
1947             let out = tempdir.push("out.txt");
1948
1949             /* Write the temp input file */
1950             let ostream = do input.to_c_str().with_ref |fromp| {
1951                 do "w+b".to_c_str().with_ref |modebuf| {
1952                     libc::fopen(fromp, modebuf)
1953                 }
1954             };
1955             assert!((ostream as uint != 0u));
1956             let s = ~"hello";
1957             do "hello".to_c_str().with_ref |buf| {
1958                 let write_len = libc::fwrite(buf as *c_void,
1959                                              1u as size_t,
1960                                              (s.len() + 1u) as size_t,
1961                                              ostream);
1962                 assert_eq!(write_len, (s.len() + 1) as size_t)
1963             }
1964             assert_eq!(libc::fclose(ostream), (0u as c_int));
1965             let in_mode = input.get_mode();
1966             let rs = os::copy_file(&input, &out);
1967             if (!os::path_exists(&input)) {
1968                 fail!("%s doesn't exist", input.to_str());
1969             }
1970             assert!((rs));
1971             let rslt = run::process_status("diff", [input.to_str(), out.to_str()]);
1972             assert_eq!(rslt, 0);
1973             assert_eq!(out.get_mode(), in_mode);
1974             assert!((remove_file(&input)));
1975             assert!((remove_file(&out)));
1976         }
1977     }
1978
1979     #[test]
1980     fn recursive_mkdir_slash() {
1981         let path = Path("/");
1982         assert!(os::mkdir_recursive(&path,  (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
1983     }
1984
1985     #[test]
1986     fn recursive_mkdir_empty() {
1987         let path = Path("");
1988         assert!(!os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
1989     }
1990
1991     #[test]
1992     fn memory_map_rw() {
1993         use result::{Ok, Err};
1994
1995         let chunk = match os::MemoryMap::new(16, ~[
1996             os::MapReadable,
1997             os::MapWritable
1998         ]) {
1999             Ok(chunk) => chunk,
2000             Err(msg) => fail!(msg.to_str())
2001         };
2002         assert!(chunk.len >= 16);
2003
2004         unsafe {
2005             *chunk.data = 0xBE;
2006             assert!(*chunk.data == 0xBE);
2007         }
2008     }
2009
2010     #[test]
2011     fn memory_map_file() {
2012         use result::{Ok, Err};
2013         use os::*;
2014         use libc::*;
2015
2016         #[cfg(unix)]
2017         fn lseek_(fd: c_int, size: uint) {
2018             unsafe {
2019                 assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
2020             }
2021         }
2022         #[cfg(windows)]
2023         fn lseek_(fd: c_int, size: uint) {
2024            unsafe {
2025                assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
2026            }
2027         }
2028
2029         let path = tmpdir().push("mmap_file.tmp");
2030         let size = page_size() * 2;
2031         remove_file(&path);
2032
2033         let fd = unsafe {
2034             let fd = do path.to_c_str().with_ref |path| {
2035                 open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
2036             };
2037             lseek_(fd, size);
2038             do "x".to_c_str().with_ref |x| {
2039                 assert!(write(fd, x as *c_void, 1) == 1);
2040             }
2041             fd
2042         };
2043         let chunk = match MemoryMap::new(size / 2, ~[
2044             MapReadable,
2045             MapWritable,
2046             MapFd(fd),
2047             MapOffset(size / 2)
2048         ]) {
2049             Ok(chunk) => chunk,
2050             Err(msg) => fail!(msg.to_str())
2051         };
2052         assert!(chunk.len > 0);
2053
2054         unsafe {
2055             *chunk.data = 0xbe;
2056             assert!(*chunk.data == 0xbe);
2057             close(fd);
2058         }
2059     }
2060
2061     // More recursive_mkdir tests are in extra::tempfile
2062 }