Skip to content

Commit 6f422c4

Browse files
committed
Make os::getcwd() return IoResult<Path>
os::getcwd() panics if the current directory is not available. According to getcwd(3), there are three cases: - EACCES: Permission denied. - ENOENT: The current working directory has been removed. - ERANGE: The buffer size is less than the actual absolute path. This commit makes os::getcwd() return IoResult<Path>, not just Path, preventing it from panicking. As os::make_absolute() depends on os::getcwd(), it is also modified to return IoResult<Path>. Fixes #16946. [breaking-change]
1 parent 09e2ad1 commit 6f422c4

File tree

12 files changed

+56
-43
lines changed

12 files changed

+56
-43
lines changed

src/librustc/metadata/filesearch.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ pub fn rust_path() -> Vec<Path> {
219219
}
220220
None => Vec::new()
221221
};
222-
let mut cwd = os::getcwd();
222+
let mut cwd = os::getcwd().unwrap();
223223
// now add in default entries
224224
let cwd_dot_rust = cwd.join(".rust");
225225
if !env_rust_path.contains(&cwd_dot_rust) {

src/librustc/plugin/load.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ impl<'a> PluginLoader<'a> {
134134
// Dynamically link a registrar function into the compiler process.
135135
fn dylink_registrar(&mut self, vi: &ast::ViewItem, path: Path, symbol: String) {
136136
// Make sure the path contains a / or the linker will search for it.
137-
let path = os::make_absolute(&path);
137+
let path = os::make_absolute(&path).unwrap();
138138

139139
let lib = match DynamicLibrary::open(Some(&path)) {
140140
Ok(lib) => lib,

src/librustc/session/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ pub fn build_session_(sopts: config::Options,
231231
if path.is_absolute() {
232232
path.clone()
233233
} else {
234-
os::getcwd().join(&path)
234+
os::getcwd().unwrap().join(&path)
235235
}
236236
);
237237

@@ -246,7 +246,7 @@ pub fn build_session_(sopts: config::Options,
246246
plugin_registrar_fn: Cell::new(None),
247247
default_sysroot: default_sysroot,
248248
local_crate_source_file: local_crate_source_file,
249-
working_dir: os::getcwd(),
249+
working_dir: os::getcwd().unwrap(),
250250
lint_store: RefCell::new(lint::LintStore::new()),
251251
lints: RefCell::new(NodeMap::new()),
252252
crate_types: RefCell::new(Vec::new()),

src/librustc_back/archive.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -229,7 +229,7 @@ impl<'a> ArchiveBuilder<'a> {
229229
pub fn build(self) -> Archive<'a> {
230230
// Get an absolute path to the destination, so `ar` will work even
231231
// though we run it from `self.work_dir`.
232-
let abs_dst = os::getcwd().join(&self.archive.dst);
232+
let abs_dst = os::getcwd().unwrap().join(&self.archive.dst);
233233
assert!(!abs_dst.is_relative());
234234
let mut args = vec![&abs_dst];
235235
let mut total_len = abs_dst.as_vec().len();
@@ -286,7 +286,7 @@ impl<'a> ArchiveBuilder<'a> {
286286
// First, extract the contents of the archive to a temporary directory.
287287
// We don't unpack directly into `self.work_dir` due to the possibility
288288
// of filename collisions.
289-
let archive = os::make_absolute(archive);
289+
let archive = os::make_absolute(archive).unwrap();
290290
run_ar(self.archive.handler, &self.archive.maybe_ar_prog,
291291
"x", Some(loc.path()), &[&archive]);
292292

src/librustc_back/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use std::os;
1616
/// returned path does not contain any symlinks in its hierarchy.
1717
pub fn realpath(original: &Path) -> io::IoResult<Path> {
1818
static MAX_LINKS_FOLLOWED: uint = 256;
19-
let original = os::make_absolute(original);
19+
let original = os::make_absolute(original).unwrap();
2020

2121
// Right now lstat on windows doesn't work quite well
2222
if cfg!(windows) {

src/librustc_back/rpath.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig,
102102
"$ORIGIN"
103103
};
104104

105-
let mut lib = (config.realpath)(&os::make_absolute(lib)).unwrap();
105+
let mut lib = (config.realpath)(&os::make_absolute(lib).unwrap()).unwrap();
106106
lib.pop();
107-
let mut output = (config.realpath)(&os::make_absolute(&config.out_filename)).unwrap();
107+
let mut output = (config.realpath)(&os::make_absolute(&config.out_filename).unwrap()).unwrap();
108108
output.pop();
109109
let relative = lib.path_relative_from(&output);
110110
let relative = relative.expect("could not create rpath relative to output");
@@ -116,7 +116,7 @@ fn get_rpath_relative_to_output(config: &mut RPathConfig,
116116

117117
fn get_install_prefix_rpath(config: RPathConfig) -> String {
118118
let path = (config.get_install_prefix_lib_path)();
119-
let path = os::make_absolute(&path);
119+
let path = os::make_absolute(&path).unwrap();
120120
// FIXME (#9639): This needs to handle non-utf8 paths
121121
path.as_str().expect("non-utf8 component in rpath").to_string()
122122
}

src/libstd/io/process.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -974,7 +974,7 @@ mod tests {
974974
let prog = pwd_cmd().spawn().unwrap();
975975

976976
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();
977-
let parent_dir = os::getcwd();
977+
let parent_dir = os::getcwd().unwrap();
978978
let child_dir = Path::new(output.as_slice().trim());
979979

980980
let parent_stat = parent_dir.stat().unwrap();
@@ -989,7 +989,7 @@ mod tests {
989989
use os;
990990
// test changing to the parent of os::getcwd() because we know
991991
// the path exists (and os::getcwd() is not expected to be root)
992-
let parent_dir = os::getcwd().dir_path();
992+
let parent_dir = os::getcwd().unwrap().dir_path();
993993
let prog = pwd_cmd().cwd(&parent_dir).spawn().unwrap();
994994

995995
let output = String::from_utf8(prog.wait_with_output().unwrap().output).unwrap();

src/libstd/io/tempfile.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ impl TempDir {
3535
/// If no directory can be created, `Err` is returned.
3636
pub fn new_in(tmpdir: &Path, suffix: &str) -> IoResult<TempDir> {
3737
if !tmpdir.is_absolute() {
38-
return TempDir::new_in(&os::make_absolute(tmpdir), suffix);
38+
let abs_tmpdir = try!(os::make_absolute(tmpdir));
39+
return TempDir::new_in(&abs_tmpdir, suffix);
3940
}
4041

4142
static CNT: atomic::AtomicUint = atomic::INIT_ATOMIC_UINT;

src/libstd/io/test.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ fn base_port() -> u16 {
7575
];
7676

7777
// FIXME (#9639): This needs to handle non-utf8 paths
78-
let path = os::getcwd();
78+
let path = os::getcwd().unwrap();
7979
let path_s = path.as_str().unwrap();
8080

8181
let mut final_base = base;

src/libstd/os.rs

+38-26
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ pub use self::MapError::*;
3838
use clone::Clone;
3939
use error::{FromError, Error};
4040
use fmt;
41-
use io::IoResult;
41+
use io::{IoResult, IoError};
4242
use iter::Iterator;
4343
use libc::{c_void, c_int};
4444
use libc;
@@ -76,72 +76,83 @@ pub fn num_cpus() -> uint {
7676
pub const TMPBUF_SZ : uint = 1000u;
7777
const BUF_BYTES : uint = 2048u;
7878

79-
/// Returns the current working directory as a Path.
79+
/// Returns the current working directory as a `Path`.
8080
///
81-
/// # Failure
81+
/// # Errors
8282
///
83-
/// Fails if the current working directory value is invalid:
83+
/// Returns an `Err` if the current working directory value is invalid.
8484
/// Possible cases:
8585
///
8686
/// * Current directory does not exist.
8787
/// * There are insufficient permissions to access the current directory.
88+
/// * The internal buffer is not large enough to hold the path.
8889
///
8990
/// # Example
9091
///
9192
/// ```rust
9293
/// use std::os;
9394
///
9495
/// // We assume that we are in a valid directory like "/home".
95-
/// let current_working_directory = os::getcwd();
96+
/// let current_working_directory = os::getcwd().unwrap();
9697
/// println!("The current directory is {}", current_working_directory.display());
9798
/// // /home
9899
/// ```
99100
#[cfg(unix)]
100-
pub fn getcwd() -> Path {
101+
pub fn getcwd() -> IoResult<Path> {
101102
use c_str::CString;
102103

103104
let mut buf = [0 as c_char, ..BUF_BYTES];
104105
unsafe {
105106
if libc::getcwd(buf.as_mut_ptr(), buf.len() as libc::size_t).is_null() {
106-
panic!()
107+
Err(IoError::last_error())
108+
} else {
109+
Ok(Path::new(CString::new(buf.as_ptr(), false)))
107110
}
108-
Path::new(CString::new(buf.as_ptr(), false))
109111
}
110112
}
111113

112-
/// Returns the current working directory as a Path.
114+
/// Returns the current working directory as a `Path`.
113115
///
114-
/// # Failure
116+
/// # Errors
115117
///
116-
/// Fails if the current working directory value is invalid.
117-
/// Possibles cases:
118+
/// Returns an `Err` if the current working directory value is invalid.
119+
/// Possible cases:
118120
///
119121
/// * Current directory does not exist.
120122
/// * There are insufficient permissions to access the current directory.
123+
/// * The internal buffer is not large enough to hold the path.
121124
///
122125
/// # Example
123126
///
124127
/// ```rust
125128
/// use std::os;
126129
///
127130
/// // We assume that we are in a valid directory like "C:\\Windows".
128-
/// let current_working_directory = os::getcwd();
131+
/// let current_working_directory = os::getcwd().unwrap();
129132
/// println!("The current directory is {}", current_working_directory.display());
130133
/// // C:\\Windows
131134
/// ```
132135
#[cfg(windows)]
133-
pub fn getcwd() -> Path {
136+
pub fn getcwd() -> IoResult<Path> {
134137
use libc::DWORD;
135138
use libc::GetCurrentDirectoryW;
139+
use io::OtherIoError;
136140

137141
let mut buf = [0 as u16, ..BUF_BYTES];
138142
unsafe {
139143
if libc::GetCurrentDirectoryW(buf.len() as DWORD, buf.as_mut_ptr()) == 0 as DWORD {
140-
panic!();
144+
return Err(IoError::last_error());
141145
}
142146
}
143-
Path::new(String::from_utf16(::str::truncate_utf16_at_nul(&buf))
144-
.expect("GetCurrentDirectoryW returned invalid UTF-16"))
147+
148+
match String::from_utf16(::str::truncate_utf16_at_nul(&buf)) {
149+
Some(ref cwd) => Ok(Path::new(cwd)),
150+
None => Err(IoError {
151+
kind: OtherIoError,
152+
desc: "GetCurrentDirectoryW returned invalid UTF-16",
153+
detail: None,
154+
}),
155+
}
145156
}
146157

147158
#[cfg(windows)]
@@ -829,20 +840,21 @@ pub fn tmpdir() -> Path {
829840
///
830841
/// // Assume we're in a path like /home/someuser
831842
/// let rel_path = Path::new("..");
832-
/// let abs_path = os::make_absolute(&rel_path);
843+
/// let abs_path = os::make_absolute(&rel_path).unwrap();
833844
/// println!("The absolute path is {}", abs_path.display());
834845
/// // Prints "The absolute path is /home"
835846
/// ```
836847
// NB: this is here rather than in path because it is a form of environment
837848
// querying; what it does depends on the process working directory, not just
838849
// the input paths.
839-
pub fn make_absolute(p: &Path) -> Path {
850+
pub fn make_absolute(p: &Path) -> IoResult<Path> {
840851
if p.is_absolute() {
841-
p.clone()
852+
Ok(p.clone())
842853
} else {
843-
let mut ret = getcwd();
844-
ret.push(p);
845-
ret
854+
getcwd().map(|mut cwd| {
855+
cwd.push(p);
856+
cwd
857+
})
846858
}
847859
}
848860

@@ -1881,11 +1893,11 @@ mod tests {
18811893
fn test() {
18821894
assert!((!Path::new("test-path").is_absolute()));
18831895

1884-
let cwd = getcwd();
1896+
let cwd = getcwd().unwrap();
18851897
debug!("Current working directory: {}", cwd.display());
18861898

1887-
debug!("{}", make_absolute(&Path::new("test-path")).display());
1888-
debug!("{}", make_absolute(&Path::new("/usr/bin")).display());
1899+
debug!("{}", make_absolute(&Path::new("test-path")).unwrap().display());
1900+
debug!("{}", make_absolute(&Path::new("/usr/bin")).unwrap().display());
18891901
}
18901902

18911903
#[test]

src/test/run-pass/process-spawn-with-unicode-params.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use std::path::Path;
2626

2727
fn main() {
2828
let my_args = os::args();
29-
let my_cwd = os::getcwd();
29+
let my_cwd = os::getcwd().unwrap();
3030
let my_env = os::env();
3131
let my_path = Path::new(os::self_exe_name().unwrap());
3232
let my_dir = my_path.dir_path();

src/test/run-pass/tempfile.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ fn test_rm_tempdir_close() {
123123
// to depend on std
124124
fn recursive_mkdir_rel() {
125125
let path = Path::new("frob");
126-
let cwd = os::getcwd();
126+
let cwd = os::getcwd().unwrap();
127127
println!("recursive_mkdir_rel: Making: {} in cwd {} [{}]", path.display(),
128128
cwd.display(), path.exists());
129129
fs::mkdir_recursive(&path, io::USER_RWX);
@@ -141,7 +141,7 @@ fn recursive_mkdir_dot() {
141141

142142
fn recursive_mkdir_rel_2() {
143143
let path = Path::new("./frob/baz");
144-
let cwd = os::getcwd();
144+
let cwd = os::getcwd().unwrap();
145145
println!("recursive_mkdir_rel_2: Making: {} in cwd {} [{}]", path.display(),
146146
cwd.display(), path.exists());
147147
fs::mkdir_recursive(&path, io::USER_RWX);

0 commit comments

Comments
 (0)