summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorcircl <circl.lastname@gmail.com>2021-12-31 19:20:17 +0100
committerAndreas Kling <kling@serenityos.org>2022-01-01 15:08:49 +0100
commit63760603f3adec2fb696018f6c1c77feeb0dbdd0 (patch)
tree3d96a31951e538ab9cdc3c99b025ff5c9a41bb42
parent344cfa0db4a76601754aead153fa52d2cde6db1e (diff)
downloadserenity-63760603f3adec2fb696018f6c1c77feeb0dbdd0.zip
Kernel+LibC+LibCore: Add lchown and fchownat functions
This modifies sys$chown to allow specifying whether or not to follow symlinks and in which directory. This was then used to implement lchown and fchownat in LibC and LibCore.
-rw-r--r--Kernel/API/Syscall.h2
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.cpp4
-rw-r--r--Kernel/FileSystem/VirtualFileSystem.h2
-rw-r--r--Kernel/Syscalls/chown.cpp15
-rw-r--r--Userland/Libraries/LibC/unistd.cpp24
-rw-r--r--Userland/Libraries/LibC/unistd.h2
-rw-r--r--Userland/Libraries/LibCore/System.cpp21
-rw-r--r--Userland/Libraries/LibCore/System.h1
8 files changed, 64 insertions, 7 deletions
diff --git a/Kernel/API/Syscall.h b/Kernel/API/Syscall.h
index 6372efb165..d02184fdfd 100644
--- a/Kernel/API/Syscall.h
+++ b/Kernel/API/Syscall.h
@@ -400,6 +400,8 @@ struct SC_chown_params {
StringArgument path;
u32 uid;
u32 gid;
+ int dirfd;
+ int follow_symlinks;
};
struct SC_mknod_params {
diff --git a/Kernel/FileSystem/VirtualFileSystem.cpp b/Kernel/FileSystem/VirtualFileSystem.cpp
index 3855182999..2bcf342329 100644
--- a/Kernel/FileSystem/VirtualFileSystem.cpp
+++ b/Kernel/FileSystem/VirtualFileSystem.cpp
@@ -564,9 +564,9 @@ ErrorOr<void> VirtualFileSystem::chown(Custody& custody, UserID a_uid, GroupID a
return inode.chown(new_uid, new_gid);
}
-ErrorOr<void> VirtualFileSystem::chown(StringView path, UserID a_uid, GroupID a_gid, Custody& base)
+ErrorOr<void> VirtualFileSystem::chown(StringView path, UserID a_uid, GroupID a_gid, Custody& base, int options)
{
- auto custody = TRY(resolve_path(path, base));
+ auto custody = TRY(resolve_path(path, base, nullptr, options));
return chown(custody, a_uid, a_gid);
}
diff --git a/Kernel/FileSystem/VirtualFileSystem.h b/Kernel/FileSystem/VirtualFileSystem.h
index bee3f1504f..a1386dbb14 100644
--- a/Kernel/FileSystem/VirtualFileSystem.h
+++ b/Kernel/FileSystem/VirtualFileSystem.h
@@ -59,7 +59,7 @@ public:
ErrorOr<void> rmdir(StringView path, Custody& base);
ErrorOr<void> chmod(StringView path, mode_t, Custody& base);
ErrorOr<void> chmod(Custody&, mode_t);
- ErrorOr<void> chown(StringView path, UserID, GroupID, Custody& base);
+ ErrorOr<void> chown(StringView path, UserID, GroupID, Custody& base, int options);
ErrorOr<void> chown(Custody&, UserID, GroupID);
ErrorOr<void> access(StringView path, int mode, Custody& base);
ErrorOr<InodeMetadata> lookup_metadata(StringView path, Custody& base, int options = 0);
diff --git a/Kernel/Syscalls/chown.cpp b/Kernel/Syscalls/chown.cpp
index 92172fed61..0db2c9cccc 100644
--- a/Kernel/Syscalls/chown.cpp
+++ b/Kernel/Syscalls/chown.cpp
@@ -4,6 +4,8 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
+#include <AK/NonnullRefPtrVector.h>
+#include <Kernel/FileSystem/Custody.h>
#include <Kernel/FileSystem/OpenFileDescription.h>
#include <Kernel/Process.h>
@@ -24,7 +26,18 @@ ErrorOr<FlatPtr> Process::sys$chown(Userspace<const Syscall::SC_chown_params*> u
TRY(require_promise(Pledge::chown));
auto params = TRY(copy_typed_from_user(user_params));
auto path = TRY(get_syscall_path_argument(params.path));
- TRY(VirtualFileSystem::the().chown(path->view(), params.uid, params.gid, current_directory()));
+
+ RefPtr<Custody> base;
+ if (params.dirfd == AT_FDCWD) {
+ base = current_directory();
+ } else {
+ auto base_description = TRY(fds().open_file_description(params.dirfd));
+ if (!base_description->custody())
+ return EINVAL;
+ base = base_description->custody();
+ }
+
+ TRY(VirtualFileSystem::the().chown(path->view(), params.uid, params.gid, *base, params.follow_symlinks ? 0 : O_NOFOLLOW_NOERROR));
return 0;
}
diff --git a/Userland/Libraries/LibC/unistd.cpp b/Userland/Libraries/LibC/unistd.cpp
index 2c0ba9a8f1..d2a7c134bb 100644
--- a/Userland/Libraries/LibC/unistd.cpp
+++ b/Userland/Libraries/LibC/unistd.cpp
@@ -38,13 +38,24 @@ static __thread int s_cached_tid = 0;
static int s_cached_pid = 0;
+int lchown(const char* pathname, uid_t uid, gid_t gid)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid, AT_FDCWD, false };
+ int rc = syscall(SC_chown, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
int chown(const char* pathname, uid_t uid, gid_t gid)
{
if (!pathname) {
errno = EFAULT;
return -1;
}
- Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid };
+ Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid, AT_FDCWD, true };
int rc = syscall(SC_chown, &params);
__RETURN_WITH_ERRNO(rc, rc, -1);
}
@@ -55,6 +66,17 @@ int fchown(int fd, uid_t uid, gid_t gid)
__RETURN_WITH_ERRNO(rc, rc, -1);
}
+int fchownat(int fd, const char* pathname, uid_t uid, gid_t gid, int flags)
+{
+ if (!pathname) {
+ errno = EFAULT;
+ return -1;
+ }
+ Syscall::SC_chown_params params { { pathname, strlen(pathname) }, uid, gid, fd, !(flags & AT_SYMLINK_NOFOLLOW) };
+ int rc = syscall(SC_chown, &params);
+ __RETURN_WITH_ERRNO(rc, rc, -1);
+}
+
pid_t fork()
{
__pthread_fork_prepare();
diff --git a/Userland/Libraries/LibC/unistd.h b/Userland/Libraries/LibC/unistd.h
index 5ed0229809..b12cc237af 100644
--- a/Userland/Libraries/LibC/unistd.h
+++ b/Userland/Libraries/LibC/unistd.h
@@ -104,8 +104,10 @@ int mknod(const char* pathname, mode_t, dev_t);
long fpathconf(int fd, int name);
long pathconf(const char* path, int name);
char* getlogin();
+int lchown(const char* pathname, uid_t uid, gid_t gid);
int chown(const char* pathname, uid_t, gid_t);
int fchown(int fd, uid_t, gid_t);
+int fchownat(int fd, const char* pathname, uid_t uid, gid_t gid, int flags);
int ftruncate(int fd, off_t length);
int truncate(const char* path, off_t length);
int mount(int source_fd, const char* target, const char* fs_type, int flags);
diff --git a/Userland/Libraries/LibCore/System.cpp b/Userland/Libraries/LibCore/System.cpp
index f51145fac2..462aa65236 100644
--- a/Userland/Libraries/LibCore/System.cpp
+++ b/Userland/Libraries/LibCore/System.cpp
@@ -368,13 +368,13 @@ ErrorOr<void> fchmod(int fd, mode_t mode)
return {};
}
-ErrorOr<void> chown(StringView pathname, uid_t uid, gid_t gid)
+ErrorOr<void> lchown(StringView pathname, uid_t uid, gid_t gid)
{
if (!pathname.characters_without_null_termination())
return Error::from_syscall("chown"sv, -EFAULT);
#ifdef __serenity__
- Syscall::SC_chown_params params = { { pathname.characters_without_null_termination(), pathname.length() }, uid, gid };
+ Syscall::SC_chown_params params = { { pathname.characters_without_null_termination(), pathname.length() }, uid, gid, AT_FDCWD, false };
int rc = syscall(SC_chown, &params);
HANDLE_SYSCALL_RETURN_VALUE("chown"sv, rc, {});
#else
@@ -385,6 +385,23 @@ ErrorOr<void> chown(StringView pathname, uid_t uid, gid_t gid)
#endif
}
+ErrorOr<void> chown(StringView pathname, uid_t uid, gid_t gid)
+{
+ if (!pathname.characters_without_null_termination())
+ return Error::from_syscall("chown"sv, -EFAULT);
+
+#ifdef __serenity__
+ Syscall::SC_chown_params params = { { pathname.characters_without_null_termination(), pathname.length() }, uid, gid, AT_FDCWD, true };
+ int rc = syscall(SC_chown, &params);
+ HANDLE_SYSCALL_RETURN_VALUE("chown"sv, rc, {});
+#else
+ String path = pathname;
+ if (::lchown(path.characters(), uid, gid) < 0)
+ return Error::from_syscall("lchown"sv, -errno);
+ return {};
+#endif
+}
+
ErrorOr<Optional<struct passwd>> getpwnam(StringView name)
{
::setpwent();
diff --git a/Userland/Libraries/LibCore/System.h b/Userland/Libraries/LibCore/System.h
index 8ea4b27693..d30457b495 100644
--- a/Userland/Libraries/LibCore/System.h
+++ b/Userland/Libraries/LibCore/System.h
@@ -66,6 +66,7 @@ ErrorOr<void> ioctl(int fd, unsigned request, ...);
ErrorOr<struct termios> tcgetattr(int fd);
ErrorOr<void> tcsetattr(int fd, int optional_actions, struct termios const&);
ErrorOr<void> chmod(StringView pathname, mode_t mode);
+ErrorOr<void> lchown(StringView pathname, uid_t uid, gid_t gid);
ErrorOr<void> chown(StringView pathname, uid_t uid, gid_t gid);
ErrorOr<Optional<struct passwd>> getpwnam(StringView name);
ErrorOr<Optional<struct group>> getgrnam(StringView name);