os.rs 48.4 KB
Newer Older
1
// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 3 4 5 6 7 8 9 10
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*!
 * Higher-level interfaces to libc::* functions and operating system services.
 *
 * In general these take and return rust types, use rust idioms (enums,
 * closures, vectors) rather than C idioms, and do more extensive safety
 * checks.
 *
 * This module is not meant to only contain 1:1 mappings to libc entries; any
 * os-interface code that is reasonably useful and broadly applicable can go
 * here. Including utility routines that merely build on other os code.
 *
 * We assume the general case is that users do not care, and do not want to
 * be made to care, which operating system they are on. While they may want
 * to special case various special cases -- and so we will not _hide_ the
 * facts of which OS the user is on -- they should be given the opportunity
 * to write OS-ignorant code by default.
 */
28

29 30
#[allow(missing_doc)];

K
Kiet Tran 已提交
31
#[cfg(target_os = "macos")]
32
#[cfg(windows)]
33
use iter::range;
34 35 36

use clone::Clone;
use container::Container;
37
use libc;
A
Alex Crichton 已提交
38
use libc::{c_char, c_void, c_int};
39
use option::{Some, None, Option};
40
use os;
41 42
use ops::Drop;
use result::{Err, Ok, Result};
43 44
use ptr;
use str;
45
use str::{Str, StrSlice};
46
use fmt;
47
use unstable::finally::Finally;
48
use sync::atomics::{AtomicInt, INIT_ATOMIC_INT, SeqCst};
49 50 51 52 53 54 55
use path::{Path, GenericPath};
use iter::Iterator;
use vec::{Vector, CloneableVector, ImmutableVector, MutableVector, OwnedVector};
use ptr::RawPtr;

#[cfg(unix)]
use c_str::ToCStr;
56 57
#[cfg(windows)]
use str::OwnedStr;
58

59
/// Delegates to the libc close() function, returning the same return value.
60
pub fn close(fd: int) -> int {
61
    unsafe {
62
        libc::close(fd as c_int) as int
63 64 65
    }
}

66 67
pub static TMPBUF_SZ : uint = 1000u;
static BUF_BYTES : uint = 2048u;
68

69
#[cfg(unix)]
70
pub fn getcwd() -> Path {
71 72
    use c_str::CString;

73
    let mut buf = [0 as c_char, ..BUF_BYTES];
74
    unsafe {
A
Alex Crichton 已提交
75
        if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
76
            fail!()
77
        }
78 79
        Path::new(CString::new(buf.as_ptr(), false))
    }
80 81
}

82 83 84 85 86
#[cfg(windows)]
pub fn getcwd() -> Path {
    use libc::DWORD;
    use libc::GetCurrentDirectoryW;
    let mut buf = [0 as u16, ..BUF_BYTES];
87 88 89
    unsafe {
        if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
            fail!();
90
        }
91
    }
92
    Path::new(str::from_utf16(buf))
93 94
}

95
#[cfg(windows)]
96
pub mod win32 {
97
    use libc::types::os::arch::extra::DWORD;
98
    use libc;
99
    use option::{None, Option};
100
    use option;
101
    use os::TMPBUF_SZ;
102 103 104 105
    use str::StrSlice;
    use str;
    use vec::{MutableVector, ImmutableVector, OwnedVector};
    use vec;
106

107
    pub fn fill_utf16_buf_and_decode(f: |*mut u16, DWORD| -> DWORD)
B
Brian Anderson 已提交
108
        -> Option<~str> {
109

110
        unsafe {
111
            let mut n = TMPBUF_SZ as DWORD;
112 113 114
            let mut res = None;
            let mut done = false;
            while !done {
115
                let mut buf = vec::from_elem(n as uint, 0u16);
116 117 118
                let k = f(buf.as_mut_ptr(), TMPBUF_SZ as DWORD);
                if k == (0 as DWORD) {
                    done = true;
H
Huon Wilson 已提交
119 120 121
                } else if k == n &&
                          libc::GetLastError() ==
                          libc::ERROR_INSUFFICIENT_BUFFER as DWORD {
122 123 124 125
                    n *= (2 as DWORD);
                } else {
                    done = true;
                }
126
                if k != 0 && done {
127
                    let sub = buf.slice(0, k as uint);
128 129
                    res = option::Some(str::from_utf16(sub));
                }
130
            }
131
            return res;
132 133 134
        }
    }

135
    pub fn as_utf16_p<T>(s: &str, f: |*u16| -> T) -> T {
136
        let mut t = s.to_utf16();
137
        // Null terminate before passing on.
138
        t.push(0u16);
139
        f(t.as_ptr())
140
    }
141 142
}

143 144
/*
Accessing environment variables is not generally threadsafe.
145
Serialize access through a global lock.
146
*/
147
fn with_env_lock<T>(f: || -> T) -> T {
148
    use unstable::mutex::{Mutex, MUTEX_INIT};
149
    use unstable::finally::Finally;
150

151 152
    static mut lock: Mutex = MUTEX_INIT;

153
    unsafe {
154
        return (|| {
155
            lock.lock();
156
            f()
157
        }).finally(|| lock.unlock());
158
    }
B
Ben Blum 已提交
159 160
}

161 162
/// Returns a vector of (variable, value) pairs for all the environment
/// variables of the current process.
163 164 165
///
/// Invalid UTF-8 bytes are replaced with \uFFFD. See `str::from_utf8_lossy()`
/// for details.
166
pub fn env() -> ~[(~str,~str)] {
167 168 169 170 171 172 173 174 175 176
    env_as_bytes().move_iter().map(|(k,v)| {
        let k = str::from_utf8_lossy(k).into_owned();
        let v = str::from_utf8_lossy(v).into_owned();
        (k,v)
    }).collect()
}

/// Returns a vector of (variable, value) byte-vector pairs for all the
/// environment variables of the current process.
pub fn env_as_bytes() -> ~[(~[u8],~[u8])] {
177
    unsafe {
178
        #[cfg(windows)]
179
        unsafe fn get_env_pairs() -> ~[~[u8]] {
A
Alex Crichton 已提交
180 181
            use c_str;
            use str::StrSlice;
182

183 184 185 186 187
            use libc::funcs::extra::kernel32::{
                GetEnvironmentStringsA,
                FreeEnvironmentStringsA
            };
            let ch = GetEnvironmentStringsA();
H
Huon Wilson 已提交
188
            if ch as uint == 0 {
189
                fail!("os::env() failure getting env string from OS: {}",
A
Alex Crichton 已提交
190
                       os::last_os_error());
191
            }
A
Alex Crichton 已提交
192
            let mut result = ~[];
193
            c_str::from_c_multistring(ch as *c_char, None, |cstr| {
194
                result.push(cstr.as_bytes_no_nul().to_owned());
195
            });
196 197 198 199
            FreeEnvironmentStringsA(ch);
            result
        }
        #[cfg(unix)]
200 201 202
        unsafe fn get_env_pairs() -> ~[~[u8]] {
            use c_str::CString;

203
            extern {
204
                fn rust_env_pairs() -> **c_char;
205
            }
206
            let environ = rust_env_pairs();
H
Huon Wilson 已提交
207
            if environ as uint == 0 {
208
                fail!("os::env() failure getting env string from OS: {}",
A
Alex Crichton 已提交
209
                       os::last_os_error());
210 211 212
            }
            let mut result = ~[];
            ptr::array_each(environ, |e| {
213
                let env_pair = CString::new(e, false).as_bytes_no_nul().to_owned();
214 215 216 217 218
                result.push(env_pair);
            });
            result
        }

219
        fn env_convert(input: ~[~[u8]]) -> ~[(~[u8], ~[u8])] {
220
            let mut pairs = ~[];
D
Daniel Micay 已提交
221
            for p in input.iter() {
222 223 224 225
                let vs: ~[&[u8]] = p.splitn(1, |b| *b == '=' as u8).collect();
                let key = vs[0].to_owned();
                let val = (if vs.len() < 2 { ~[] } else { vs[1].to_owned() });
                pairs.push((key, val));
226
            }
L
Luqman Aden 已提交
227
            pairs
228
        }
229
        with_env_lock(|| {
230 231
            let unparsed_environ = get_env_pairs();
            env_convert(unparsed_environ)
232
        })
233
    }
234
}
235

236
#[cfg(unix)]
237 238
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
239 240 241 242 243 244 245
///
/// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
/// `str::from_utf8_lossy()` for details.
///
/// # Failure
///
/// Fails if `n` has any interior NULs.
246
pub fn getenv(n: &str) -> Option<~str> {
247 248 249 250 251 252 253 254 255 256 257 258 259
    getenv_as_bytes(n).map(|v| str::from_utf8_lossy(v).into_owned())
}

#[cfg(unix)]
/// Fetches the environment variable `n` byte vector from the current process,
/// returning None if the variable isn't set.
///
/// # Failure
///
/// Fails if `n` has any interior NULs.
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
    use c_str::CString;

260
    unsafe {
261 262
        with_env_lock(|| {
            let s = n.with_c_str(|buf| libc::getenv(buf));
263
            if s.is_null() {
264
                None
265
            } else {
266
                Some(CString::new(s, false).as_bytes_no_nul().to_owned())
267
            }
268
        })
269 270
    }
}
271

272
#[cfg(windows)]
273 274
/// Fetches the environment variable `n` from the current process, returning
/// None if the variable isn't set.
275 276
pub fn getenv(n: &str) -> Option<~str> {
    unsafe {
277
        with_env_lock(|| {
278
            use os::win32::{as_utf16_p, fill_utf16_buf_and_decode};
279 280
            as_utf16_p(n, |u| {
                fill_utf16_buf_and_decode(|buf, sz| {
281
                    libc::GetEnvironmentVariableW(u, buf, sz)
282 283 284
                })
            })
        })
285 286
    }
}
287

288 289 290 291 292 293 294
#[cfg(windows)]
/// Fetches the environment variable `n` byte vector from the current process,
/// returning None if the variable isn't set.
pub fn getenv_as_bytes(n: &str) -> Option<~[u8]> {
    getenv(n).map(|s| s.into_bytes())
}

295

296
#[cfg(unix)]
297 298
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
299 300 301 302
///
/// # Failure
///
/// Fails if `n` or `v` have any interior NULs.
303 304
pub fn setenv(n: &str, v: &str) {
    unsafe {
305 306 307
        with_env_lock(|| {
            n.with_c_str(|nbuf| {
                v.with_c_str(|vbuf| {
308
                    libc::funcs::posix01::unistd::setenv(nbuf, vbuf, 1);
309 310 311
                })
            })
        })
312 313
    }
}
314 315


316
#[cfg(windows)]
317 318
/// Sets the environment variable `n` to the value `v` for the currently running
/// process
319 320
pub fn setenv(n: &str, v: &str) {
    unsafe {
321
        with_env_lock(|| {
322
            use os::win32::as_utf16_p;
323 324
            as_utf16_p(n, |nbuf| {
                as_utf16_p(v, |vbuf| {
325
                    libc::SetEnvironmentVariableW(nbuf, vbuf);
326 327 328
                })
            })
        })
329 330 331
    }
}

C
Corey Richardson 已提交
332
/// Remove a variable from the environment entirely
333 334 335 336
///
/// # Failure
///
/// Fails (on unix) if `n` has any interior NULs.
C
Corey Richardson 已提交
337 338 339 340
pub fn unsetenv(n: &str) {
    #[cfg(unix)]
    fn _unsetenv(n: &str) {
        unsafe {
341 342
            with_env_lock(|| {
                n.with_c_str(|nbuf| {
C
Corey Richardson 已提交
343
                    libc::funcs::posix01::unistd::unsetenv(nbuf);
344 345
                })
            })
C
Corey Richardson 已提交
346 347 348 349 350
        }
    }
    #[cfg(windows)]
    fn _unsetenv(n: &str) {
        unsafe {
351
            with_env_lock(|| {
C
Corey Richardson 已提交
352
                use os::win32::as_utf16_p;
353
                as_utf16_p(n, |nbuf| {
C
Corey Richardson 已提交
354
                    libc::SetEnvironmentVariableW(nbuf, ptr::null());
355 356
                })
            })
C
Corey Richardson 已提交
357 358 359 360 361 362
        }
    }

    _unsetenv(n);
}

363
pub struct Pipe {
364
    input: c_int,
365 366
    out: c_int
}
367

368
#[cfg(unix)]
369
pub fn pipe() -> Pipe {
370
    unsafe {
371 372 373
        let mut fds = Pipe {input: 0,
                            out: 0};
        assert_eq!(libc::pipe(&mut fds.input), 0);
374
        return Pipe {input: fds.input, out: fds.out};
375
    }
376 377
}

378
#[cfg(windows)]
379
pub fn pipe() -> Pipe {
380 381 382 383 384
    unsafe {
        // Windows pipes work subtly differently than unix pipes, and their
        // inheritance has to be handled in a different way that I do not
        // fully understand. Here we explicitly make the pipe non-inheritable,
        // which means to pass it to a subprocess they need to be duplicated
385
        // first, as in std::run.
386 387
        let mut fds = Pipe {input: 0,
                    out: 0};
388
        let res = libc::pipe(&mut fds.input, 1024 as ::libc::c_uint,
389
                             (libc::O_BINARY | libc::O_NOINHERIT) as c_int);
390 391 392
        assert_eq!(res, 0);
        assert!((fds.input != -1 && fds.input != 0 ));
        assert!((fds.out != -1 && fds.input != 0));
393
        return Pipe {input: fds.input, out: fds.out};
394
    }
395 396
}

397
/// Returns the proper dll filename for the given basename of a file.
398
pub fn dll_filename(base: &str) -> ~str {
399
    format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
400 401
}

B
Ben Noordhuis 已提交
402
/// Optionally returns the filesystem path of the current executable which is
403
/// running. If any failure occurs, None is returned.
B
Ben Noordhuis 已提交
404
pub fn self_exe_name() -> Option<Path> {
405 406

    #[cfg(target_os = "freebsd")]
407
    fn load_self() -> Option<~[u8]> {
408
        unsafe {
409 410
            use libc::funcs::bsd44::*;
            use libc::consts::os::extra::*;
411
            use vec;
412 413 414
            let mib = ~[CTL_KERN as c_int,
                        KERN_PROC as c_int,
                        KERN_PROC_PATHNAME as c_int, -1 as c_int];
A
Alex Crichton 已提交
415
            let mut sz: libc::size_t = 0;
416
            let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
A
Alex Crichton 已提交
417 418
                             ptr::mut_null(), &mut sz, ptr::null(),
                             0u as libc::size_t);
419 420 421
            if err != 0 { return None; }
            if sz == 0 { return None; }
            let mut v: ~[u8] = vec::with_capacity(sz as uint);
422
            let err = sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint,
A
Alex Crichton 已提交
423 424
                             v.as_mut_ptr() as *mut c_void, &mut sz, ptr::null(),
                             0u as libc::size_t);
425 426
            if err != 0 { return None; }
            if sz == 0 { return None; }
427
            v.set_len(sz as uint - 1); // chop off trailing NUL
428
            Some(v)
429
        }
430 431 432
    }

    #[cfg(target_os = "linux")]
K
kyeongwoon 已提交
433
    #[cfg(target_os = "android")]
434
    fn load_self() -> Option<~[u8]> {
A
Alex Crichton 已提交
435
        use std::io;
436

A
Alex Crichton 已提交
437 438 439
        match io::fs::readlink(&Path::new("/proc/self/exe")) {
            Ok(path) => Some(path.as_vec().to_owned()),
            Err(..) => None
440 441 442
        }
    }

443
    #[cfg(target_os = "macos")]
444
    fn load_self() -> Option<~[u8]> {
445
        unsafe {
446
            use libc::funcs::extra::_NSGetExecutablePath;
447
            use vec;
448 449 450 451
            let mut sz: u32 = 0;
            _NSGetExecutablePath(ptr::mut_null(), &mut sz);
            if sz == 0 { return None; }
            let mut v: ~[u8] = vec::with_capacity(sz as uint);
452
            let err = _NSGetExecutablePath(v.as_mut_ptr() as *mut i8, &mut sz);
453
            if err != 0 { return None; }
454
            v.set_len(sz as uint - 1); // chop off trailing NUL
455
            Some(v)
456
        }
457 458
    }

459
    #[cfg(windows)]
460
    fn load_self() -> Option<~[u8]> {
461 462
        use str::OwnedStr;

463 464
        unsafe {
            use os::win32::fill_utf16_buf_and_decode;
465
            fill_utf16_buf_and_decode(|buf, sz| {
466
                libc::GetModuleFileNameW(0u as libc::DWORD, buf, sz)
467
            }).map(|s| s.into_bytes())
468
        }
469 470
    }

B
Ben Noordhuis 已提交
471 472 473 474 475 476 477 478
    load_self().and_then(Path::new_opt)
}

/// Optionally returns the filesystem path to the current executable which is
/// running. Like self_exe_name() but without the binary's name.
/// If any failure occurs, None is returned.
pub fn self_exe_path() -> Option<Path> {
    self_exe_name().map(|mut p| { p.pop(); p })
479 480
}

481 482 483 484 485 486 487 488 489 490 491 492 493
/**
 * Returns the path to the user's home directory, if known.
 *
 * On Unix, returns the value of the 'HOME' environment variable if it is set
 * and not equal to the empty string.
 *
 * On Windows, returns the value of the 'HOME' environment variable if it is
 * set and not equal to the empty string. Otherwise, returns the value of the
 * 'USERPROFILE' environment variable if it is set and not equal to the empty
 * string.
 *
 * Otherwise, homedir returns option::none.
 */
494
pub fn homedir() -> Option<Path> {
495
    // FIXME (#7188): getenv needs a ~[u8] variant
496
    return match getenv("HOME") {
497
        Some(ref p) if !p.is_empty() => Path::new_opt(p.as_slice()),
498
        _ => secondary()
499 500
    };

501
    #[cfg(unix)]
B
Brian Anderson 已提交
502 503
    fn secondary() -> Option<Path> {
        None
504 505
    }

506
    #[cfg(windows)]
B
Brian Anderson 已提交
507
    fn secondary() -> Option<Path> {
508
        getenv("USERPROFILE").and_then(|p| {
509
            if !p.is_empty() {
510
                Path::new_opt(p)
511
            } else {
B
Brian Anderson 已提交
512
                None
513
            }
514
        })
515 516 517
    }
}

518
/**
519
 * Returns the path to a temporary directory.
520 521 522
 *
 * On Unix, returns the value of the 'TMPDIR' environment variable if it is
 * set and non-empty and '/tmp' otherwise.
523 524
 * On Android, there is no global temporary folder (it is usually allocated
 * per-app), hence returns '/data/tmp' which is commonly used.
525 526
 *
 * On Windows, returns the value of, in order, the 'TMP', 'TEMP',
527 528
 * 'USERPROFILE' environment variable  if any are set and not the empty
 * string. Otherwise, tmpdir returns the path to the Windows directory.
529
 */
530
pub fn tmpdir() -> Path {
531 532
    return lookup();

B
Brian Anderson 已提交
533
    fn getenv_nonempty(v: &str) -> Option<Path> {
534
        match getenv(v) {
L
Luqman Aden 已提交
535
            Some(x) =>
536
                if x.is_empty() {
B
Brian Anderson 已提交
537
                    None
538
                } else {
539
                    Path::new_opt(x)
540
                },
B
Brian Anderson 已提交
541
            _ => None
542 543 544 545
        }
    }

    #[cfg(unix)]
546
    fn lookup() -> Path {
547
        if cfg!(target_os = "android") {
548
            Path::new("/data/tmp")
549
        } else {
550
            getenv_nonempty("TMPDIR").unwrap_or(Path::new("/tmp"))
551
        }
552 553 554
    }

    #[cfg(windows)]
555
    fn lookup() -> Path {
556 557 558
        getenv_nonempty("TMP").or(
            getenv_nonempty("TEMP").or(
                getenv_nonempty("USERPROFILE").or(
559
                   getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
560 561
    }
}
B
Brian Anderson 已提交
562

563 564 565 566 567
/**
 * Convert a relative path to an absolute path
 *
 * If the given path is relative, return it prepended with the current working
 * directory. If the given path is already an absolute path, return it
568
 * as is.
569
 */
570 571 572
// NB: this is here rather than in path because it is a form of environment
// querying; what it does depends on the process working directory, not just
// the input paths.
573
pub fn make_absolute(p: &Path) -> Path {
574 575
    if p.is_absolute() {
        p.clone()
576
    } else {
577
        let mut ret = getcwd();
578
        ret.push(p);
579
        ret
580
    }
581 582
}

583 584
/// Changes the current working directory to the specified path, returning
/// whether the change was completed successfully or not.
585
pub fn change_dir(p: &Path) -> bool {
B
Brian Anderson 已提交
586
    return chdir(p);
587

588
    #[cfg(windows)]
589
    fn chdir(p: &Path) -> bool {
590 591
        unsafe {
            use os::win32::as_utf16_p;
592
            return as_utf16_p(p.as_str().unwrap(), |buf| {
593
                libc::SetCurrentDirectoryW(buf) != (0 as libc::BOOL)
594
            });
595
        }
596 597
    }

598
    #[cfg(unix)]
599
    fn chdir(p: &Path) -> bool {
600
        p.with_c_str(|buf| {
E
Erick Tryzelaar 已提交
601
            unsafe {
602
                libc::chdir(buf) == (0 as c_int)
E
Erick Tryzelaar 已提交
603
            }
604
        })
605 606 607
    }
}

608
#[cfg(unix)]
609
/// Returns the platform-specific value of errno
610 611 612 613 614 615
pub fn errno() -> int {
    #[cfg(target_os = "macos")]
    #[cfg(target_os = "freebsd")]
    fn errno_location() -> *c_int {
        #[nolink]
        extern {
616
            fn __error() -> *c_int;
617 618 619 620 621 622 623 624 625 626 627
        }
        unsafe {
            __error()
        }
    }

    #[cfg(target_os = "linux")]
    #[cfg(target_os = "android")]
    fn errno_location() -> *c_int {
        #[nolink]
        extern {
628
            fn __errno_location() -> *c_int;
629 630 631 632 633 634 635 636 637 638 639 640
        }
        unsafe {
            __errno_location()
        }
    }

    unsafe {
        (*errno_location()) as int
    }
}

#[cfg(windows)]
641
/// Returns the platform-specific value of errno
642 643 644 645
pub fn errno() -> uint {
    use libc::types::os::arch::extra::DWORD;

    #[link_name = "kernel32"]
A
Alex Crichton 已提交
646
    extern "system" {
K
klutzy 已提交
647 648 649
        fn GetLastError() -> DWORD;
    }

650
    unsafe {
651
        GetLastError() as uint
652 653 654
    }
}

655
/// Get a string representing the platform-dependent last error
656
pub fn last_os_error() -> ~str {
657 658 659 660 661
    #[cfg(unix)]
    fn strerror() -> ~str {
        #[cfg(target_os = "macos")]
        #[cfg(target_os = "android")]
        #[cfg(target_os = "freebsd")]
A
Alex Crichton 已提交
662
        fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t)
663
                      -> c_int {
664 665
            #[nolink]
            extern {
A
Alex Crichton 已提交
666 667
                fn strerror_r(errnum: c_int, buf: *mut c_char,
                              buflen: libc::size_t) -> c_int;
668 669 670 671 672 673 674 675
            }
            unsafe {
                strerror_r(errnum, buf, buflen)
            }
        }

        // GNU libc provides a non-compliant version of strerror_r by default
        // and requires macros to instead use the POSIX compliant variant.
L
Luqman Aden 已提交
676
        // So we just use __xpg_strerror_r which is always POSIX compliant
677
        #[cfg(target_os = "linux")]
A
Alex Crichton 已提交
678 679
        fn strerror_r(errnum: c_int, buf: *mut c_char,
                      buflen: libc::size_t) -> c_int {
680 681
            #[nolink]
            extern {
682 683
                fn __xpg_strerror_r(errnum: c_int,
                                    buf: *mut c_char,
A
Alex Crichton 已提交
684
                                    buflen: libc::size_t)
685
                                    -> c_int;
686 687 688 689 690 691 692
            }
            unsafe {
                __xpg_strerror_r(errnum, buf, buflen)
            }
        }

        let mut buf = [0 as c_char, ..TMPBUF_SZ];
693

694 695
        let p = buf.as_mut_ptr();
        unsafe {
A
Alex Crichton 已提交
696
            if strerror_r(errno() as c_int, p, buf.len() as libc::size_t) < 0 {
697
                fail!("strerror_r failure");
698
            }
699 700 701

            str::raw::from_c_str(p as *c_char)
        }
702
    }
703 704 705

    #[cfg(windows)]
    fn strerror() -> ~str {
706
        use libc::types::os::arch::extra::DWORD;
707
        use libc::types::os::arch::extra::LPWSTR;
708
        use libc::types::os::arch::extra::LPVOID;
709
        use libc::types::os::arch::extra::WCHAR;
710 711

        #[link_name = "kernel32"]
A
Alex Crichton 已提交
712
        extern "system" {
713
            fn FormatMessageW(flags: DWORD,
K
klutzy 已提交
714 715 716
                              lpSrc: LPVOID,
                              msgId: DWORD,
                              langId: DWORD,
717
                              buf: LPWSTR,
K
klutzy 已提交
718 719 720 721 722
                              nsize: DWORD,
                              args: *c_void)
                              -> DWORD;
        }

723 724
        static FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000;
        static FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200;
725 726 727 728 729 730

        // This value is calculated from the macro
        // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT)
        let langId = 0x0800 as DWORD;
        let err = errno() as DWORD;

731
        let mut buf = [0 as WCHAR, ..TMPBUF_SZ];
732

733
        unsafe {
734 735 736 737 738 739 740 741 742 743 744
            let res = FormatMessageW(FORMAT_MESSAGE_FROM_SYSTEM |
                                     FORMAT_MESSAGE_IGNORE_INSERTS,
                                     ptr::mut_null(),
                                     err,
                                     langId,
                                     buf.as_mut_ptr(),
                                     buf.len() as DWORD,
                                     ptr::null());
            if res == 0 {
                fail!("[{}] FormatMessage failure", errno());
            }
745

746
            str::from_utf16(buf)
747 748 749 750
        }
    }

    strerror()
751
}
752

753 754
static mut EXIT_STATUS: AtomicInt = INIT_ATOMIC_INT;

755 756 757 758 759 760
/**
 * Sets the process exit code
 *
 * Sets the exit code returned by the process if all supervised tasks
 * terminate successfully (without failing). If the current root task fails
 * and is supervised by the scheduler then any user-specified exit status is
761 762 763
 * ignored and the process exits with the default failure status.
 *
 * Note that this is not synchronized against modifications of other threads.
764
 */
765
pub fn set_exit_status(code: int) {
766 767 768 769 770 771 772
    unsafe { EXIT_STATUS.store(code, SeqCst) }
}

/// Fetches the process's current exit code. This defaults to 0 and can change
/// by calling `set_exit_status`.
pub fn get_exit_status() -> int {
    unsafe { EXIT_STATUS.load(SeqCst) }
773
}
774

K
Kiet Tran 已提交
775
#[cfg(target_os = "macos")]
776 777 778
unsafe fn load_argc_and_argv(argc: int, argv: **c_char) -> ~[~[u8]] {
    use c_str::CString;

779
    let mut args = ~[];
D
Daniel Micay 已提交
780
    for i in range(0u, argc as uint) {
781
        args.push(CString::new(*argv.offset(i as int), false).as_bytes_no_nul().to_owned())
782
    }
L
Luqman Aden 已提交
783
    args
784 785
}

786 787 788 789 790 791
/**
 * Returns the command line arguments
 *
 * Returns a list of the command line arguments.
 */
#[cfg(target_os = "macos")]
792
fn real_args_as_bytes() -> ~[~[u8]] {
793
    unsafe {
794
        let (argc, argv) = (*_NSGetArgc() as int,
795 796
                            *_NSGetArgv() as **c_char);
        load_argc_and_argv(argc, argv)
797 798 799
    }
}

800
#[cfg(target_os = "linux")]
K
kyeongwoon 已提交
801
#[cfg(target_os = "android")]
802
#[cfg(target_os = "freebsd")]
803
fn real_args_as_bytes() -> ~[~[u8]] {
804 805
    use rt;

806 807
    match rt::args::clone() {
        Some(args) => args,
808
        None => fail!("process arguments not initialized")
809
    }
810 811
}

812 813 814 815 816
#[cfg(not(windows))]
fn real_args() -> ~[~str] {
    real_args_as_bytes().move_iter().map(|v| str::from_utf8_lossy(v).into_owned()).collect()
}

817
#[cfg(windows)]
818
fn real_args() -> ~[~str] {
819
    use vec;
820

821
    let mut nArgs: c_int = 0;
D
Daniel Micay 已提交
822
    let lpArgCount: *mut c_int = &mut nArgs;
T
Tim Chevalier 已提交
823 824
    let lpCmdLine = unsafe { GetCommandLineW() };
    let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
825 826

    let mut args = ~[];
D
Daniel Micay 已提交
827
    for i in range(0u, nArgs as uint) {
828 829
        unsafe {
            // Determine the length of this argument.
830
            let ptr = *szArgList.offset(i as int);
831
            let mut len = 0;
832
            while *ptr.offset(len as int) != 0 { len += 1; }
833 834

            // Push it onto the list.
835
            args.push(vec::raw::buf_as_slice(ptr, len,
836
                                             str::from_utf16));
837 838 839 840
        }
    }

    unsafe {
841
        LocalFree(szArgList as *c_void);
842 843 844 845 846
    }

    return args;
}

847 848 849 850 851
#[cfg(windows)]
fn real_args_as_bytes() -> ~[~[u8]] {
    real_args().move_iter().map(|s| s.into_bytes()).collect()
}

852 853
type LPCWSTR = *u16;

A
Alex Crichton 已提交
854
#[cfg(windows)]
K
klutzy 已提交
855
#[link_name="kernel32"]
A
Alex Crichton 已提交
856
extern "system" {
K
klutzy 已提交
857 858 859 860
    fn GetCommandLineW() -> LPCWSTR;
    fn LocalFree(ptr: *c_void);
}

A
Alex Crichton 已提交
861
#[cfg(windows)]
K
klutzy 已提交
862
#[link_name="shell32"]
A
Alex Crichton 已提交
863
extern "system" {
K
klutzy 已提交
864 865 866
    fn CommandLineToArgvW(lpCmdLine: LPCWSTR, pNumArgs: *mut c_int) -> **u16;
}

867 868
/// Returns the arguments which this program was started with (normally passed
/// via the command line).
869 870 871
///
/// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
/// See `str::from_utf8_lossy` for details.
872
pub fn args() -> ~[~str] {
873
    real_args()
874 875
}

876 877 878 879 880 881
/// Returns the arguments which this program was started with (normally passed
/// via the command line) as byte vectors.
pub fn args_as_bytes() -> ~[~[u8]] {
    real_args_as_bytes()
}

882 883 884 885 886 887 888
#[cfg(target_os = "macos")]
extern {
    // These functions are in crt_externs.h.
    pub fn _NSGetArgc() -> *c_int;
    pub fn _NSGetArgv() -> ***c_char;
}

889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911
// Round up `from` to be divisible by `to`
fn round_up(from: uint, to: uint) -> uint {
    let r = if from % to == 0 {
        from
    } else {
        from + to - (from % to)
    };
    if r == 0 {
        to
    } else {
        r
    }
}

#[cfg(unix)]
pub fn page_size() -> uint {
    unsafe {
        libc::sysconf(libc::_SC_PAGESIZE) as uint
    }
}

#[cfg(windows)]
pub fn page_size() -> uint {
V
Vadim Chugunov 已提交
912 913 914
    unsafe {
        let mut info = libc::SYSTEM_INFO::new();
        libc::GetSystemInfo(&mut info);
915

V
Vadim Chugunov 已提交
916 917
        return info.dwPageSize as uint;
    }
918 919
}

A
Alex Crichton 已提交
920 921 922 923
/// A memory mapped file or chunk of memory. This is a very system-specific
/// interface to the OS's memory mapping facilities (`mmap` on POSIX,
/// `VirtualAlloc`/`CreateFileMapping` on win32). It makes no attempt at
/// abstracting platform differences, besides in error values returned. Consider
C
Corey Richardson 已提交
924 925
/// yourself warned.
///
A
Alex Crichton 已提交
926 927
/// The memory map is released (unmapped) when the destructor is run, so don't
/// let it leave scope by accident if you want it to stick around.
928
pub struct MemoryMap {
C
Corey Richardson 已提交
929
    /// Pointer to the memory created or modified by this map.
930
    data: *mut u8,
C
Corey Richardson 已提交
931
    /// Number of bytes this map applies to
932
    len: uint,
C
Corey Richardson 已提交
933
    /// Type of mapping
934 935 936
    kind: MemoryMapKind
}

C
Corey Richardson 已提交
937
/// Type of memory map
938
pub enum MemoryMapKind {
A
Alex Crichton 已提交
939 940
    /// Virtual memory map. Usually used to change the permissions of a given
    /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
941
    MapFile(*u8),
A
Alex Crichton 已提交
942 943 944
    /// Virtual memory map. Usually used to change the permissions of a given
    /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
    /// Windows.
945 946 947
    MapVirtual
}

C
Corey Richardson 已提交
948
/// Options the memory map is created with
949
pub enum MapOption {
C
Corey Richardson 已提交
950
    /// The memory should be readable
951
    MapReadable,
C
Corey Richardson 已提交
952
    /// The memory should be writable
953
    MapWritable,
C
Corey Richardson 已提交
954
    /// The memory should be executable
955
    MapExecutable,
A
Alex Crichton 已提交
956 957
    /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
    /// POSIX.
958
    MapAddr(*u8),
C
Corey Richardson 已提交
959
    /// Create a memory mapping for a file with a given fd.
960
    MapFd(c_int),
A
Alex Crichton 已提交
961 962
    /// When using `MapFd`, the start of the map is `uint` bytes from the start
    /// of the file.
963
    MapOffset(uint),
A
Alex Crichton 已提交
964 965 966 967
    /// On POSIX, this can be used to specify the default flags passed to
    /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
    /// `MAP_ANON`. This will override both of those. This is platform-specific
    /// (the exact values used) and ignored on Windows.
968
    MapNonStandardFlags(c_int),
969 970
}

C
Corey Richardson 已提交
971
/// Possible errors when creating a map.
972
pub enum MapError {
C
Corey Richardson 已提交
973 974
    /// ## The following are POSIX-specific
    ///
A
Alex Crichton 已提交
975 976
    /// fd was not open for reading or, if using `MapWritable`, was not open for
    /// writing.
977
    ErrFdNotAvail,
C
Corey Richardson 已提交
978
    /// fd was not valid
979
    ErrInvalidFd,
A
Alex Crichton 已提交
980 981
    /// Either the address given by `MapAddr` or offset given by `MapOffset` was
    /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
982
    ErrUnaligned,
C
Corey Richardson 已提交
983
    /// With `MapFd`, the fd does not support mapping.
984
    ErrNoMapSupport,
A
Alex Crichton 已提交
985 986 987
    /// If using `MapAddr`, the address + `min_len` was outside of the process's
    /// address space. If using `MapFd`, the target of the fd didn't have enough
    /// resources to fulfill the request.
988
    ErrNoMem,
C
Corey Richardson 已提交
989
    /// A zero-length map was requested. This is invalid according to
A
Alex Crichton 已提交
990 991
    /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
    /// Not all platforms obey this, but this wrapper does.
C
Corey Richardson 已提交
992
    ErrZeroLength,
C
Corey Richardson 已提交
993
    /// Unrecognized error. The inner value is the unrecognized errno.
994
    ErrUnknown(int),
C
Corey Richardson 已提交
995 996
    /// ## The following are win32-specific
    ///
A
Alex Crichton 已提交
997 998
    /// Unsupported combination of protection flags
    /// (`MapReadable`/`MapWritable`/`MapExecutable`).
999
    ErrUnsupProt,
A
Alex Crichton 已提交
1000 1001
    /// When using `MapFd`, `MapOffset` was given (Windows does not support this
    /// at all)
1002
    ErrUnsupOffset,
C
Corey Richardson 已提交
1003
    /// When using `MapFd`, there was already a mapping to the file.
1004
    ErrAlreadyExists,
A
Alex Crichton 已提交
1005 1006
    /// Unrecognized error from `VirtualAlloc`. The inner value is the return
    /// value of GetLastError.
1007
    ErrVirtualAlloc(uint),
A
Alex Crichton 已提交
1008 1009
    /// Unrecognized error from `CreateFileMapping`. The inner value is the
    /// return value of `GetLastError`.
1010
    ErrCreateFileMappingW(uint),
A
Alex Crichton 已提交
1011 1012
    /// Unrecognized error from `MapViewOfFile`. The inner value is the return
    /// value of `GetLastError`.
1013 1014 1015
    ErrMapViewOfFile(uint)
}

1016
impl fmt::Show for MapError {
1017 1018
    fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
        let str = match *self {
1019 1020
            ErrFdNotAvail => "fd not available for reading or writing",
            ErrInvalidFd => "Invalid fd",
A
Alex Crichton 已提交
1021 1022 1023 1024
            ErrUnaligned => {
                "Unaligned address, invalid flags, negative length or \
                 unaligned offset"
            }
1025 1026 1027 1028 1029
            ErrNoMapSupport=> "File doesn't support mapping",
            ErrNoMem => "Invalid address, or not enough available memory",
            ErrUnsupProt => "Protection mode unsupported",
            ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
            ErrAlreadyExists => "File mapping for specified file already exists",
C
Corey Richardson 已提交
1030
            ErrZeroLength => "Zero-length mapping not allowed",
A
Alex Crichton 已提交
1031
            ErrUnknown(code) => {
A
Alex Crichton 已提交
1032
                return write!(out.buf, "Unknown error = {}", code)
A
Alex Crichton 已提交
1033 1034
            },
            ErrVirtualAlloc(code) => {
A
Alex Crichton 已提交
1035
                return write!(out.buf, "VirtualAlloc failure = {}", code)
A
Alex Crichton 已提交
1036
            },
1037
            ErrCreateFileMappingW(code) => {
A
Alex Crichton 已提交
1038
                return write!(out.buf, "CreateFileMappingW failure = {}", code)
1039 1040
            },
            ErrMapViewOfFile(code) => {
A
Alex Crichton 已提交
1041
                return write!(out.buf, "MapViewOfFile failure = {}", code)
1042 1043
            }
        };
A
Alex Crichton 已提交
1044
        write!(out.buf, "{}", str)
1045 1046 1047 1048 1049
    }
}

#[cfg(unix)]
impl MemoryMap {
A
Alex Crichton 已提交
1050 1051 1052
    /// Create a new mapping with the given `options`, at least `min_len` bytes
    /// long. `min_len` must be greater than zero; see the note on
    /// `ErrZeroLength`.
1053
    pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1054
        use libc::off_t;
1055
        use cmp::Equiv;
1056

C
Corey Richardson 已提交
1057 1058 1059
        if min_len == 0 {
            return Err(ErrZeroLength)
        }
1060 1061 1062 1063 1064
        let mut addr: *u8 = ptr::null();
        let mut prot = 0;
        let mut flags = libc::MAP_PRIVATE;
        let mut fd = -1;
        let mut offset = 0;
1065
        let mut custom_flags = false;
1066
        let len = round_up(min_len, page_size());
1067

D
Daniel Micay 已提交
1068
        for &o in options.iter() {
1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080
            match o {
                MapReadable => { prot |= libc::PROT_READ; },
                MapWritable => { prot |= libc::PROT_WRITE; },
                MapExecutable => { prot |= libc::PROT_EXEC; },
                MapAddr(addr_) => {
                    flags |= libc::MAP_FIXED;
                    addr = addr_;
                },
                MapFd(fd_) => {
                    flags |= libc::MAP_FILE;
                    fd = fd_;
                },
1081 1082
                MapOffset(offset_) => { offset = offset_ as off_t; },
                MapNonStandardFlags(f) => { custom_flags = true; flags = f },
1083 1084
            }
        }
1085
        if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
1086 1087

        let r = unsafe {
A
Alex Crichton 已提交
1088 1089
            libc::mmap(addr as *c_void, len as libc::size_t, prot, flags, fd,
                       offset)
1090
        };
1091
        if r.equiv(&libc::MAP_FAILED) {
1092 1093 1094 1095 1096 1097
            Err(match errno() as c_int {
                libc::EACCES => ErrFdNotAvail,
                libc::EBADF => ErrInvalidFd,
                libc::EINVAL => ErrUnaligned,
                libc::ENODEV => ErrNoMapSupport,
                libc::ENOMEM => ErrNoMem,
1098
                code => ErrUnknown(code as int)
1099 1100
            })
        } else {
1101
            Ok(MemoryMap {
1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
               data: r as *mut u8,
               len: len,
               kind: if fd == -1 {
                   MapVirtual
               } else {
                   MapFile(ptr::null())
               }
            })
        }
    }
V
Vadim Chugunov 已提交
1112

A
Alex Crichton 已提交
1113 1114
    /// Granularity that the offset or address must be for `MapOffset` and
    /// `MapAddr` respectively.
V
Vadim Chugunov 已提交
1115 1116 1117
    pub fn granularity() -> uint {
        page_size()
    }
1118 1119 1120 1121
}

#[cfg(unix)]
impl Drop for MemoryMap {
C
Corey Richardson 已提交
1122
    /// Unmap the mapping. Fails the task if `munmap` fails.
D
Daniel Micay 已提交
1123
    fn drop(&mut self) {
C
Corey Richardson 已提交
1124 1125
        if self.len == 0 { /* workaround for dummy_stack */ return; }

1126
        unsafe {
1127
            match libc::munmap(self.data as *c_void, self.len as libc::size_t) {
1128
                0 => (),
A
Alex Crichton 已提交
1129
                -1 => match errno() as c_int {
1130 1131
                    libc::EINVAL => error!("invalid addr or len"),
                    e => error!("unknown errno={}", e)
A
Alex Crichton 已提交
1132
                },
1133
                r => error!("Unexpected result {}", r)
1134 1135 1136 1137 1138 1139 1140
            }
        }
    }
}

#[cfg(windows)]
impl MemoryMap {
C
Corey Richardson 已提交
1141
    /// Create a new mapping with the given `options`, at least `min_len` bytes long.
1142
    pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
1143 1144 1145 1146 1147 1148 1149 1150
        use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};

        let mut lpAddress: LPVOID = ptr::mut_null();
        let mut readable = false;
        let mut writable = false;
        let mut executable = false;
        let mut fd: c_int = -1;
        let mut offset: uint = 0;
1151
        let len = round_up(min_len, page_size());
1152

D
Daniel Micay 已提交
1153
        for &o in options.iter() {
1154 1155 1156 1157 1158 1159
            match o {
                MapReadable => { readable = true; },
                MapWritable => { writable = true; },
                MapExecutable => { executable = true; }
                MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
                MapFd(fd_) => { fd = fd_; },
1160
                MapOffset(offset_) => { offset = offset_; },
A
Alex Crichton 已提交
1161 1162 1163 1164
                MapNonStandardFlags(f) => {
                    info!("MemoryMap::new: MapNonStandardFlags used on \
                           Windows: {}", f)
                }
1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
            }
        }

        let flProtect = match (executable, readable, writable) {
            (false, false, false) if fd == -1 => libc::PAGE_NOACCESS,
            (false, true, false) => libc::PAGE_READONLY,
            (false, true, true) => libc::PAGE_READWRITE,
            (true, false, false) if fd == -1 => libc::PAGE_EXECUTE,
            (true, true, false) => libc::PAGE_EXECUTE_READ,
            (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
            _ => return Err(ErrUnsupProt)
        };

        if fd == -1 {
            if offset != 0 {
                return Err(ErrUnsupOffset);
            }
            let r = unsafe {
                libc::VirtualAlloc(lpAddress,
1184
                                   len as SIZE_T,
1185 1186 1187 1188 1189
                                   libc::MEM_COMMIT | libc::MEM_RESERVE,
                                   flProtect)
            };
            match r as uint {
                0 => Err(ErrVirtualAlloc(errno())),
1190
                _ => Ok(MemoryMap {
1191 1192 1193 1194 1195 1196
                   data: r as *mut u8,
                   len: len,
                   kind: MapVirtual
                })
            }
        } else {
V
Vadim Chugunov 已提交
1197 1198 1199 1200 1201 1202 1203
            let dwDesiredAccess = match (executable, readable, writable) {
                (false, true, false) => libc::FILE_MAP_READ,
                (false, true, true) => libc::FILE_MAP_WRITE,
                (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
                (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
                _ => return Err(ErrUnsupProt) // Actually, because of the check above,
                                              // we should never get here.
1204 1205 1206 1207 1208 1209
            };
            unsafe {
                let hFile = libc::get_osfhandle(fd) as HANDLE;
                let mapping = libc::CreateFileMappingW(hFile,
                                                       ptr::mut_null(),
                                                       flProtect,
V
Vadim Chugunov 已提交
1210 1211
                                                       0,
                                                       0,
1212 1213 1214 1215 1216 1217 1218 1219 1220
                                                       ptr::null());
                if mapping == ptr::mut_null() {
                    return Err(ErrCreateFileMappingW(errno()));
                }
                if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
                    return Err(ErrAlreadyExists);
                }
                let r = libc::MapViewOfFile(mapping,
                                            dwDesiredAccess,
V
Vadim Chugunov 已提交
1221
                                            ((len as u64) >> 32) as DWORD,
1222 1223 1224 1225
                                            (offset & 0xffff_ffff) as DWORD,
                                            0);
                match r as uint {
                    0 => Err(ErrMapViewOfFile(errno())),
1226
                    _ => Ok(MemoryMap {
1227 1228
                       data: r as *mut u8,
                       len: len,
1229
                       kind: MapFile(mapping as *u8)
1230 1231 1232 1233 1234
                    })
                }
            }
        }
    }
V
Vadim Chugunov 已提交
1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245

    /// Granularity of MapAddr() and MapOffset() parameter values.
    /// This may be greater than the value returned by page_size().
    pub fn granularity() -> uint {
        unsafe {
            let mut info = libc::SYSTEM_INFO::new();
            libc::GetSystemInfo(&mut info);

            return info.dwAllocationGranularity as uint;
        }
    }
1246 1247 1248 1249
}

#[cfg(windows)]
impl Drop for MemoryMap {
A
Alex Crichton 已提交
1250 1251
    /// Unmap the mapping. Fails the task if any of `VirtualFree`,
    /// `UnmapViewOfFile`, or `CloseHandle` fail.
D
Daniel Micay 已提交
1252
    fn drop(&mut self) {
1253
        use libc::types::os::arch::extra::{LPCVOID, HANDLE};
V
Vadim Chugunov 已提交
1254
        use libc::consts::os::extra::FALSE;
A
Alex Crichton 已提交
1255
        if self.len == 0 { return }
1256 1257 1258

        unsafe {
            match self.kind {
V
Vadim Chugunov 已提交
1259
                MapVirtual => {
1260
                    if libc::VirtualFree(self.data as *mut c_void, 0,
A
Alex Crichton 已提交
1261
                                         libc::MEM_RELEASE) == 0 {
1262
                        error!("VirtualFree failed: {}", errno());
V
Vadim Chugunov 已提交
1263
                    }
1264 1265
                },
                MapFile(mapping) => {
V
Vadim Chugunov 已提交
1266
                    if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1267
                        error!("UnmapViewOfFile failed: {}", errno());
1268
                    }
V
Vadim Chugunov 已提交
1269
                    if libc::CloseHandle(mapping as HANDLE) == FALSE {
1270
                        error!("CloseHandle failed: {}", errno());
1271 1272 1273 1274 1275 1276 1277
                    }
                }
            }
        }
    }
}

1278
pub mod consts {
1279

I
ILyoan 已提交
1280
    #[cfg(unix)]
1281
    pub use os::consts::unix::*;
1282

I
ILyoan 已提交
1283
    #[cfg(windows)]
1284
    pub use os::consts::windows::*;
1285

I
ILyoan 已提交
1286
    #[cfg(target_os = "macos")]
1287
    pub use os::consts::macos::*;
I
ILyoan 已提交
1288 1289

    #[cfg(target_os = "freebsd")]
1290
    pub use os::consts::freebsd::*;
I
ILyoan 已提交
1291 1292

    #[cfg(target_os = "linux")]
1293
    pub use os::consts::linux::*;
I
ILyoan 已提交
1294

K
kyeongwoon 已提交
1295
    #[cfg(target_os = "android")]
1296
    pub use os::consts::android::*;
K
kyeongwoon 已提交
1297

I
ILyoan 已提交
1298
    #[cfg(target_os = "win32")]
1299
    pub use os::consts::win32::*;
1300

1301 1302 1303 1304 1305 1306 1307 1308 1309 1310
    #[cfg(target_arch = "x86")]
    pub use os::consts::x86::*;

    #[cfg(target_arch = "x86_64")]
    pub use os::consts::x86_64::*;

    #[cfg(target_arch = "arm")]
    pub use os::consts::arm::*;

    #[cfg(target_arch = "mips")]
1311
    pub use os::consts::mips::*;
1312 1313 1314 1315 1316 1317 1318 1319 1320

    pub mod unix {
        pub static FAMILY: &'static str = "unix";
    }

    pub mod windows {
        pub static FAMILY: &'static str = "windows";
    }

I
ILyoan 已提交
1321
    pub mod macos {
1322 1323 1324
        pub static SYSNAME: &'static str = "macos";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".dylib";
1325
        pub static DLL_EXTENSION: &'static str = "dylib";
1326
        pub static EXE_SUFFIX: &'static str = "";
1327
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1328 1329 1330
    }

    pub mod freebsd {
1331 1332 1333
        pub static SYSNAME: &'static str = "freebsd";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1334
        pub static DLL_EXTENSION: &'static str = "so";
1335
        pub static EXE_SUFFIX: &'static str = "";
1336
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1337 1338 1339
    }

    pub mod linux {
1340 1341 1342
        pub static SYSNAME: &'static str = "linux";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1343
        pub static DLL_EXTENSION: &'static str = "so";
1344
        pub static EXE_SUFFIX: &'static str = "";
1345
        pub static EXE_EXTENSION: &'static str = "";
I
ILyoan 已提交
1346
    }
K
kyeongwoon 已提交
1347 1348

    pub mod android {
1349 1350 1351
        pub static SYSNAME: &'static str = "android";
        pub static DLL_PREFIX: &'static str = "lib";
        pub static DLL_SUFFIX: &'static str = ".so";
1352
        pub static DLL_EXTENSION: &'static str = "so";
1353
        pub static EXE_SUFFIX: &'static str = "";
1354
        pub static EXE_EXTENSION: &'static str = "";
K
kyeongwoon 已提交
1355
    }
1356

I
ILyoan 已提交
1357
    pub mod win32 {
1358 1359 1360
        pub static SYSNAME: &'static str = "win32";
        pub static DLL_PREFIX: &'static str = "";
        pub static DLL_SUFFIX: &'static str = ".dll";
1361
        pub static DLL_EXTENSION: &'static str = "dll";
1362
        pub static EXE_SUFFIX: &'static str = ".exe";
1363
        pub static EXE_EXTENSION: &'static str = "exe";
I
ILyoan 已提交
1364 1365 1366 1367
    }


    pub mod x86 {
1368
        pub static ARCH: &'static str = "x86";
I
ILyoan 已提交
1369 1370
    }
    pub mod x86_64 {
1371
        pub static ARCH: &'static str = "x86_64";
I
ILyoan 已提交
1372 1373
    }
    pub mod arm {
1374
        pub static ARCH: &'static str = "arm";
I
ILyoan 已提交
1375
    }
J
Jyun-Yan You 已提交
1376
    pub mod mips {
1377
        pub static ARCH: &'static str = "mips";
J
Jyun-Yan You 已提交
1378
    }
I
ILyoan 已提交
1379
}
1380 1381 1382

#[cfg(test)]
mod tests {
1383
    use prelude::*;
1384
    use c_str::ToCStr;
1385
    use option;
1386
    use os::{env, getcwd, getenv, make_absolute, args};
1387
    use os::{setenv, unsetenv};
1388
    use os;
1389
    use rand::Rng;
1390
    use rand;
1391

1392

1393
    #[test]
1394
    pub fn last_os_error() {
1395
        debug!("{}", os::last_os_error());
1396
    }
1397

1398 1399
    #[test]
    pub fn test_args() {
1400
        let a = args();
P
Patrick Walton 已提交
1401
        assert!(a.len() >= 1);
1402 1403
    }

1404
    fn make_rand_name() -> ~str {
P
Patrick Walton 已提交
1405
        let mut rng = rand::rng();
1406
        let n = ~"TEST" + rng.gen_ascii_str(10u);
P
Patrick Walton 已提交
1407
        assert!(getenv(n).is_none());
L
Luqman Aden 已提交
1408
        n
1409 1410 1411 1412 1413
    }

    #[test]
    fn test_setenv() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1414
        setenv(n, "VALUE");
1415
        assert_eq!(getenv(n), option::Some(~"VALUE"));
1416 1417
    }

C
Corey Richardson 已提交
1418 1419 1420
    #[test]
    fn test_unsetenv() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1421
        setenv(n, "VALUE");
C
Corey Richardson 已提交
1422
        unsetenv(n);
1423
        assert_eq!(getenv(n), option::None);
C
Corey Richardson 已提交
1424 1425
    }

1426
    #[test]
1427
    #[ignore]
1428 1429
    fn test_setenv_overwrite() {
        let n = make_rand_name();
E
Erick Tryzelaar 已提交
1430 1431
        setenv(n, "1");
        setenv(n, "2");
1432
        assert_eq!(getenv(n), option::Some(~"2"));
E
Erick Tryzelaar 已提交
1433
        setenv(n, "");
1434
        assert_eq!(getenv(n), option::Some(~""));
1435 1436 1437 1438 1439
    }

    // Windows GetEnvironmentVariable requires some extra work to make sure
    // the buffer the variable is copied into is the right size
    #[test]
1440
    #[ignore]
1441
    fn test_getenv_big() {
1442
        let mut s = ~"";
1443
        let mut i = 0;
1444 1445 1446 1447
        while i < 100 {
            s = s + "aaaaaaaaaa";
            i += 1;
        }
1448 1449
        let n = make_rand_name();
        setenv(n, s);
1450
        debug!("{}", s.clone());
1451
        assert_eq!(getenv(n), option::Some(s));
1452 1453
    }

B
Ben Noordhuis 已提交
1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464
    #[test]
    fn test_self_exe_name() {
        let path = os::self_exe_name();
        assert!(path.is_some());
        let path = path.unwrap();
        debug!("{:?}", path.clone());

        // Hard to test this function
        assert!(path.is_absolute());
    }

1465 1466 1467
    #[test]
    fn test_self_exe_path() {
        let path = os::self_exe_path();
P
Patrick Walton 已提交
1468
        assert!(path.is_some());
1469
        let path = path.unwrap();
1470
        debug!("{:?}", path.clone());
1471 1472

        // Hard to test this function
1473
        assert!(path.is_absolute());
1474 1475 1476
    }

    #[test]
1477
    #[ignore]
1478 1479
    fn test_env_getenv() {
        let e = env();
Y
Youngmin Yoo 已提交
1480
        assert!(e.len() > 0u);
D
Daniel Micay 已提交
1481
        for p in e.iter() {
1482
            let (n, v) = (*p).clone();
1483
            debug!("{:?}", n.clone());
1484 1485 1486 1487
            let v2 = getenv(n);
            // MingW seems to set some funky environment variables like
            // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
            // from env() but not visible from getenv().
P
Patrick Walton 已提交
1488
            assert!(v2.is_none() || v2 == option::Some(v));
1489 1490 1491 1492 1493 1494 1495
        }
    }

    #[test]
    fn test_env_setenv() {
        let n = make_rand_name();

1496
        let mut e = env();
E
Erick Tryzelaar 已提交
1497
        setenv(n, "VALUE");
1498
        assert!(!e.contains(&(n.clone(), ~"VALUE")));
1499 1500

        e = env();
1501
        assert!(e.contains(&(n, ~"VALUE")));
1502 1503
    }

1504 1505
    #[test]
    fn test() {
1506
        assert!((!Path::new("test-path").is_absolute()));
1507

1508
        let cwd = getcwd();
1509
        debug!("Current working directory: {}", cwd.display());
1510

1511 1512
        debug!("{:?}", make_absolute(&Path::new("test-path")));
        debug!("{:?}", make_absolute(&Path::new("/usr/bin")));
1513 1514 1515
    }

    #[test]
1516
    #[cfg(unix)]
1517
    fn homedir() {
E
Erick Tryzelaar 已提交
1518
        let oldhome = getenv("HOME");
1519

E
Erick Tryzelaar 已提交
1520
        setenv("HOME", "/home/MountainView");
1521
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1522

E
Erick Tryzelaar 已提交
1523
        setenv("HOME", "");
P
Patrick Walton 已提交
1524
        assert!(os::homedir().is_none());
1525

D
Daniel Micay 已提交
1526
        for s in oldhome.iter() { setenv("HOME", *s) }
1527 1528 1529
    }

    #[test]
1530
    #[cfg(windows)]
1531 1532
    fn homedir() {

E
Erick Tryzelaar 已提交
1533 1534
        let oldhome = getenv("HOME");
        let olduserprofile = getenv("USERPROFILE");
1535

E
Erick Tryzelaar 已提交
1536 1537
        setenv("HOME", "");
        setenv("USERPROFILE", "");
1538

P
Patrick Walton 已提交
1539
        assert!(os::homedir().is_none());
1540

E
Erick Tryzelaar 已提交
1541
        setenv("HOME", "/home/MountainView");
1542
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1543

E
Erick Tryzelaar 已提交
1544
        setenv("HOME", "");
1545

E
Erick Tryzelaar 已提交
1546
        setenv("USERPROFILE", "/home/MountainView");
1547
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1548

E
Erick Tryzelaar 已提交
1549 1550
        setenv("HOME", "/home/MountainView");
        setenv("USERPROFILE", "/home/PaloAlto");
1551
        assert_eq!(os::homedir(), Some(Path::new("/home/MountainView")));
1552

1553 1554
        for s in oldhome.iter() { setenv("HOME", *s) }
        for s in olduserprofile.iter() { setenv("USERPROFILE", *s) }
1555 1556
    }

1557 1558 1559 1560
    #[test]
    fn memory_map_rw() {
        use result::{Ok, Err};

1561
        let chunk = match os::MemoryMap::new(16, [
1562 1563 1564 1565
            os::MapReadable,
            os::MapWritable
        ]) {
            Ok(chunk) => chunk,
C
Corey Richardson 已提交
1566
            Err(msg) => fail!("{}", msg)
1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580
        };
        assert!(chunk.len >= 16);

        unsafe {
            *chunk.data = 0xBE;
            assert!(*chunk.data == 0xBE);
        }
    }

    #[test]
    fn memory_map_file() {
        use result::{Ok, Err};
        use os::*;
        use libc::*;
A
Alex Crichton 已提交
1581
        use io::fs;
1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595

        #[cfg(unix)]
        fn lseek_(fd: c_int, size: uint) {
            unsafe {
                assert!(lseek(fd, size as off_t, SEEK_SET) == size as off_t);
            }
        }
        #[cfg(windows)]
        fn lseek_(fd: c_int, size: uint) {
           unsafe {
               assert!(lseek(fd, size as c_long, SEEK_SET) == size as c_long);
           }
        }

1596
        let mut path = tmpdir();
1597
        path.push("mmap_file.tmp");
V
Vadim Chugunov 已提交
1598
        let size = MemoryMap::granularity() * 2;
1599 1600

        let fd = unsafe {
1601
            let fd = path.with_c_str(|path| {
1602
                open(path, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)
1603
            });
1604
            lseek_(fd, size);
1605
            "x".with_c_str(|x| assert!(write(fd, x as *c_void, 1) == 1));
1606 1607
            fd
        };
1608
        let chunk = match MemoryMap::new(size / 2, [
1609 1610 1611 1612 1613 1614
            MapReadable,
            MapWritable,
            MapFd(fd),
            MapOffset(size / 2)
        ]) {
            Ok(chunk) => chunk,
1615
            Err(msg) => fail!("{}", msg)
1616 1617 1618 1619 1620 1621 1622 1623
        };
        assert!(chunk.len > 0);

        unsafe {
            *chunk.data = 0xbe;
            assert!(*chunk.data == 0xbe);
            close(fd);
        }
1624
        drop(chunk);
1625

1626
        fs::unlink(&path).unwrap();
1627 1628
    }

1629
    // More recursive_mkdir tests are in extra::tempfile
1630
}