bunpen: handle intermediary symlinks when binding
This commit is contained in:
@@ -105,7 +105,7 @@ fn isolate_paths(paths: []path::buffer) void = {
|
||||
// - [x] ancestors of `p` are all ordinary directories in the old fs:
|
||||
// corresponding directories will be created in the new fs.
|
||||
// mountpoints are treated as directories for this case.
|
||||
// - [ ] ancestors of `p` are symlinks, such that `p != realpath(p)`.
|
||||
// - [x] ancestors of `p` are symlinks, such that `p != realpath(p)`.
|
||||
// corresponding symlinks will be created in the new fs, as well as
|
||||
// exactly as many underlying directories necessary to bind `p`.
|
||||
// - [x] `p` itself is a symlink in the old fs, rather than a file/directory.
|
||||
@@ -130,7 +130,7 @@ fn bind_leaf(old_fs: *fs::fs, new_fs: *fs::fs, user_path: *path::buffer) void =
|
||||
log::printfln("[namespace] not binding external path {} (of {})", cur_strpath, path_str);
|
||||
return;
|
||||
};
|
||||
if (len(comp) >= 1 && strings::sub(comp, 0, 1) == "/") {
|
||||
if (path::abs(comp)) {
|
||||
// dirfd doesn't do well will absolute paths.
|
||||
comp = strings::sub(comp, 1, strings::end);
|
||||
};
|
||||
@@ -142,10 +142,13 @@ fn bind_leaf(old_fs: *fs::fs, new_fs: *fs::fs, user_path: *path::buffer) void =
|
||||
yield other;
|
||||
};
|
||||
|
||||
match (bind_component(old_fs, new_fs, cur_strpath)) {
|
||||
match (bind_component(old_fs, new_fs, cur_strpath, path::iterrem(&it))) {
|
||||
case let e: fs::error =>
|
||||
log::printfln("[namespace] unable to copy intermediate path {} of {}: {}", cur_strpath, path_str, fs::strerror(e));
|
||||
return;
|
||||
case let e: path::error =>
|
||||
log::printfln("[namespace] unable to copy intermediate path {} of {}: {}", cur_strpath, path_str, path::strerror(e));
|
||||
return;
|
||||
case void => void;
|
||||
};
|
||||
};
|
||||
@@ -171,7 +174,7 @@ fn bind_leaf(old_fs: *fs::fs, new_fs: *fs::fs, user_path: *path::buffer) void =
|
||||
));
|
||||
};
|
||||
|
||||
fn bind_component(old_fs: *fs::fs, new_fs: *fs::fs, strpath: str) (void | fs::error) = {
|
||||
fn bind_component(old_fs: *fs::fs, new_fs: *fs::fs, strpath: str, remaining: str) (void | fs::error | path::error) = {
|
||||
match (fs::stat(new_fs, strpath)) {
|
||||
case let e: fs::error => void;
|
||||
case let other: fs::filestat => return; // already created
|
||||
@@ -185,11 +188,27 @@ fn bind_component(old_fs: *fs::fs, new_fs: *fs::fs, strpath: str) (void | fs::er
|
||||
let linktext = fs::readlink(old_fs, strpath)?;
|
||||
log::printfln("[namespace/bind] ln new/{} -> {}", strpath, linktext);
|
||||
fs::symlink(new_fs, linktext, strpath)?;
|
||||
// TODO: lots of edge cases with symlinks i need to flesh out here.
|
||||
if (remaining != "") {
|
||||
// bind the real path (or, the "more real" path, in case there are
|
||||
// multiple layers of symlink).
|
||||
let target_path: path::buffer = if (path::abs(linktext)) {
|
||||
// foo/bar/baz/fnord with bar -> /target => `/target/baz/fnord`
|
||||
yield path::init(linktext, remaining)?;
|
||||
} else {
|
||||
// foo/bar/baz/fnord with foo -> target => `foo/target/bar/baz`
|
||||
yield path::init(strpath, "..", linktext, remaining)?;
|
||||
};
|
||||
bind_leaf(old_fs, new_fs, &target_path);
|
||||
};
|
||||
} else if (fs::isdir(st.mode)) {
|
||||
log::printfln("[namespace/bind] mkdir new/{}", strpath);
|
||||
fs::mkdir(new_fs, strpath, st.mode)?;
|
||||
} else {
|
||||
} else { // file-like
|
||||
if (remaining != "") {
|
||||
log::printfln("[namespace/bind] ignoring file where a non-terminal was expected: {}", strpath);
|
||||
return fs::wrongtype;
|
||||
};
|
||||
|
||||
// TODO: tune options (optional parameter; default is fs::flag::TRUNC)
|
||||
log::printfln("[namespace/bind] touch new/{}", strpath);
|
||||
fs::create(new_fs, strpath, st.mode)?;
|
||||
|
Reference in New Issue
Block a user