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