summaryrefslogtreecommitdiff
path: root/Kernel/Process.cpp
diff options
context:
space:
mode:
authorSergey Bugaev <bugaevc@serenityos.org>2020-06-16 21:51:08 +0300
committerAndreas Kling <kling@serenityos.org>2020-06-17 15:02:03 +0200
commit47d83800e1c27c0a26d3ee432973d49a3f83f299 (patch)
treed3dcf6565f6aa111a2013eb0b60ba2c99219262b /Kernel/Process.cpp
parent35329400b899f632866348c95c4bb04920ed6f58 (diff)
downloadserenity-47d83800e1c27c0a26d3ee432973d49a3f83f299.zip
Kernel+LibC: Do not return -ENAMETOOLONG from sys$readlink()
That's not how readlink() is supposed to work: it should copy as many bytes as fit into the buffer, and return the number of bytes copied. So do that, but add a twist: make sys$readlink() actually return the whole size, not the number of bytes copied. We fix up this return value in userspace, to make LibC's readlink() behave as expected, but this will also allow other code to allocate a buffer of just the right size. Also, avoid an extra copy of the link target.
Diffstat (limited to 'Kernel/Process.cpp')
-rw-r--r--Kernel/Process.cpp10
1 files changed, 5 insertions, 5 deletions
diff --git a/Kernel/Process.cpp b/Kernel/Process.cpp
index 568648401e..9c066baf95 100644
--- a/Kernel/Process.cpp
+++ b/Kernel/Process.cpp
@@ -1953,11 +1953,11 @@ int Process::sys$readlink(const Syscall::SC_readlink_params* user_params)
if (contents.is_error())
return contents.error();
- auto link_target = String::copy(contents.value());
- if (link_target.length() > params.buffer.size)
- return -ENAMETOOLONG;
- copy_to_user(params.buffer.data, link_target.characters(), link_target.length());
- return link_target.length();
+ auto& link_target = contents.value();
+ auto size_to_copy = min(link_target.size(), params.buffer.size);
+ copy_to_user(params.buffer.data, link_target.data(), size_to_copy);
+ // Note: we return the whole size here, not the copied size.
+ return link_target.size();
}
int Process::sys$chdir(const char* user_path, size_t path_length)