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:
|
// - [x] ancestors of `p` are all ordinary directories in the old fs:
|
||||||
// corresponding directories will be created in the new fs.
|
// corresponding directories will be created in the new fs.
|
||||||
// mountpoints are treated as directories for this case.
|
// 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
|
// corresponding symlinks will be created in the new fs, as well as
|
||||||
// exactly as many underlying directories necessary to bind `p`.
|
// exactly as many underlying directories necessary to bind `p`.
|
||||||
// - [x] `p` itself is a symlink in the old fs, rather than a file/directory.
|
// - [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);
|
log::printfln("[namespace] not binding external path {} (of {})", cur_strpath, path_str);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
if (len(comp) >= 1 && strings::sub(comp, 0, 1) == "/") {
|
if (path::abs(comp)) {
|
||||||
// dirfd doesn't do well will absolute paths.
|
// dirfd doesn't do well will absolute paths.
|
||||||
comp = strings::sub(comp, 1, strings::end);
|
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;
|
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 =>
|
case let e: fs::error =>
|
||||||
log::printfln("[namespace] unable to copy intermediate path {} of {}: {}", cur_strpath, path_str, fs::strerror(e));
|
log::printfln("[namespace] unable to copy intermediate path {} of {}: {}", cur_strpath, path_str, fs::strerror(e));
|
||||||
return;
|
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;
|
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)) {
|
match (fs::stat(new_fs, strpath)) {
|
||||||
case let e: fs::error => void;
|
case let e: fs::error => void;
|
||||||
case let other: fs::filestat => return; // already created
|
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)?;
|
let linktext = fs::readlink(old_fs, strpath)?;
|
||||||
log::printfln("[namespace/bind] ln new/{} -> {}", strpath, linktext);
|
log::printfln("[namespace/bind] ln new/{} -> {}", strpath, linktext);
|
||||||
fs::symlink(new_fs, linktext, strpath)?;
|
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)) {
|
} else if (fs::isdir(st.mode)) {
|
||||||
log::printfln("[namespace/bind] mkdir new/{}", strpath);
|
log::printfln("[namespace/bind] mkdir new/{}", strpath);
|
||||||
fs::mkdir(new_fs, strpath, st.mode)?;
|
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)
|
// TODO: tune options (optional parameter; default is fs::flag::TRUNC)
|
||||||
log::printfln("[namespace/bind] touch new/{}", strpath);
|
log::printfln("[namespace/bind] touch new/{}", strpath);
|
||||||
fs::create(new_fs, strpath, st.mode)?;
|
fs::create(new_fs, strpath, st.mode)?;
|
||||||
|
Reference in New Issue
Block a user