From 3be1c7b5147066812488942f7b982a63fe40885f Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Fri, 3 Jan 2020 03:53:06 +0100 Subject: [PATCH] Kernel: Fix awkward bug where "touch /foo/bar/baz" could create "/baz" To accomodate file creation, path resolution optionally returns the last valid parent directory seen while traversing the path. Clients will then interpret "ENOENT, but I have a parent for you" as meaning that the file doesn't exist, but its immediate parent directory does. The client then goes ahead and creates a new file. In the case of "/foo/bar/baz" where there is no "/foo", it would fail with ENOENT and "/" as the last seen parent directory, causing e.g the open() syscall to create "/baz". Covered by test_io. --- Kernel/FileSystem/VirtualFileSystem.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp index 64317dec64..5539032e69 100644 --- a/Kernel/FileSystem/VirtualFileSystem.cpp +++ b/Kernel/FileSystem/VirtualFileSystem.cpp @@ -692,8 +692,19 @@ KResultOr> VFS::resolve_path(StringView path, Custody& ba auto& current_parent = custody_chain.last(); crumb_id = crumb_inode->lookup(part); - if (!crumb_id.is_valid()) + if (!crumb_id.is_valid()) { + if (i != parts.size() - 1) { + // We didn't find the filename we were looking for, + // and we didn't even reach the last path part. + // (ENOENT with non-null parent_custody) signals to caller that + // we found the immediate parent of the file, but the file itself + // does not exist yet. + // Since this is not the immediate parent, clear parent_custody. + if (parent_custody) + *parent_custody = nullptr; + } return KResult(-ENOENT); + } if (auto mount = find_mount_for_host(crumb_id)) crumb_id = mount->guest(); if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && !is_vfs_root(crumb_id) && part == "..") {