]> git.lizzy.rs Git - rust.git/blob - src/libstd/os.rs
Auto merge of #22517 - brson:relnotes, r=Gankro
[rust.git] / src / libstd / os.rs
1 // Copyright 2012-2015 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 //! Higher-level interfaces to libc::* functions and operating system services.
12 //!
13 //! In general these take and return rust types, use rust idioms (enums,
14 //! closures, vectors) rather than C idioms, and do more extensive safety
15 //! checks.
16 //!
17 //! This module is not meant to only contain 1:1 mappings to libc entries; any
18 //! os-interface code that is reasonably useful and broadly applicable can go
19 //! here. Including utility routines that merely build on other os code.
20 //!
21 //! We assume the general case is that users do not care, and do not want to be
22 //! made to care, which operating system they are on. While they may want to
23 //! special case various special cases -- and so we will not _hide_ the facts of
24 //! which OS the user is on -- they should be given the opportunity to write
25 //! OS-ignorant code by default.
26
27 #![unstable(feature = "os")]
28
29 #![allow(missing_docs)]
30 #![allow(non_snake_case)]
31 #![allow(unused_imports)]
32
33 use self::MemoryMapKind::*;
34 use self::MapOption::*;
35 use self::MapError::*;
36
37 use boxed::Box;
38 use clone::Clone;
39 use env;
40 use error::{FromError, Error};
41 use ffi::{OsString, OsStr};
42 use fmt;
43 use iter::{Iterator, IteratorExt};
44 use libc::{c_void, c_int, c_char};
45 use libc;
46 use marker::{Copy, Send};
47 use old_io::{IoResult, IoError};
48 use ops::{Drop, FnOnce};
49 use option::Option::{Some, None};
50 use option::Option;
51 use old_path::{Path, GenericPath, BytesContainer};
52 use ptr::PtrExt;
53 use ptr;
54 use result::Result::{Err, Ok};
55 use result::Result;
56 use slice::{AsSlice, SliceExt};
57 use str::{Str, StrExt};
58 use str;
59 use string::{String, ToString};
60 use sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT, Ordering};
61 use sys::os as os_imp;
62 use sys;
63 use vec::Vec;
64
65 #[cfg(unix)] use ffi::{self, CString};
66
67 #[cfg(unix)] pub use sys::ext as unix;
68 #[cfg(windows)] pub use sys::ext as windows;
69
70 /// Get the number of cores available
71 pub fn num_cpus() -> uint {
72     unsafe {
73         return rust_get_num_cpus() as uint;
74     }
75
76     extern {
77         fn rust_get_num_cpus() -> libc::uintptr_t;
78     }
79 }
80
81 pub const TMPBUF_SZ : uint = 1000;
82
83 /// Returns the current working directory as a `Path`.
84 ///
85 /// # Errors
86 ///
87 /// Returns an `Err` if the current working directory value is invalid.
88 /// Possible cases:
89 ///
90 /// * Current directory does not exist.
91 /// * There are insufficient permissions to access the current directory.
92 /// * The internal buffer is not large enough to hold the path.
93 ///
94 /// # Example
95 ///
96 /// ```rust
97 /// use std::os;
98 ///
99 /// // We assume that we are in a valid directory.
100 /// let current_working_directory = os::getcwd().unwrap();
101 /// println!("The current directory is {:?}", current_working_directory.display());
102 /// ```
103 #[deprecated(since = "1.0.0", reason = "renamed to std::env::current_dir")]
104 #[unstable(feature = "os")]
105 pub fn getcwd() -> IoResult<Path> {
106     env::current_dir()
107 }
108
109 /// Returns a vector of (variable, value) pairs, for all the environment
110 /// variables of the current process.
111 ///
112 /// Invalid UTF-8 bytes are replaced with \uFFFD. See `String::from_utf8_lossy()`
113 /// for details.
114 ///
115 /// # Example
116 ///
117 /// ```rust
118 /// use std::os;
119 ///
120 /// // We will iterate through the references to the element returned by os::env();
121 /// for &(ref key, ref value) in os::env().iter() {
122 ///     println!("'{}': '{}'", key, value );
123 /// }
124 /// ```
125 #[deprecated(since = "1.0.0", reason = "use env::vars instead")]
126 #[unstable(feature = "os")]
127 pub fn env() -> Vec<(String,String)> {
128     env::vars_os().map(|(k, v)| {
129         (k.to_string_lossy().into_owned(), v.to_string_lossy().into_owned())
130     }).collect()
131 }
132
133 /// Returns a vector of (variable, value) byte-vector pairs for all the
134 /// environment variables of the current process.
135 #[deprecated(since = "1.0.0", reason = "use env::vars_os instead")]
136 #[unstable(feature = "os")]
137 pub fn env_as_bytes() -> Vec<(Vec<u8>, Vec<u8>)> {
138     env::vars_os().map(|(k, v)| (byteify(k), byteify(v))).collect()
139 }
140
141 /// Fetches the environment variable `n` from the current process, returning
142 /// None if the variable isn't set.
143 ///
144 /// Any invalid UTF-8 bytes in the value are replaced by \uFFFD. See
145 /// `String::from_utf8_lossy()` for details.
146 ///
147 /// # Panics
148 ///
149 /// Panics if `n` has any interior NULs.
150 ///
151 /// # Example
152 ///
153 /// ```rust
154 /// use std::os;
155 ///
156 /// let key = "HOME";
157 /// match os::getenv(key) {
158 ///     Some(val) => println!("{}: {}", key, val),
159 ///     None => println!("{} is not defined in the environment.", key)
160 /// }
161 /// ```
162 #[deprecated(since = "1.0.0", reason = "use env::var instead")]
163 #[unstable(feature = "os")]
164 pub fn getenv(n: &str) -> Option<String> {
165     env::var(n).ok()
166 }
167
168 /// Fetches the environment variable `n` byte vector from the current process,
169 /// returning None if the variable isn't set.
170 ///
171 /// # Panics
172 ///
173 /// Panics if `n` has any interior NULs.
174 #[deprecated(since = "1.0.0", reason = "use env::var_os instead")]
175 #[unstable(feature = "os")]
176 pub fn getenv_as_bytes(n: &str) -> Option<Vec<u8>> {
177     env::var_os(n).map(byteify)
178 }
179
180 #[cfg(unix)]
181 fn byteify(s: OsString) -> Vec<u8> {
182     use os::unix::*;
183     s.into_vec()
184 }
185 #[cfg(windows)]
186 fn byteify(s: OsString) -> Vec<u8> {
187     s.to_string_lossy().as_bytes().to_vec()
188 }
189
190 /// Sets the environment variable `n` to the value `v` for the currently running
191 /// process.
192 ///
193 /// # Example
194 ///
195 /// ```rust
196 /// use std::os;
197 ///
198 /// let key = "KEY";
199 /// os::setenv(key, "VALUE");
200 /// match os::getenv(key) {
201 ///     Some(ref val) => println!("{}: {}", key, val),
202 ///     None => println!("{} is not defined in the environment.", key)
203 /// }
204 /// ```
205 #[deprecated(since = "1.0.0", reason = "renamed to env::set_var")]
206 #[unstable(feature = "os")]
207 pub fn setenv<T: BytesContainer>(n: &str, v: T) {
208     #[cfg(unix)]
209     fn _setenv(n: &str, v: &[u8]) {
210         use os::unix::*;
211         let v: OsString = OsStringExt::from_vec(v.to_vec());
212         env::set_var(n, &v)
213     }
214
215     #[cfg(windows)]
216     fn _setenv(n: &str, v: &[u8]) {
217         let v = str::from_utf8(v).unwrap();
218         env::set_var(n, v)
219     }
220
221     _setenv(n, v.container_as_bytes())
222 }
223
224 /// Remove a variable from the environment entirely.
225 #[deprecated(since = "1.0.0", reason = "renamed to env::remove_var")]
226 #[unstable(feature = "os")]
227 pub fn unsetenv(n: &str) {
228     env::remove_var(n)
229 }
230
231 /// Parses input according to platform conventions for the `PATH`
232 /// environment variable.
233 ///
234 /// # Example
235 /// ```rust
236 /// use std::os;
237 ///
238 /// let key = "PATH";
239 /// match os::getenv_as_bytes(key) {
240 ///     Some(paths) => {
241 ///         for path in os::split_paths(paths).iter() {
242 ///             println!("'{}'", path.display());
243 ///         }
244 ///     }
245 ///     None => println!("{} is not defined in the environment.", key)
246 /// }
247 /// ```
248 #[deprecated(since = "1.0.0", reason = "renamed to env::split_paths")]
249 #[unstable(feature = "os")]
250 pub fn split_paths<T: BytesContainer>(unparsed: T) -> Vec<Path> {
251     let b = unparsed.container_as_bytes();
252     let s = str::from_utf8(b).unwrap();
253     env::split_paths(s).collect()
254 }
255
256 /// Joins a collection of `Path`s appropriately for the `PATH`
257 /// environment variable.
258 ///
259 /// Returns a `Vec<u8>` on success, since `Path`s are not utf-8
260 /// encoded on all platforms.
261 ///
262 /// Returns an `Err` (containing an error message) if one of the input
263 /// `Path`s contains an invalid character for constructing the `PATH`
264 /// variable (a double quote on Windows or a colon on Unix).
265 ///
266 /// # Example
267 ///
268 /// ```rust
269 /// use std::os;
270 /// use std::old_path::Path;
271 ///
272 /// let key = "PATH";
273 /// let mut paths = os::getenv_as_bytes(key).map_or(Vec::new(), os::split_paths);
274 /// paths.push(Path::new("/home/xyz/bin"));
275 /// os::setenv(key, os::join_paths(paths.as_slice()).unwrap());
276 /// ```
277 #[deprecated(since = "1.0.0", reason = "renamed to env::join_paths")]
278 #[unstable(feature = "os")]
279 pub fn join_paths<T: BytesContainer>(paths: &[T]) -> Result<Vec<u8>, &'static str> {
280     env::join_paths(paths.iter().map(|s| {
281         str::from_utf8(s.container_as_bytes()).unwrap()
282     })).map(|s| {
283         s.to_string_lossy().into_owned().into_bytes()
284     }).map_err(|_| "failed to join paths")
285 }
286
287 /// A low-level OS in-memory pipe.
288 #[derive(Copy)]
289 pub struct Pipe {
290     /// A file descriptor representing the reading end of the pipe. Data written
291     /// on the `out` file descriptor can be read from this file descriptor.
292     pub reader: c_int,
293     /// A file descriptor representing the write end of the pipe. Data written
294     /// to this file descriptor can be read from the `input` file descriptor.
295     pub writer: c_int,
296 }
297
298 /// Creates a new low-level OS in-memory pipe.
299 ///
300 /// This function can fail to succeed if there are no more resources available
301 /// to allocate a pipe.
302 ///
303 /// This function is also unsafe as there is no destructor associated with the
304 /// `Pipe` structure will return. If it is not arranged for the returned file
305 /// descriptors to be closed, the file descriptors will leak. For safe handling
306 /// of this scenario, use `std::old_io::PipeStream` instead.
307 pub unsafe fn pipe() -> IoResult<Pipe> {
308     let (reader, writer) = try!(sys::os::pipe());
309     Ok(Pipe {
310         reader: reader.unwrap(),
311         writer: writer.unwrap(),
312     })
313 }
314
315 /// Returns the proper dll filename for the given basename of a file
316 /// as a String.
317 #[cfg(not(target_os="ios"))]
318 #[deprecated(since = "1.0.0", reason = "this function will be removed, use the constants directly")]
319 #[unstable(feature = "os")]
320 #[allow(deprecated)]
321 pub fn dll_filename(base: &str) -> String {
322     format!("{}{}{}", consts::DLL_PREFIX, base, consts::DLL_SUFFIX)
323 }
324
325 /// Optionally returns the filesystem path to the current executable which is
326 /// running but with the executable name.
327 ///
328 /// # Examples
329 ///
330 /// ```rust
331 /// use std::os;
332 ///
333 /// match os::self_exe_name() {
334 ///     Some(exe_path) => println!("Path of this executable is: {}", exe_path.display()),
335 ///     None => println!("Unable to get the path of this executable!")
336 /// };
337 /// ```
338 #[deprecated(since = "1.0.0", reason = "renamed to env::current_exe")]
339 #[unstable(feature = "os")]
340 pub fn self_exe_name() -> Option<Path> {
341     env::current_exe().ok()
342 }
343
344 /// Optionally returns the filesystem path to the current executable which is
345 /// running.
346 ///
347 /// Like self_exe_name() but without the binary's name.
348 ///
349 /// # Example
350 ///
351 /// ```rust
352 /// use std::os;
353 ///
354 /// match os::self_exe_path() {
355 ///     Some(exe_path) => println!("Executable's Path is: {}", exe_path.display()),
356 ///     None => println!("Impossible to fetch the path of this executable.")
357 /// };
358 /// ```
359 #[deprecated(since = "1.0.0", reason = "use env::current_exe + dir_path/pop")]
360 #[unstable(feature = "os")]
361 pub fn self_exe_path() -> Option<Path> {
362     env::current_exe().ok().map(|mut p| { p.pop(); p })
363 }
364
365 /// Optionally returns the path to the current user's home directory if known.
366 ///
367 /// # Unix
368 ///
369 /// Returns the value of the 'HOME' environment variable if it is set
370 /// and not equal to the empty string.
371 ///
372 /// # Windows
373 ///
374 /// Returns the value of the 'HOME' environment variable if it is
375 /// set and not equal to the empty string. Otherwise, returns the value of the
376 /// 'USERPROFILE' environment variable if it is set and not equal to the empty
377 /// string.
378 ///
379 /// # Example
380 ///
381 /// ```rust
382 /// use std::os;
383 ///
384 /// match os::homedir() {
385 ///     Some(ref p) => println!("{}", p.display()),
386 ///     None => println!("Impossible to get your home dir!")
387 /// }
388 /// ```
389 #[deprecated(since = "1.0.0", reason = "renamed to env::home_dir")]
390 #[allow(deprecated)]
391 #[unstable(feature = "os")]
392 pub fn homedir() -> Option<Path> {
393     #[inline]
394     #[cfg(unix)]
395     fn _homedir() -> Option<Path> {
396         aux_homedir("HOME")
397     }
398
399     #[inline]
400     #[cfg(windows)]
401     fn _homedir() -> Option<Path> {
402         aux_homedir("HOME").or(aux_homedir("USERPROFILE"))
403     }
404
405     #[inline]
406     fn aux_homedir(home_name: &str) -> Option<Path> {
407         match getenv_as_bytes(home_name) {
408             Some(p)  => {
409                 if p.is_empty() { None } else { Path::new_opt(p) }
410             },
411             _ => None
412         }
413     }
414     _homedir()
415 }
416
417 /// Returns the path to a temporary directory.
418 ///
419 /// On Unix, returns the value of the 'TMPDIR' environment variable if it is
420 /// set, otherwise for non-Android it returns '/tmp'. If Android, since there
421 /// is no global temporary folder (it is usually allocated per-app), we return
422 /// '/data/local/tmp'.
423 ///
424 /// On Windows, returns the value of, in order, the 'TMP', 'TEMP',
425 /// 'USERPROFILE' environment variable  if any are set and not the empty
426 /// string. Otherwise, tmpdir returns the path to the Windows directory.
427 #[deprecated(since = "1.0.0", reason = "renamed to env::temp_dir")]
428 #[allow(deprecated)]
429 #[unstable(feature = "os")]
430 pub fn tmpdir() -> Path {
431     return lookup();
432
433     fn getenv_nonempty(v: &str) -> Option<Path> {
434         match getenv(v) {
435             Some(x) =>
436                 if x.is_empty() {
437                     None
438                 } else {
439                     Path::new_opt(x)
440                 },
441             _ => None
442         }
443     }
444
445     #[cfg(unix)]
446     fn lookup() -> Path {
447         let default = if cfg!(target_os = "android") {
448             Path::new("/data/local/tmp")
449         } else {
450             Path::new("/tmp")
451         };
452
453         getenv_nonempty("TMPDIR").unwrap_or(default)
454     }
455
456     #[cfg(windows)]
457     fn lookup() -> Path {
458         getenv_nonempty("TMP").or(
459             getenv_nonempty("TEMP").or(
460                 getenv_nonempty("USERPROFILE").or(
461                    getenv_nonempty("WINDIR")))).unwrap_or(Path::new("C:\\Windows"))
462     }
463 }
464
465 /// Convert a relative path to an absolute path
466 ///
467 /// If the given path is relative, return it prepended with the current working
468 /// directory. If the given path is already an absolute path, return it
469 /// as is.
470 ///
471 /// # Example
472 /// ```rust
473 /// use std::os;
474 /// use std::old_path::Path;
475 ///
476 /// // Assume we're in a path like /home/someuser
477 /// let rel_path = Path::new("..");
478 /// let abs_path = os::make_absolute(&rel_path).unwrap();
479 /// println!("The absolute path is {}", abs_path.display());
480 /// // Prints "The absolute path is /home"
481 /// ```
482 // NB: this is here rather than in path because it is a form of environment
483 // querying; what it does depends on the process working directory, not just
484 // the input paths.
485 #[deprecated(since = "1.0.0", reason = "use env::current_dir + .join directly")]
486 #[unstable(feature = "os")]
487 pub fn make_absolute(p: &Path) -> IoResult<Path> {
488     if p.is_absolute() {
489         Ok(p.clone())
490     } else {
491         env::current_dir().map(|mut cwd| {
492             cwd.push(p);
493             cwd
494         })
495     }
496 }
497
498 /// Changes the current working directory to the specified path, returning
499 /// whether the change was completed successfully or not.
500 ///
501 /// # Example
502 /// ```rust
503 /// use std::os;
504 /// use std::old_path::Path;
505 ///
506 /// let root = Path::new("/");
507 /// assert!(os::change_dir(&root).is_ok());
508 /// println!("Successfully changed working directory to {}!", root.display());
509 /// ```
510 #[deprecated(since = "1.0.0", reason = "renamed to env::set_current_dir")]
511 #[unstable(feature = "os")]
512 pub fn change_dir(p: &Path) -> IoResult<()> {
513     return sys::os::chdir(p);
514 }
515
516 /// Returns the platform-specific value of errno
517 pub fn errno() -> i32 {
518     sys::os::errno() as i32
519 }
520
521 /// Return the string corresponding to an `errno()` value of `errnum`.
522 ///
523 /// # Example
524 /// ```rust
525 /// use std::os;
526 ///
527 /// // Same as println!("{}", last_os_error());
528 /// println!("{}", os::error_string(os::errno() as i32));
529 /// ```
530 pub fn error_string(errnum: i32) -> String {
531     return sys::os::error_string(errnum);
532 }
533
534 /// Get a string representing the platform-dependent last error
535 pub fn last_os_error() -> String {
536     error_string(errno())
537 }
538
539 /// Sets the process exit code
540 ///
541 /// Sets the exit code returned by the process if all supervised tasks
542 /// terminate successfully (without panicking). If the current root task panics
543 /// and is supervised by the scheduler then any user-specified exit status is
544 /// ignored and the process exits with the default panic status.
545 ///
546 /// Note that this is not synchronized against modifications of other threads.
547 #[deprecated(since = "1.0.0", reason = "renamed to env::set_exit_status")]
548 #[unstable(feature = "os")]
549 pub fn set_exit_status(code: int) {
550     env::set_exit_status(code as i32)
551 }
552
553 /// Fetches the process's current exit code. This defaults to 0 and can change
554 /// by calling `set_exit_status`.
555 #[deprecated(since = "1.0.0", reason = "renamed to env::get_exit_status")]
556 #[unstable(feature = "os")]
557 pub fn get_exit_status() -> int {
558     env::get_exit_status() as isize
559 }
560
561 #[cfg(target_os = "macos")]
562 unsafe fn load_argc_and_argv(argc: int,
563                              argv: *const *const c_char) -> Vec<Vec<u8>> {
564     use iter::range;
565
566     (0..argc as uint).map(|i| {
567         ffi::c_str_to_bytes(&*argv.offset(i as int)).to_vec()
568     }).collect()
569 }
570
571 /// Returns the command line arguments
572 ///
573 /// Returns a list of the command line arguments.
574 #[cfg(target_os = "macos")]
575 fn real_args_as_bytes() -> Vec<Vec<u8>> {
576     unsafe {
577         let (argc, argv) = (*_NSGetArgc() as int,
578                             *_NSGetArgv() as *const *const c_char);
579         load_argc_and_argv(argc, argv)
580     }
581 }
582
583 // As _NSGetArgc and _NSGetArgv aren't mentioned in iOS docs
584 // and use underscores in their names - they're most probably
585 // are considered private and therefore should be avoided
586 // Here is another way to get arguments using Objective C
587 // runtime
588 //
589 // In general it looks like:
590 // res = Vec::new()
591 // let args = [[NSProcessInfo processInfo] arguments]
592 // for i in 0..[args count]
593 //      res.push([args objectAtIndex:i])
594 // res
595 #[cfg(target_os = "ios")]
596 fn real_args_as_bytes() -> Vec<Vec<u8>> {
597     use ffi::c_str_to_bytes;
598     use iter::range;
599     use mem;
600
601     #[link(name = "objc")]
602     extern {
603         fn sel_registerName(name: *const libc::c_uchar) -> Sel;
604         fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId;
605         fn objc_getClass(class_name: *const libc::c_uchar) -> NsId;
606     }
607
608     #[link(name = "Foundation", kind = "framework")]
609     extern {}
610
611     type Sel = *const libc::c_void;
612     type NsId = *const libc::c_void;
613
614     let mut res = Vec::new();
615
616     unsafe {
617         let processInfoSel = sel_registerName("processInfo\0".as_ptr());
618         let argumentsSel = sel_registerName("arguments\0".as_ptr());
619         let utf8Sel = sel_registerName("UTF8String\0".as_ptr());
620         let countSel = sel_registerName("count\0".as_ptr());
621         let objectAtSel = sel_registerName("objectAtIndex:\0".as_ptr());
622
623         let klass = objc_getClass("NSProcessInfo\0".as_ptr());
624         let info = objc_msgSend(klass, processInfoSel);
625         let args = objc_msgSend(info, argumentsSel);
626
627         let cnt: int = mem::transmute(objc_msgSend(args, countSel));
628         for i in 0..cnt {
629             let tmp = objc_msgSend(args, objectAtSel, i);
630             let utf_c_str: *const libc::c_char =
631                 mem::transmute(objc_msgSend(tmp, utf8Sel));
632             res.push(c_str_to_bytes(&utf_c_str).to_vec());
633         }
634     }
635
636     res
637 }
638
639 #[cfg(any(target_os = "linux",
640           target_os = "android",
641           target_os = "freebsd",
642           target_os = "dragonfly",
643           target_os = "openbsd"))]
644 fn real_args_as_bytes() -> Vec<Vec<u8>> {
645     use rt;
646     rt::args::clone().unwrap_or_else(|| vec![])
647 }
648
649 #[cfg(not(windows))]
650 fn real_args() -> Vec<String> {
651     real_args_as_bytes().into_iter()
652                         .map(|v| {
653                             String::from_utf8_lossy(&v).into_owned()
654                         }).collect()
655 }
656
657 #[cfg(windows)]
658 fn real_args() -> Vec<String> {
659     use slice;
660     use iter::range;
661
662     let mut nArgs: c_int = 0;
663     let lpArgCount: *mut c_int = &mut nArgs;
664     let lpCmdLine = unsafe { GetCommandLineW() };
665     let szArgList = unsafe { CommandLineToArgvW(lpCmdLine, lpArgCount) };
666
667     let args: Vec<_> = (0..nArgs as uint).map(|i| unsafe {
668         // Determine the length of this argument.
669         let ptr = *szArgList.offset(i as int);
670         let mut len = 0;
671         while *ptr.offset(len as int) != 0 { len += 1; }
672
673         // Push it onto the list.
674         let ptr = ptr as *const u16;
675         let buf = slice::from_raw_parts(ptr, len);
676         let opt_s = String::from_utf16(sys::truncate_utf16_at_nul(buf));
677         opt_s.ok().expect("CommandLineToArgvW returned invalid UTF-16")
678     }).collect();
679
680     unsafe {
681         LocalFree(szArgList as *mut c_void);
682     }
683
684     return args
685 }
686
687 #[cfg(windows)]
688 fn real_args_as_bytes() -> Vec<Vec<u8>> {
689     real_args().into_iter().map(|s| s.into_bytes()).collect()
690 }
691
692 type LPCWSTR = *const u16;
693
694 #[cfg(windows)]
695 #[link_name="kernel32"]
696 extern "system" {
697     fn GetCommandLineW() -> LPCWSTR;
698     fn LocalFree(ptr: *mut c_void);
699 }
700
701 #[cfg(windows)]
702 #[link_name="shell32"]
703 extern "system" {
704     fn CommandLineToArgvW(lpCmdLine: LPCWSTR,
705                           pNumArgs: *mut c_int) -> *mut *mut u16;
706 }
707
708 /// Returns the arguments which this program was started with (normally passed
709 /// via the command line).
710 ///
711 /// The first element is traditionally the path to the executable, but it can be
712 /// set to arbitrary text, and it may not even exist, so this property should not
713 /// be relied upon for security purposes.
714 ///
715 /// The arguments are interpreted as utf-8, with invalid bytes replaced with \uFFFD.
716 /// See `String::from_utf8_lossy` for details.
717 /// # Example
718 ///
719 /// ```rust
720 /// use std::os;
721 ///
722 /// // Prints each argument on a separate line
723 /// for argument in os::args().iter() {
724 ///     println!("{}", argument);
725 /// }
726 /// ```
727 #[deprecated(since = "1.0.0", reason = "use std::env::args() instead")]
728 #[unstable(feature = "os")]
729 pub fn args() -> Vec<String> {
730     real_args()
731 }
732
733 /// Returns the arguments which this program was started with (normally passed
734 /// via the command line) as byte vectors.
735 #[deprecated(since = "1.0.0", reason = "use env::args_os instead")]
736 #[unstable(feature = "os")]
737 pub fn args_as_bytes() -> Vec<Vec<u8>> {
738     real_args_as_bytes()
739 }
740
741 #[cfg(target_os = "macos")]
742 extern {
743     // These functions are in crt_externs.h.
744     fn _NSGetArgc() -> *mut c_int;
745     fn _NSGetArgv() -> *mut *mut *mut c_char;
746 }
747
748 /// Returns the page size of the current architecture in bytes.
749 #[deprecated(since = "1.0.0", reason = "renamed to env::page_size")]
750 #[unstable(feature = "os")]
751 pub fn page_size() -> uint {
752     sys::os::page_size()
753 }
754
755 /// A memory mapped file or chunk of memory. This is a very system-specific
756 /// interface to the OS's memory mapping facilities (`mmap` on POSIX,
757 /// `VirtualAlloc`/`CreateFileMapping` on Windows). It makes no attempt at
758 /// abstracting platform differences, besides in error values returned. Consider
759 /// yourself warned.
760 ///
761 /// The memory map is released (unmapped) when the destructor is run, so don't
762 /// let it leave scope by accident if you want it to stick around.
763 pub struct MemoryMap {
764     data: *mut u8,
765     len: uint,
766     kind: MemoryMapKind,
767 }
768
769 /// Type of memory map
770 #[allow(raw_pointer_derive)]
771 #[derive(Copy)]
772 pub enum MemoryMapKind {
773     /// Virtual memory map. Usually used to change the permissions of a given
774     /// chunk of memory.  Corresponds to `VirtualAlloc` on Windows.
775     MapFile(*const u8),
776     /// Virtual memory map. Usually used to change the permissions of a given
777     /// chunk of memory, or for allocation. Corresponds to `VirtualAlloc` on
778     /// Windows.
779     MapVirtual
780 }
781
782 /// Options the memory map is created with
783 #[allow(raw_pointer_derive)]
784 #[derive(Copy)]
785 pub enum MapOption {
786     /// The memory should be readable
787     MapReadable,
788     /// The memory should be writable
789     MapWritable,
790     /// The memory should be executable
791     MapExecutable,
792     /// Create a map for a specific address range. Corresponds to `MAP_FIXED` on
793     /// POSIX.
794     MapAddr(*const u8),
795     /// Create a memory mapping for a file with a given HANDLE.
796     #[cfg(windows)]
797     MapFd(libc::HANDLE),
798     /// Create a memory mapping for a file with a given fd.
799     #[cfg(not(windows))]
800     MapFd(c_int),
801     /// When using `MapFd`, the start of the map is `uint` bytes from the start
802     /// of the file.
803     MapOffset(uint),
804     /// On POSIX, this can be used to specify the default flags passed to
805     /// `mmap`. By default it uses `MAP_PRIVATE` and, if not using `MapFd`,
806     /// `MAP_ANON`. This will override both of those. This is platform-specific
807     /// (the exact values used) and ignored on Windows.
808     MapNonStandardFlags(c_int),
809 }
810
811 /// Possible errors when creating a map.
812 #[derive(Copy, Debug)]
813 pub enum MapError {
814     /// # The following are POSIX-specific
815     ///
816     /// fd was not open for reading or, if using `MapWritable`, was not open for
817     /// writing.
818     ErrFdNotAvail,
819     /// fd was not valid
820     ErrInvalidFd,
821     /// Either the address given by `MapAddr` or offset given by `MapOffset` was
822     /// not a multiple of `MemoryMap::granularity` (unaligned to page size).
823     ErrUnaligned,
824     /// With `MapFd`, the fd does not support mapping.
825     ErrNoMapSupport,
826     /// If using `MapAddr`, the address + `min_len` was outside of the process's
827     /// address space. If using `MapFd`, the target of the fd didn't have enough
828     /// resources to fulfill the request.
829     ErrNoMem,
830     /// A zero-length map was requested. This is invalid according to
831     /// [POSIX](http://pubs.opengroup.org/onlinepubs/9699919799/functions/mmap.html).
832     /// Not all platforms obey this, but this wrapper does.
833     ErrZeroLength,
834     /// Unrecognized error. The inner value is the unrecognized errno.
835     ErrUnknown(int),
836     /// # The following are Windows-specific
837     ///
838     /// Unsupported combination of protection flags
839     /// (`MapReadable`/`MapWritable`/`MapExecutable`).
840     ErrUnsupProt,
841     /// When using `MapFd`, `MapOffset` was given (Windows does not support this
842     /// at all)
843     ErrUnsupOffset,
844     /// When using `MapFd`, there was already a mapping to the file.
845     ErrAlreadyExists,
846     /// Unrecognized error from `VirtualAlloc`. The inner value is the return
847     /// value of GetLastError.
848     ErrVirtualAlloc(i32),
849     /// Unrecognized error from `CreateFileMapping`. The inner value is the
850     /// return value of `GetLastError`.
851     ErrCreateFileMappingW(i32),
852     /// Unrecognized error from `MapViewOfFile`. The inner value is the return
853     /// value of `GetLastError`.
854     ErrMapViewOfFile(i32)
855 }
856
857 #[stable(feature = "rust1", since = "1.0.0")]
858 impl fmt::Display for MapError {
859     fn fmt(&self, out: &mut fmt::Formatter) -> fmt::Result {
860         let str = match *self {
861             ErrFdNotAvail => "fd not available for reading or writing",
862             ErrInvalidFd => "Invalid fd",
863             ErrUnaligned => {
864                 "Unaligned address, invalid flags, negative length or \
865                  unaligned offset"
866             }
867             ErrNoMapSupport=> "File doesn't support mapping",
868             ErrNoMem => "Invalid address, or not enough available memory",
869             ErrUnsupProt => "Protection mode unsupported",
870             ErrUnsupOffset => "Offset in virtual memory mode is unsupported",
871             ErrAlreadyExists => "File mapping for specified file already exists",
872             ErrZeroLength => "Zero-length mapping not allowed",
873             ErrUnknown(code) => {
874                 return write!(out, "Unknown error = {}", code)
875             },
876             ErrVirtualAlloc(code) => {
877                 return write!(out, "VirtualAlloc failure = {}", code)
878             },
879             ErrCreateFileMappingW(code) => {
880                 return write!(out, "CreateFileMappingW failure = {}", code)
881             },
882             ErrMapViewOfFile(code) => {
883                 return write!(out, "MapViewOfFile failure = {}", code)
884             }
885         };
886         write!(out, "{}", str)
887     }
888 }
889
890 impl Error for MapError {
891     fn description(&self) -> &str { "memory map error" }
892 }
893
894 // Round up `from` to be divisible by `to`
895 fn round_up(from: uint, to: uint) -> uint {
896     let r = if from % to == 0 {
897         from
898     } else {
899         from + to - (from % to)
900     };
901     if r == 0 {
902         to
903     } else {
904         r
905     }
906 }
907
908 #[cfg(unix)]
909 impl MemoryMap {
910     /// Create a new mapping with the given `options`, at least `min_len` bytes
911     /// long. `min_len` must be greater than zero; see the note on
912     /// `ErrZeroLength`.
913     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
914         use libc::off_t;
915
916         if min_len == 0 {
917             return Err(ErrZeroLength)
918         }
919         let mut addr: *const u8 = ptr::null();
920         let mut prot = 0;
921         let mut flags = libc::MAP_PRIVATE;
922         let mut fd = -1;
923         let mut offset = 0;
924         let mut custom_flags = false;
925         let len = round_up(min_len, env::page_size());
926
927         for &o in options {
928             match o {
929                 MapReadable => { prot |= libc::PROT_READ; },
930                 MapWritable => { prot |= libc::PROT_WRITE; },
931                 MapExecutable => { prot |= libc::PROT_EXEC; },
932                 MapAddr(addr_) => {
933                     flags |= libc::MAP_FIXED;
934                     addr = addr_;
935                 },
936                 MapFd(fd_) => {
937                     flags |= libc::MAP_FILE;
938                     fd = fd_;
939                 },
940                 MapOffset(offset_) => { offset = offset_ as off_t; },
941                 MapNonStandardFlags(f) => { custom_flags = true; flags = f },
942             }
943         }
944         if fd == -1 && !custom_flags { flags |= libc::MAP_ANON; }
945
946         let r = unsafe {
947             libc::mmap(addr as *mut c_void, len as libc::size_t, prot, flags,
948                        fd, offset)
949         };
950         if r == libc::MAP_FAILED {
951             Err(match errno() as c_int {
952                 libc::EACCES => ErrFdNotAvail,
953                 libc::EBADF => ErrInvalidFd,
954                 libc::EINVAL => ErrUnaligned,
955                 libc::ENODEV => ErrNoMapSupport,
956                 libc::ENOMEM => ErrNoMem,
957                 code => ErrUnknown(code as int)
958             })
959         } else {
960             Ok(MemoryMap {
961                data: r as *mut u8,
962                len: len,
963                kind: if fd == -1 {
964                    MapVirtual
965                } else {
966                    MapFile(ptr::null())
967                }
968             })
969         }
970     }
971
972     /// Granularity that the offset or address must be for `MapOffset` and
973     /// `MapAddr` respectively.
974     pub fn granularity() -> uint {
975         env::page_size()
976     }
977 }
978
979 #[cfg(unix)]
980 impl Drop for MemoryMap {
981     /// Unmap the mapping. Panics the task if `munmap` panics.
982     fn drop(&mut self) {
983         if self.len == 0 { /* workaround for dummy_stack */ return; }
984
985         unsafe {
986             // `munmap` only panics due to logic errors
987             libc::munmap(self.data as *mut c_void, self.len as libc::size_t);
988         }
989     }
990 }
991
992 #[cfg(windows)]
993 impl MemoryMap {
994     /// Create a new mapping with the given `options`, at least `min_len` bytes long.
995     pub fn new(min_len: uint, options: &[MapOption]) -> Result<MemoryMap, MapError> {
996         use libc::types::os::arch::extra::{LPVOID, DWORD, SIZE_T, HANDLE};
997
998         let mut lpAddress: LPVOID = ptr::null_mut();
999         let mut readable = false;
1000         let mut writable = false;
1001         let mut executable = false;
1002         let mut handle: HANDLE = libc::INVALID_HANDLE_VALUE;
1003         let mut offset: uint = 0;
1004         let len = round_up(min_len, env::page_size());
1005
1006         for &o in options {
1007             match o {
1008                 MapReadable => { readable = true; },
1009                 MapWritable => { writable = true; },
1010                 MapExecutable => { executable = true; }
1011                 MapAddr(addr_) => { lpAddress = addr_ as LPVOID; },
1012                 MapFd(handle_) => { handle = handle_; },
1013                 MapOffset(offset_) => { offset = offset_; },
1014                 MapNonStandardFlags(..) => {}
1015             }
1016         }
1017
1018         let flProtect = match (executable, readable, writable) {
1019             (false, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_NOACCESS,
1020             (false, true, false) => libc::PAGE_READONLY,
1021             (false, true, true) => libc::PAGE_READWRITE,
1022             (true, false, false) if handle == libc::INVALID_HANDLE_VALUE => libc::PAGE_EXECUTE,
1023             (true, true, false) => libc::PAGE_EXECUTE_READ,
1024             (true, true, true) => libc::PAGE_EXECUTE_READWRITE,
1025             _ => return Err(ErrUnsupProt)
1026         };
1027
1028         if handle == libc::INVALID_HANDLE_VALUE {
1029             if offset != 0 {
1030                 return Err(ErrUnsupOffset);
1031             }
1032             let r = unsafe {
1033                 libc::VirtualAlloc(lpAddress,
1034                                    len as SIZE_T,
1035                                    libc::MEM_COMMIT | libc::MEM_RESERVE,
1036                                    flProtect)
1037             };
1038             match r as uint {
1039                 0 => Err(ErrVirtualAlloc(errno())),
1040                 _ => Ok(MemoryMap {
1041                    data: r as *mut u8,
1042                    len: len,
1043                    kind: MapVirtual
1044                 })
1045             }
1046         } else {
1047             let dwDesiredAccess = match (executable, readable, writable) {
1048                 (false, true, false) => libc::FILE_MAP_READ,
1049                 (false, true, true) => libc::FILE_MAP_WRITE,
1050                 (true, true, false) => libc::FILE_MAP_READ | libc::FILE_MAP_EXECUTE,
1051                 (true, true, true) => libc::FILE_MAP_WRITE | libc::FILE_MAP_EXECUTE,
1052                 _ => return Err(ErrUnsupProt) // Actually, because of the check above,
1053                                               // we should never get here.
1054             };
1055             unsafe {
1056                 let hFile = handle;
1057                 let mapping = libc::CreateFileMappingW(hFile,
1058                                                        ptr::null_mut(),
1059                                                        flProtect,
1060                                                        0,
1061                                                        0,
1062                                                        ptr::null());
1063                 if mapping == ptr::null_mut() {
1064                     return Err(ErrCreateFileMappingW(errno()));
1065                 }
1066                 if errno() as c_int == libc::ERROR_ALREADY_EXISTS {
1067                     return Err(ErrAlreadyExists);
1068                 }
1069                 let r = libc::MapViewOfFile(mapping,
1070                                             dwDesiredAccess,
1071                                             ((len as u64) >> 32) as DWORD,
1072                                             (offset & 0xffff_ffff) as DWORD,
1073                                             0);
1074                 match r as uint {
1075                     0 => Err(ErrMapViewOfFile(errno())),
1076                     _ => Ok(MemoryMap {
1077                        data: r as *mut u8,
1078                        len: len,
1079                        kind: MapFile(mapping as *const u8)
1080                     })
1081                 }
1082             }
1083         }
1084     }
1085
1086     /// Granularity of MapAddr() and MapOffset() parameter values.
1087     /// This may be greater than the value returned by page_size().
1088     pub fn granularity() -> uint {
1089         use mem;
1090         unsafe {
1091             let mut info = mem::zeroed();
1092             libc::GetSystemInfo(&mut info);
1093
1094             return info.dwAllocationGranularity as uint;
1095         }
1096     }
1097 }
1098
1099 #[cfg(windows)]
1100 impl Drop for MemoryMap {
1101     /// Unmap the mapping. Panics the task if any of `VirtualFree`,
1102     /// `UnmapViewOfFile`, or `CloseHandle` fail.
1103     fn drop(&mut self) {
1104         use libc::types::os::arch::extra::{LPCVOID, HANDLE};
1105         use libc::consts::os::extra::FALSE;
1106         if self.len == 0 { return }
1107
1108         unsafe {
1109             match self.kind {
1110                 MapVirtual => {
1111                     if libc::VirtualFree(self.data as *mut c_void, 0,
1112                                          libc::MEM_RELEASE) == 0 {
1113                         println!("VirtualFree failed: {}", errno());
1114                     }
1115                 },
1116                 MapFile(mapping) => {
1117                     if libc::UnmapViewOfFile(self.data as LPCVOID) == FALSE {
1118                         println!("UnmapViewOfFile failed: {}", errno());
1119                     }
1120                     if libc::CloseHandle(mapping as HANDLE) == FALSE {
1121                         println!("CloseHandle failed: {}", errno());
1122                     }
1123                 }
1124             }
1125         }
1126     }
1127 }
1128
1129 impl MemoryMap {
1130     /// Returns the pointer to the memory created or modified by this map.
1131     pub fn data(&self) -> *mut u8 { self.data }
1132     /// Returns the number of bytes this map applies to.
1133     pub fn len(&self) -> uint { self.len }
1134     /// Returns the type of mapping this represents.
1135     pub fn kind(&self) -> MemoryMapKind { self.kind }
1136 }
1137
1138 #[cfg(target_os = "linux")]
1139 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1140 #[unstable(feature = "os")]
1141 pub mod consts {
1142     pub use os::arch_consts::ARCH;
1143
1144     pub const FAMILY: &'static str = "unix";
1145
1146     /// A string describing the specific operating system in use: in this
1147     /// case, `linux`.
1148     pub const SYSNAME: &'static str = "linux";
1149
1150     /// Specifies the filename prefix used for shared libraries on this
1151     /// platform: in this case, `lib`.
1152     pub const DLL_PREFIX: &'static str = "lib";
1153
1154     /// Specifies the filename suffix used for shared libraries on this
1155     /// platform: in this case, `.so`.
1156     pub const DLL_SUFFIX: &'static str = ".so";
1157
1158     /// Specifies the file extension used for shared libraries on this
1159     /// platform that goes after the dot: in this case, `so`.
1160     pub const DLL_EXTENSION: &'static str = "so";
1161
1162     /// Specifies the filename suffix used for executable binaries on this
1163     /// platform: in this case, the empty string.
1164     pub const EXE_SUFFIX: &'static str = "";
1165
1166     /// Specifies the file extension, if any, used for executable binaries
1167     /// on this platform: in this case, the empty string.
1168     pub const EXE_EXTENSION: &'static str = "";
1169 }
1170
1171 #[cfg(target_os = "macos")]
1172 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1173 #[unstable(feature = "os")]
1174 pub mod consts {
1175     pub use os::arch_consts::ARCH;
1176
1177     pub const FAMILY: &'static str = "unix";
1178
1179     /// A string describing the specific operating system in use: in this
1180     /// case, `macos`.
1181     pub const SYSNAME: &'static str = "macos";
1182
1183     /// Specifies the filename prefix used for shared libraries on this
1184     /// platform: in this case, `lib`.
1185     pub const DLL_PREFIX: &'static str = "lib";
1186
1187     /// Specifies the filename suffix used for shared libraries on this
1188     /// platform: in this case, `.dylib`.
1189     pub const DLL_SUFFIX: &'static str = ".dylib";
1190
1191     /// Specifies the file extension used for shared libraries on this
1192     /// platform that goes after the dot: in this case, `dylib`.
1193     pub const DLL_EXTENSION: &'static str = "dylib";
1194
1195     /// Specifies the filename suffix used for executable binaries on this
1196     /// platform: in this case, the empty string.
1197     pub const EXE_SUFFIX: &'static str = "";
1198
1199     /// Specifies the file extension, if any, used for executable binaries
1200     /// on this platform: in this case, the empty string.
1201     pub const EXE_EXTENSION: &'static str = "";
1202 }
1203
1204 #[cfg(target_os = "ios")]
1205 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1206 #[unstable(feature = "os")]
1207 pub mod consts {
1208     pub use os::arch_consts::ARCH;
1209
1210     pub const FAMILY: &'static str = "unix";
1211
1212     /// A string describing the specific operating system in use: in this
1213     /// case, `ios`.
1214     pub const SYSNAME: &'static str = "ios";
1215
1216     /// Specifies the filename suffix used for executable binaries on this
1217     /// platform: in this case, the empty string.
1218     pub const EXE_SUFFIX: &'static str = "";
1219
1220     /// Specifies the file extension, if any, used for executable binaries
1221     /// on this platform: in this case, the empty string.
1222     pub const EXE_EXTENSION: &'static str = "";
1223 }
1224
1225 #[cfg(target_os = "freebsd")]
1226 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1227 #[unstable(feature = "os")]
1228 pub mod consts {
1229     pub use os::arch_consts::ARCH;
1230
1231     pub const FAMILY: &'static str = "unix";
1232
1233     /// A string describing the specific operating system in use: in this
1234     /// case, `freebsd`.
1235     pub const SYSNAME: &'static str = "freebsd";
1236
1237     /// Specifies the filename prefix used for shared libraries on this
1238     /// platform: in this case, `lib`.
1239     pub const DLL_PREFIX: &'static str = "lib";
1240
1241     /// Specifies the filename suffix used for shared libraries on this
1242     /// platform: in this case, `.so`.
1243     pub const DLL_SUFFIX: &'static str = ".so";
1244
1245     /// Specifies the file extension used for shared libraries on this
1246     /// platform that goes after the dot: in this case, `so`.
1247     pub const DLL_EXTENSION: &'static str = "so";
1248
1249     /// Specifies the filename suffix used for executable binaries on this
1250     /// platform: in this case, the empty string.
1251     pub const EXE_SUFFIX: &'static str = "";
1252
1253     /// Specifies the file extension, if any, used for executable binaries
1254     /// on this platform: in this case, the empty string.
1255     pub const EXE_EXTENSION: &'static str = "";
1256 }
1257
1258 #[cfg(target_os = "dragonfly")]
1259 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1260 #[unstable(feature = "os")]
1261 pub mod consts {
1262     pub use os::arch_consts::ARCH;
1263
1264     pub const FAMILY: &'static str = "unix";
1265
1266     /// A string describing the specific operating system in use: in this
1267     /// case, `dragonfly`.
1268     pub const SYSNAME: &'static str = "dragonfly";
1269
1270     /// Specifies the filename prefix used for shared libraries on this
1271     /// platform: in this case, `lib`.
1272     pub const DLL_PREFIX: &'static str = "lib";
1273
1274     /// Specifies the filename suffix used for shared libraries on this
1275     /// platform: in this case, `.so`.
1276     pub const DLL_SUFFIX: &'static str = ".so";
1277
1278     /// Specifies the file extension used for shared libraries on this
1279     /// platform that goes after the dot: in this case, `so`.
1280     pub const DLL_EXTENSION: &'static str = "so";
1281
1282     /// Specifies the filename suffix used for executable binaries on this
1283     /// platform: in this case, the empty string.
1284     pub const EXE_SUFFIX: &'static str = "";
1285
1286     /// Specifies the file extension, if any, used for executable binaries
1287     /// on this platform: in this case, the empty string.
1288     pub const EXE_EXTENSION: &'static str = "";
1289 }
1290
1291 #[cfg(target_os = "openbsd")]
1292 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1293 #[unstable(feature = "os")]
1294 pub mod consts {
1295     pub use os::arch_consts::ARCH;
1296
1297     pub const FAMILY: &'static str = "unix";
1298
1299     /// A string describing the specific operating system in use: in this
1300     /// case, `openbsd`.
1301     pub const SYSNAME: &'static str = "openbsd";
1302
1303     /// Specifies the filename prefix used for shared libraries on this
1304     /// platform: in this case, `lib`.
1305     pub const DLL_PREFIX: &'static str = "lib";
1306
1307     /// Specifies the filename suffix used for shared libraries on this
1308     /// platform: in this case, `.so`.
1309     pub const DLL_SUFFIX: &'static str = ".so";
1310
1311     /// Specifies the file extension used for shared libraries on this
1312     /// platform that goes after the dot: in this case, `so`.
1313     pub const DLL_EXTENSION: &'static str = "so";
1314
1315     /// Specifies the filename suffix used for executable binaries on this
1316     /// platform: in this case, the empty string.
1317     pub const EXE_SUFFIX: &'static str = "";
1318
1319     /// Specifies the file extension, if any, used for executable binaries
1320     /// on this platform: in this case, the empty string.
1321     pub const EXE_EXTENSION: &'static str = "";
1322 }
1323
1324 #[cfg(target_os = "android")]
1325 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1326 #[unstable(feature = "os")]
1327 pub mod consts {
1328     pub use os::arch_consts::ARCH;
1329
1330     pub const FAMILY: &'static str = "unix";
1331
1332     /// A string describing the specific operating system in use: in this
1333     /// case, `android`.
1334     pub const SYSNAME: &'static str = "android";
1335
1336     /// Specifies the filename prefix used for shared libraries on this
1337     /// platform: in this case, `lib`.
1338     pub const DLL_PREFIX: &'static str = "lib";
1339
1340     /// Specifies the filename suffix used for shared libraries on this
1341     /// platform: in this case, `.so`.
1342     pub const DLL_SUFFIX: &'static str = ".so";
1343
1344     /// Specifies the file extension used for shared libraries on this
1345     /// platform that goes after the dot: in this case, `so`.
1346     pub const DLL_EXTENSION: &'static str = "so";
1347
1348     /// Specifies the filename suffix used for executable binaries on this
1349     /// platform: in this case, the empty string.
1350     pub const EXE_SUFFIX: &'static str = "";
1351
1352     /// Specifies the file extension, if any, used for executable binaries
1353     /// on this platform: in this case, the empty string.
1354     pub const EXE_EXTENSION: &'static str = "";
1355 }
1356
1357 #[cfg(target_os = "windows")]
1358 #[deprecated(since = "1.0.0", reason = "renamed to env::consts")]
1359 #[unstable(feature = "os")]
1360 pub mod consts {
1361     pub use os::arch_consts::ARCH;
1362
1363     pub const FAMILY: &'static str = "windows";
1364
1365     /// A string describing the specific operating system in use: in this
1366     /// case, `windows`.
1367     pub const SYSNAME: &'static str = "windows";
1368
1369     /// Specifies the filename prefix used for shared libraries on this
1370     /// platform: in this case, the empty string.
1371     pub const DLL_PREFIX: &'static str = "";
1372
1373     /// Specifies the filename suffix used for shared libraries on this
1374     /// platform: in this case, `.dll`.
1375     pub const DLL_SUFFIX: &'static str = ".dll";
1376
1377     /// Specifies the file extension used for shared libraries on this
1378     /// platform that goes after the dot: in this case, `dll`.
1379     pub const DLL_EXTENSION: &'static str = "dll";
1380
1381     /// Specifies the filename suffix used for executable binaries on this
1382     /// platform: in this case, `.exe`.
1383     pub const EXE_SUFFIX: &'static str = ".exe";
1384
1385     /// Specifies the file extension, if any, used for executable binaries
1386     /// on this platform: in this case, `exe`.
1387     pub const EXE_EXTENSION: &'static str = "exe";
1388 }
1389
1390 #[cfg(target_arch = "x86")]
1391 mod arch_consts {
1392     pub const ARCH: &'static str = "x86";
1393 }
1394
1395 #[cfg(target_arch = "x86_64")]
1396 mod arch_consts {
1397     pub const ARCH: &'static str = "x86_64";
1398 }
1399
1400 #[cfg(target_arch = "arm")]
1401 mod arch_consts {
1402     pub const ARCH: &'static str = "arm";
1403 }
1404
1405 #[cfg(target_arch = "aarch64")]
1406 mod arch_consts {
1407     pub const ARCH: &'static str = "aarch64";
1408 }
1409
1410 #[cfg(target_arch = "mips")]
1411 mod arch_consts {
1412     pub const ARCH: &'static str = "mips";
1413 }
1414
1415 #[cfg(target_arch = "mipsel")]
1416 mod arch_consts {
1417     pub const ARCH: &'static str = "mipsel";
1418 }
1419
1420 #[cfg(target_arch = "powerpc")]
1421 mod arch_consts {
1422     pub const ARCH: &'static str = "powerpc";
1423 }
1424
1425 #[cfg(test)]
1426 mod tests {
1427     #![allow(deprecated)] // rand
1428
1429     use prelude::v1::*;
1430
1431     use iter::repeat;
1432     use os::{env, getcwd, getenv, make_absolute};
1433     use os::{split_paths, join_paths, setenv, unsetenv};
1434     use os;
1435     use rand::Rng;
1436     use rand;
1437
1438     #[test]
1439     pub fn last_os_error() {
1440         debug!("{}", os::last_os_error());
1441     }
1442
1443     fn make_rand_name() -> String {
1444         let mut rng = rand::thread_rng();
1445         let n = format!("TEST{}", rng.gen_ascii_chars().take(10)
1446                                      .collect::<String>());
1447         assert!(getenv(&n).is_none());
1448         n
1449     }
1450
1451     #[test]
1452     fn test_num_cpus() {
1453         assert!(os::num_cpus() > 0);
1454     }
1455
1456     #[test]
1457     fn test_setenv() {
1458         let n = make_rand_name();
1459         setenv(&n, "VALUE");
1460         assert_eq!(getenv(&n), Some("VALUE".to_string()));
1461     }
1462
1463     #[test]
1464     fn test_unsetenv() {
1465         let n = make_rand_name();
1466         setenv(&n, "VALUE");
1467         unsetenv(&n);
1468         assert_eq!(getenv(&n), None);
1469     }
1470
1471     #[test]
1472     #[ignore]
1473     fn test_setenv_overwrite() {
1474         let n = make_rand_name();
1475         setenv(&n, "1");
1476         setenv(&n, "2");
1477         assert_eq!(getenv(&n), Some("2".to_string()));
1478         setenv(&n, "");
1479         assert_eq!(getenv(&n), Some("".to_string()));
1480     }
1481
1482     // Windows GetEnvironmentVariable requires some extra work to make sure
1483     // the buffer the variable is copied into is the right size
1484     #[test]
1485     #[ignore]
1486     fn test_getenv_big() {
1487         let mut s = "".to_string();
1488         let mut i = 0;
1489         while i < 100 {
1490             s.push_str("aaaaaaaaaa");
1491             i += 1;
1492         }
1493         let n = make_rand_name();
1494         setenv(&n, &s);
1495         debug!("{}", s.clone());
1496         assert_eq!(getenv(&n), Some(s));
1497     }
1498
1499     #[test]
1500     fn test_self_exe_name() {
1501         let path = os::self_exe_name();
1502         assert!(path.is_some());
1503         let path = path.unwrap();
1504         debug!("{}", path.display());
1505
1506         // Hard to test this function
1507         assert!(path.is_absolute());
1508     }
1509
1510     #[test]
1511     fn test_self_exe_path() {
1512         let path = os::self_exe_path();
1513         assert!(path.is_some());
1514         let path = path.unwrap();
1515         debug!("{}", path.display());
1516
1517         // Hard to test this function
1518         assert!(path.is_absolute());
1519     }
1520
1521     #[test]
1522     #[ignore]
1523     fn test_env_getenv() {
1524         let e = env();
1525         assert!(e.len() > 0);
1526         for p in &e {
1527             let (n, v) = (*p).clone();
1528             debug!("{}", n);
1529             let v2 = getenv(&n);
1530             // MingW seems to set some funky environment variables like
1531             // "=C:=C:\MinGW\msys\1.0\bin" and "!::=::\" that are returned
1532             // from env() but not visible from getenv().
1533             assert!(v2.is_none() || v2 == Some(v));
1534         }
1535     }
1536
1537     #[test]
1538     fn test_env_set_get_huge() {
1539         let n = make_rand_name();
1540         let s = repeat("x").take(10000).collect::<String>();
1541         setenv(&n, &s);
1542         assert_eq!(getenv(&n), Some(s));
1543         unsetenv(&n);
1544         assert_eq!(getenv(&n), None);
1545     }
1546
1547     #[test]
1548     fn test_env_setenv() {
1549         let n = make_rand_name();
1550
1551         let mut e = env();
1552         setenv(&n, "VALUE");
1553         assert!(!e.contains(&(n.clone(), "VALUE".to_string())));
1554
1555         e = env();
1556         assert!(e.contains(&(n, "VALUE".to_string())));
1557     }
1558
1559     #[test]
1560     fn test() {
1561         assert!((!Path::new("test-path").is_absolute()));
1562
1563         let cwd = getcwd().unwrap();
1564         debug!("Current working directory: {}", cwd.display());
1565
1566         debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display());
1567         debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display());
1568     }
1569
1570     #[test]
1571     #[cfg(unix)]
1572     fn homedir() {
1573         let oldhome = getenv("HOME");
1574
1575         setenv("HOME", "/home/MountainView");
1576         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1577
1578         setenv("HOME", "");
1579         assert!(os::homedir().is_none());
1580
1581         if let Some(s) = oldhome {
1582             setenv("HOME", s);
1583         }
1584     }
1585
1586     #[test]
1587     #[cfg(windows)]
1588     fn homedir() {
1589
1590         let oldhome = getenv("HOME");
1591         let olduserprofile = getenv("USERPROFILE");
1592
1593         setenv("HOME", "");
1594         setenv("USERPROFILE", "");
1595
1596         assert!(os::homedir().is_none());
1597
1598         setenv("HOME", "/home/MountainView");
1599         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1600
1601         setenv("HOME", "");
1602
1603         setenv("USERPROFILE", "/home/MountainView");
1604         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1605
1606         setenv("HOME", "/home/MountainView");
1607         setenv("USERPROFILE", "/home/PaloAlto");
1608         assert!(os::homedir() == Some(Path::new("/home/MountainView")));
1609
1610         if let Some(s) = oldhome {
1611             setenv("HOME", &s);
1612         }
1613         if let Some(s) = olduserprofile {
1614             setenv("USERPROFILE", &s);
1615         }
1616     }
1617
1618     #[test]
1619     fn memory_map_rw() {
1620         use result::Result::{Ok, Err};
1621
1622         let chunk = match os::MemoryMap::new(16, &[
1623             os::MapOption::MapReadable,
1624             os::MapOption::MapWritable
1625         ]) {
1626             Ok(chunk) => chunk,
1627             Err(msg) => panic!("{:?}", msg)
1628         };
1629         assert!(chunk.len >= 16);
1630
1631         unsafe {
1632             *chunk.data = 0xBE;
1633             assert!(*chunk.data == 0xBE);
1634         }
1635     }
1636
1637     #[test]
1638     fn memory_map_file() {
1639         use libc;
1640         use os::*;
1641         use old_io::fs::{File, unlink};
1642         use old_io::SeekStyle::SeekSet;
1643         use old_io::FileMode::Open;
1644         use old_io::FileAccess::ReadWrite;
1645
1646         #[cfg(not(windows))]
1647         fn get_fd(file: &File) -> libc::c_int {
1648             use os::unix::AsRawFd;
1649             file.as_raw_fd()
1650         }
1651
1652         #[cfg(windows)]
1653         fn get_fd(file: &File) -> libc::HANDLE {
1654             use os::windows::AsRawHandle;
1655             file.as_raw_handle()
1656         }
1657
1658         let mut path = tmpdir();
1659         path.push("mmap_file.tmp");
1660         let size = MemoryMap::granularity() * 2;
1661         let mut file = File::open_mode(&path, Open, ReadWrite).unwrap();
1662         file.seek(size as i64, SeekSet).unwrap();
1663         file.write_u8(0).unwrap();
1664
1665         let chunk = MemoryMap::new(size / 2, &[
1666             MapOption::MapReadable,
1667             MapOption::MapWritable,
1668             MapOption::MapFd(get_fd(&file)),
1669             MapOption::MapOffset(size / 2)
1670         ]).unwrap();
1671         assert!(chunk.len > 0);
1672
1673         unsafe {
1674             *chunk.data = 0xbe;
1675             assert!(*chunk.data == 0xbe);
1676         }
1677         drop(chunk);
1678
1679         unlink(&path).unwrap();
1680     }
1681
1682     #[test]
1683     #[cfg(windows)]
1684     fn split_paths_windows() {
1685         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1686             split_paths(unparsed) ==
1687                 parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
1688         }
1689
1690         assert!(check_parse("", &mut [""]));
1691         assert!(check_parse(r#""""#, &mut [""]));
1692         assert!(check_parse(";;", &mut ["", "", ""]));
1693         assert!(check_parse(r"c:\", &mut [r"c:\"]));
1694         assert!(check_parse(r"c:\;", &mut [r"c:\", ""]));
1695         assert!(check_parse(r"c:\;c:\Program Files\",
1696                             &mut [r"c:\", r"c:\Program Files\"]));
1697         assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"]));
1698         assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#,
1699                             &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"]));
1700     }
1701
1702     #[test]
1703     #[cfg(unix)]
1704     fn split_paths_unix() {
1705         fn check_parse(unparsed: &str, parsed: &[&str]) -> bool {
1706             split_paths(unparsed) ==
1707                 parsed.iter().map(|s| Path::new(*s)).collect::<Vec<_>>()
1708         }
1709
1710         assert!(check_parse("", &mut [""]));
1711         assert!(check_parse("::", &mut ["", "", ""]));
1712         assert!(check_parse("/", &mut ["/"]));
1713         assert!(check_parse("/:", &mut ["/", ""]));
1714         assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"]));
1715     }
1716
1717     #[test]
1718     #[cfg(unix)]
1719     fn join_paths_unix() {
1720         fn test_eq(input: &[&str], output: &str) -> bool {
1721             join_paths(input).unwrap() == output.as_bytes()
1722         }
1723
1724         assert!(test_eq(&[], ""));
1725         assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"],
1726                          "/bin:/usr/bin:/usr/local/bin"));
1727         assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""],
1728                          ":/bin:::/usr/bin:"));
1729         assert!(join_paths(&["/te:st"]).is_err());
1730     }
1731
1732     #[test]
1733     #[cfg(windows)]
1734     fn join_paths_windows() {
1735         fn test_eq(input: &[&str], output: &str) -> bool {
1736             join_paths(input).unwrap() == output.as_bytes()
1737         }
1738
1739         assert!(test_eq(&[], ""));
1740         assert!(test_eq(&[r"c:\windows", r"c:\"],
1741                         r"c:\windows;c:\"));
1742         assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""],
1743                         r";c:\windows;;;c:\;"));
1744         assert!(test_eq(&[r"c:\te;st", r"c:\"],
1745                         r#""c:\te;st";c:\"#));
1746         assert!(join_paths(&[r#"c:\te"st"#]).is_err());
1747     }
1748
1749     // More recursive_mkdir tests are in extra::tempfile
1750 }