diff options
Diffstat (limited to 'src/libcore/os.rs')
| -rw-r--r-- | src/libcore/os.rs | 155 |
1 files changed, 153 insertions, 2 deletions
diff --git a/src/libcore/os.rs b/src/libcore/os.rs index d5271ec228b..42c77a687e5 100644 --- a/src/libcore/os.rs +++ b/src/libcore/os.rs @@ -38,6 +38,7 @@ use ptr; use str; use task; use uint; +use unstable::finally::Finally; use vec; pub use libc::fclose; @@ -372,8 +373,9 @@ pub fn pipe() -> Pipe { // 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 - // first, as in rust_run_program. - let mut fds = Pipe {in: 0 as c_int, out: 0 as c_int}; + // first, as in core::run. + let mut fds = Pipe {in: 0 as c_int, + out: 0 as c_int }; let res = libc::pipe(&mut fds.in, 1024 as ::libc::c_uint, (libc::O_BINARY | libc::O_NOINHERIT) as c_int); assert!((res == 0 as c_int)); @@ -770,6 +772,28 @@ pub fn list_dir_path(p: &Path) -> ~[~Path] { list_dir(p).map(|f| ~p.push(*f)) } +/// Removes a directory at the specified path, after removing +/// all its contents. Use carefully! +pub fn remove_dir_recursive(p: &Path) -> bool { + let mut error_happened = false; + for walk_dir(p) |inner| { + if !error_happened { + if path_is_dir(inner) { + if !remove_dir_recursive(inner) { + error_happened = true; + } + } + else { + if !remove_file(inner) { + error_happened = true; + } + } + } + }; + // Directory should now be empty + !error_happened && remove_dir(p) +} + /// Removes a directory at the specified path pub fn remove_dir(p: &Path) -> bool { return rmdir(p); @@ -817,6 +841,36 @@ pub fn change_dir(p: &Path) -> bool { } } +/// Changes the current working directory to the specified +/// path while acquiring a global lock, then calls `action`. +/// If the change is successful, releases the lock and restores the +/// CWD to what it was before, returning true. +/// Returns false if the directory doesn't exist or if the directory change +/// is otherwise unsuccessful. +pub fn change_dir_locked(p: &Path, action: &fn()) -> bool { + use unstable::global::global_data_clone_create; + use unstable::{Exclusive, exclusive}; + + fn key(_: Exclusive<()>) { } + + let result = unsafe { + global_data_clone_create(key, || { + ~exclusive(()) + }) + }; + + do result.with_imm() |_| { + let old_dir = os::getcwd(); + if change_dir(p) { + action(); + change_dir(&old_dir) + } + else { + false + } + } +} + /// Copies a file from one location to another pub fn copy_file(from: &Path, to: &Path) -> bool { return do_copy_file(from, to); @@ -845,6 +899,10 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { if istream as uint == 0u { return false; } + // Preserve permissions + let from_mode = from.get_mode().expect("copy_file: couldn't get permissions \ + for source file"); + let ostream = do as_c_charp(to.to_str()) |top| { do as_c_charp("w+b") |modebuf| { libc::fopen(top, modebuf) @@ -876,6 +934,15 @@ pub fn copy_file(from: &Path, to: &Path) -> bool { } fclose(istream); fclose(ostream); + + // Give the new file the old file's permissions + unsafe { + if do str::as_c_str(to.to_str()) |to_buf| { + libc::chmod(to_buf, from_mode as mode_t) + } != 0 { + return false; // should be a condition... + } + } return ok; } } @@ -1152,6 +1219,88 @@ pub fn set_args(new_args: ~[~str]) { } } +// FIXME #6100 we should really use an internal implementation of this - using +// the POSIX glob functions isn't portable to windows, probably has slight +// inconsistencies even where it is implemented, and makes extending +// functionality a lot more difficult +// FIXME #6101 also provide a non-allocating version - each_glob or so? +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "linux")] +#[cfg(target_os = "android")] +#[cfg(target_os = "freebsd")] +#[cfg(target_os = "macos")] +pub fn glob(pattern: &str) -> ~[Path] { + #[cfg(target_os = "linux")] + #[cfg(target_os = "android")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + gl_pathv: ptr::null(), + gl_offs: 0, + __unused1: ptr::null(), + __unused2: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + } + } + + #[cfg(target_os = "freebsd")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + #[cfg(target_os = "macos")] + fn default_glob_t () -> libc::glob_t { + libc::glob_t { + gl_pathc: 0, + __unused1: 0, + gl_offs: 0, + __unused2: 0, + gl_pathv: ptr::null(), + __unused3: ptr::null(), + __unused4: ptr::null(), + __unused5: ptr::null(), + __unused6: ptr::null(), + __unused7: ptr::null(), + __unused8: ptr::null(), + } + } + + let mut g = default_glob_t(); + do str::as_c_str(pattern) |c_pattern| { + unsafe { libc::glob(c_pattern, 0, ptr::null(), &mut g) } + }; + do(|| { + let paths = unsafe { + vec::raw::from_buf_raw(g.gl_pathv, g.gl_pathc as uint) + }; + do paths.map |&c_str| { + Path(unsafe { str::raw::from_c_str(c_str) }) + } + }).finally { + unsafe { libc::globfree(&mut g) }; + } +} + +/// Returns a vector of Path objects that match the given glob pattern +#[cfg(target_os = "win32")] +pub fn glob(pattern: &str) -> ~[Path] { + fail!(~"glob() is unimplemented on Windows") +} + #[cfg(target_os = "macos")] extern { // These functions are in crt_externs.h. @@ -1480,6 +1629,7 @@ mod tests { == buf.len() as size_t)) } assert!((libc::fclose(ostream) == (0u as c_int))); + let in_mode = in.get_mode(); let rs = os::copy_file(&in, &out); if (!os::path_exists(&in)) { fail!(fmt!("%s doesn't exist", in.to_str())); @@ -1487,6 +1637,7 @@ mod tests { assert!((rs)); let rslt = run::run_program(~"diff", ~[in.to_str(), out.to_str()]); assert!((rslt == 0)); + assert!(out.get_mode() == in_mode); assert!((remove_file(&in))); assert!((remove_file(&out))); } |
