Skip to content

Commit 48f50ac

Browse files
committed
auto merge of #6107 : catamorphism/rust/mkdir_recursive, r=brson
r? @brson This hopefully addresses your concerns about the termination condition, and adds more tests. With a bonus documentation commit.
2 parents 868b7c1 + d045ce7 commit 48f50ac

File tree

3 files changed

+119
-22
lines changed

3 files changed

+119
-22
lines changed

src/libcore/os.rs

+20-16
Original file line numberDiff line numberDiff line change
@@ -643,20 +643,22 @@ pub fn make_dir(p: &Path, mode: c_int) -> bool {
643643
/// Returns true iff creation
644644
/// succeeded. Also creates all intermediate subdirectories
645645
/// if they don't already exist, giving all of them the same mode.
646+
647+
// tjc: if directory exists but with different permissions,
648+
// should we return false?
646649
pub fn mkdir_recursive(p: &Path, mode: c_int) -> bool {
647650
if path_is_dir(p) {
648651
return true;
649652
}
650-
let parent = p.dir_path();
651-
debug!("mkdir_recursive: parent = %s",
652-
parent.to_str());
653-
if parent.to_str() == ~"."
654-
|| parent.to_str() == ~"/" { // !!!
653+
else if p.components.is_empty() {
654+
return false;
655+
}
656+
else if p.components.len() == 1 {
655657
// No parent directories to create
656-
path_is_dir(&parent) && make_dir(p, mode)
658+
path_is_dir(p) || make_dir(p, mode)
657659
}
658660
else {
659-
mkdir_recursive(&parent, mode) && make_dir(p, mode)
661+
mkdir_recursive(&p.pop(), mode) && make_dir(p, mode)
660662
}
661663
}
662664

@@ -1267,6 +1269,8 @@ mod tests {
12671269
use run;
12681270
use str;
12691271
use vec;
1272+
use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
1273+
12701274
12711275
#[test]
12721276
pub fn last_os_error() {
@@ -1490,16 +1494,16 @@ mod tests {
14901494
}
14911495
14921496
#[test]
1493-
fn recursive_mkdir_ok() {
1494-
use libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
1497+
fn recursive_mkdir_slash() {
1498+
let path = Path("/");
1499+
assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
1500+
}
14951501
1496-
let root = os::tmpdir();
1497-
let path = "xy/z/zy";
1498-
let nested = root.push(path);
1499-
assert!(os::mkdir_recursive(&nested, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
1500-
assert!(os::path_is_dir(&root.push("xy")));
1501-
assert!(os::path_is_dir(&root.push("xy/z")));
1502-
assert!(os::path_is_dir(&nested));
1502+
#[test]
1503+
fn recursive_mkdir_empty() {
1504+
let path = Path("");
1505+
assert!(!os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
15031506
}
15041507

1508+
// More recursive_mkdir tests are in std::tempfile
15051509
}

src/libcore/path.rs

+40
Original file line numberDiff line numberDiff line change
@@ -49,31 +49,71 @@ pub fn PosixPath(s: &str) -> PosixPath {
4949
}
5050

5151
pub trait GenericPath {
52+
/// Converts a string to a Path
5253
fn from_str(&str) -> Self;
5354

55+
/// Returns the directory component of `self`, as a string
5456
fn dirname(&self) -> ~str;
57+
/// Returns the file component of `self`, as a string option.
58+
/// Returns None if `self` names a directory.
5559
fn filename(&self) -> Option<~str>;
60+
/// Returns the stem of the file component of `self`, as a string option.
61+
/// The stem is the slice of a filename starting at 0 and ending just before
62+
/// the last '.' in the name.
63+
/// Returns None if `self` names a directory.
5664
fn filestem(&self) -> Option<~str>;
65+
/// Returns the type of the file component of `self`, as a string option.
66+
/// The file type is the slice of a filename starting just after the last
67+
/// '.' in the name and ending at the last index in the filename.
68+
/// Returns None if `self` names a directory.
5769
fn filetype(&self) -> Option<~str>;
5870

71+
/// Returns a new path consisting of `self` with the parent directory component replaced
72+
/// with the given string.
5973
fn with_dirname(&self, (&str)) -> Self;
74+
/// Returns a new path consisting of `self` with the file component replaced
75+
/// with the given string.
6076
fn with_filename(&self, (&str)) -> Self;
77+
/// Returns a new path consisting of `self` with the file stem replaced
78+
/// with the given string.
6179
fn with_filestem(&self, (&str)) -> Self;
80+
/// Returns a new path consisting of `self` with the file type replaced
81+
/// with the given string.
6282
fn with_filetype(&self, (&str)) -> Self;
6383

84+
/// Returns the directory component of `self`, as a new path.
85+
/// If `self` has no parent, returns `self`.
6486
fn dir_path(&self) -> Self;
87+
/// Returns the file component of `self`, as a new path.
88+
/// If `self` names a directory, returns the empty path.
6589
fn file_path(&self) -> Self;
6690

91+
/// Returns a new Path whose parent directory is `self` and whose
92+
/// file component is the given string.
6793
fn push(&self, (&str)) -> Self;
94+
/// Returns a new Path consisting of the given path, made relative to `self`.
6895
fn push_rel(&self, (&Self)) -> Self;
96+
/// Returns a new Path consisting of the path given by the given vector
97+
/// of strings, relative to `self`.
6998
fn push_many(&self, (&[~str])) -> Self;
99+
/// Identical to `dir_path` except in the case where `self` has only one
100+
/// component. In this case, `pop` returns the empty path.
70101
fn pop(&self) -> Self;
71102

103+
/// The same as `push_rel`, except that the directory argument must not
104+
/// contain directory separators in any of its components.
72105
fn unsafe_join(&self, (&Self)) -> Self;
106+
/// On Unix, always returns false. On Windows, returns true iff `self`'s
107+
/// file stem is one of: `con` `aux` `com1` `com2` `com3` `com4`
108+
/// `lpt1` `lpt2` `lpt3` `prn` `nul`
73109
fn is_restricted(&self) -> bool;
74110

111+
/// Returns a new path that names the same file as `self`, without containing
112+
/// any '.', '..', or empty components. On Windows, uppercases the drive letter
113+
/// as well.
75114
fn normalize(&self) -> Self;
76115

116+
/// Returns `true` if `self` is an absolute path.
77117
fn is_absolute(&self) -> bool;
78118
}
79119

src/libstd/tempfile.rs

+59-6
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,62 @@ pub fn mkdtemp(tmpdir: &Path, suffix: &str) -> Option<Path> {
2323
None
2424
}
2525

26-
#[test]
27-
fn test_mkdtemp() {
28-
let p = mkdtemp(&Path("."), "foobar").unwrap();
29-
os::remove_dir(&p);
30-
assert!(str::ends_with(p.to_str(), "foobar"));
31-
}
26+
#[cfg(test)]
27+
mod tests {
28+
use tempfile::mkdtemp;
29+
use tempfile;
30+
31+
#[test]
32+
fn test_mkdtemp() {
33+
let p = mkdtemp(&Path("."), "foobar").unwrap();
34+
os::remove_dir(&p);
35+
assert!(str::ends_with(p.to_str(), "foobar"));
36+
}
37+
38+
// Ideally these would be in core::os but then core would need
39+
// to depend on std
40+
#[test]
41+
fn recursive_mkdir_rel() {
42+
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
43+
use core::os;
44+
45+
let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel");
46+
os::change_dir(&root);
47+
let path = Path("frob");
48+
assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
49+
assert!(os::path_is_dir(&path));
50+
assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
51+
assert!(os::path_is_dir(&path));
52+
}
53+
54+
#[test]
55+
fn recursive_mkdir_dot() {
56+
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
57+
use core::os;
58+
59+
let dot = Path(".");
60+
assert!(os::mkdir_recursive(&dot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
61+
let dotdot = Path("..");
62+
assert!(os::mkdir_recursive(&dotdot, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
63+
}
64+
65+
#[test]
66+
fn recursive_mkdir_rel_2() {
67+
use core::libc::consts::os::posix88::{S_IRUSR, S_IWUSR, S_IXUSR};
68+
use core::os;
69+
70+
let root = mkdtemp(&os::tmpdir(), "temp").expect("recursive_mkdir_rel_2");
71+
os::change_dir(&root);
72+
let path = Path("./frob/baz");
73+
debug!("...Making: %s in cwd %s", path.to_str(), os::getcwd().to_str());
74+
assert!(os::mkdir_recursive(&path, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
75+
assert!(os::path_is_dir(&path));
76+
assert!(os::path_is_dir(&path.pop()));
77+
let path2 = Path("quux/blat");
78+
debug!("Making: %s in cwd %s", path2.to_str(), os::getcwd().to_str());
79+
assert!(os::mkdir_recursive(&path2, (S_IRUSR | S_IWUSR | S_IXUSR) as i32));
80+
assert!(os::path_is_dir(&path2));
81+
assert!(os::path_is_dir(&path2.pop()));
82+
}
83+
84+
}

0 commit comments

Comments
 (0)