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