kernel/fs: Don't report the leaf node in vnode_path_to_vnode unless it's last.

That is, if we have a path like "/nonexistent-1/nonexistent-2/file",
we shouldn't report "nonexistent-1" as the "leaf" node, but rather
nothing at all. Otherwise, create_vnode() that expects the result to be a
directory vnode plus a nonexistent file will get confused and try
to create a file "/nonexistent-1" rather than just bailing out.

This fixes #19062. The reproducer in that ticket caused a scenario
much like the above; and since rootfs doesn't support regular files,
it returned "EINVAL" when attempting to create the "/nonexistent" file.
After this change, we get ENOENT as expected.

Change-Id: Ifcaaa858403fb747858800afbf644051bb9913ad
Reviewed-on: https://review.haiku-os.org/c/haiku/+/8621
Reviewed-by: Jérôme Duval <jerome.duval@gmail.com>
Tested-by: Commit checker robot <no-reply+buildbot@haiku-os.org>
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2024-12-03 20:21:39 -05:00 committed by waddlesplash
parent 4c98a54842
commit 149182f6ac

View File

@ -2224,7 +2224,7 @@ vnode_path_to_vnode(struct vnode* start, char* path, bool traverseLeafLink,
}
if (status != B_OK) {
if (leafName != NULL) {
if (leafName != NULL && !directoryFound) {
strlcpy(leafName, path, B_FILE_NAME_LENGTH);
_vnode.SetTo(vnode.Detach());
}
@ -5413,16 +5413,16 @@ create_vnode(struct vnode* directory, const char* name, int openMode,
status = vnode_path_to_vnode(directory, clonedName, true,
kernel, vnode, NULL, clonedName);
if (status != B_OK) {
if (status != B_ENTRY_NOT_FOUND || !vnode.IsSet())
return status;
// vnode is not found, but maybe it has a parent and we can create it from
// there. In that case, vnode_path_to_vnode has set vnode to the latest
// directory found in the path
if (status == B_ENTRY_NOT_FOUND) {
directory = vnode.Detach();
dirPutter.SetTo(directory);
name = clonedName;
create = true;
} else
return status;
// directory found in the path.
directory = vnode.Detach();
dirPutter.SetTo(directory);
name = clonedName;
create = true;
}
}