vfs: dir_vnode_to_path(): Fix bug with chroot on mount
Simplify the code, which also fixes the bug that the I/O context's root was ignored when it was a mount point, thus resulting in globally rooted paths in this case.
This commit is contained in:
@@ -2585,50 +2585,40 @@ dir_vnode_to_path(struct vnode* vnode, char* buffer, size_t bufferSize,
|
|||||||
// efficient and does all we need from get_vnode()
|
// efficient and does all we need from get_vnode()
|
||||||
inc_vnode_ref_count(vnode);
|
inc_vnode_ref_count(vnode);
|
||||||
|
|
||||||
if (vnode != ioContext->root) {
|
|
||||||
// we don't hit the IO context root
|
|
||||||
// resolve a vnode to its covered vnode
|
|
||||||
if (Vnode* coveredVnode = get_covered_vnode(vnode)) {
|
|
||||||
put_vnode(vnode);
|
|
||||||
vnode = coveredVnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
path[--insert] = '\0';
|
path[--insert] = '\0';
|
||||||
// the path is filled right to left
|
// the path is filled right to left
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// the name buffer is also used for fs_read_dir()
|
// If the node is the context's root, bail out. Otherwise resolve mount
|
||||||
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
// points.
|
||||||
char* name = &((struct dirent*)nameBuffer)->d_name[0];
|
if (vnode == ioContext->root)
|
||||||
struct vnode* parentVnode;
|
break;
|
||||||
|
|
||||||
|
if (Vnode* coveredVnode = get_covered_vnode(vnode)) {
|
||||||
|
put_vnode(vnode);
|
||||||
|
vnode = coveredVnode;
|
||||||
|
}
|
||||||
|
|
||||||
// lookup the parent vnode
|
// lookup the parent vnode
|
||||||
if (vnode == ioContext->root) {
|
struct vnode* parentVnode;
|
||||||
// we hit the IO context root
|
status = lookup_dir_entry(vnode, "..", &parentVnode);
|
||||||
parentVnode = vnode;
|
if (status != B_OK)
|
||||||
inc_vnode_ref_count(vnode);
|
goto out;
|
||||||
} else {
|
|
||||||
status = lookup_dir_entry(vnode, "..", &parentVnode);
|
if (parentVnode == vnode) {
|
||||||
if (status != B_OK)
|
// The caller apparently got their hands on a node outside of their
|
||||||
goto out;
|
// context's root. Now we've hit the global root.
|
||||||
|
put_vnode(parentVnode);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the node's name
|
// get the node's name
|
||||||
|
char nameBuffer[sizeof(struct dirent) + B_FILE_NAME_LENGTH];
|
||||||
|
// also used for fs_read_dir()
|
||||||
|
char* name = &((struct dirent*)nameBuffer)->d_name[0];
|
||||||
status = get_vnode_name(vnode, parentVnode, (struct dirent*)nameBuffer,
|
status = get_vnode_name(vnode, parentVnode, (struct dirent*)nameBuffer,
|
||||||
sizeof(nameBuffer), ioContext);
|
sizeof(nameBuffer), ioContext);
|
||||||
|
|
||||||
if (vnode != ioContext->root) {
|
|
||||||
// we don't hit the IO context root
|
|
||||||
// resolve a vnode to its covered vnode
|
|
||||||
if (Vnode* coveredVnode = get_covered_vnode(parentVnode)) {
|
|
||||||
put_vnode(parentVnode);
|
|
||||||
parentVnode = coveredVnode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool hitRoot = (parentVnode == vnode);
|
|
||||||
|
|
||||||
// release the current vnode, we only need its parent from now on
|
// release the current vnode, we only need its parent from now on
|
||||||
put_vnode(vnode);
|
put_vnode(vnode);
|
||||||
vnode = parentVnode;
|
vnode = parentVnode;
|
||||||
@@ -2636,12 +2626,6 @@ dir_vnode_to_path(struct vnode* vnode, char* buffer, size_t bufferSize,
|
|||||||
if (status != B_OK)
|
if (status != B_OK)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
if (hitRoot) {
|
|
||||||
// we have reached "/", which means we have constructed the full
|
|
||||||
// path
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: add an explicit check for loops in about 10 levels to do
|
// TODO: add an explicit check for loops in about 10 levels to do
|
||||||
// real loop detection
|
// real loop detection
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user