Skip to content

Commit

Permalink
Add APIs to get group details and to change ownership of file.
Browse files Browse the repository at this point in the history
  • Loading branch information
muthu90tech committed Sep 2, 2024
1 parent e42e382 commit da2ee2e
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/seastar/core/reactor.hh
Original file line number Diff line number Diff line change
Expand Up @@ -493,6 +493,8 @@ public:
future<> touch_directory(std::string_view name, file_permissions permissions = file_permissions::default_dir_permissions) noexcept;
future<std::optional<directory_entry_type>> file_type(std::string_view name, follow_symlink = follow_symlink::yes) noexcept;
future<stat_data> file_stat(std::string_view pathname, follow_symlink) noexcept;
future<> chown(std::string_view filepath, uid_t owner, gid_t group);
future<std::optional<struct group>> getgrnam(std::string_view name, char *buf, size_t buflen);
future<uint64_t> file_size(std::string_view pathname) noexcept;
future<bool> file_accessible(std::string_view pathname, access_flags flags) noexcept;
future<bool> file_exists(std::string_view pathname) noexcept {
Expand Down
17 changes: 17 additions & 0 deletions include/seastar/core/seastar.hh
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,23 @@ using follow_symlink = bool_class<follow_symlink_tag>;
/// with follow_symlink::yes, or for the link itself, with follow_symlink::no.
future<stat_data> file_stat(std::string_view name, follow_symlink fs = follow_symlink::yes) noexcept;

/// Wrapper around getgrnam_r.
/// If the provided group name does not exist in the group database, this call will return an empty optional.
/// If the provided group name exists in the group database, the optional returned will contain the struct group information.
/// When an unexpected error is thrown by the getgrnam_r libc call, this function throws std::system_error with std::error_code.
/// \param groupname name of the group
/// \param buf buffer to store the string fields pointed to by the members of group structure.
/// \param buflen size of the buffer
///
/// \return optional struct group of the group identified by name. struct group has details of the group from the group database.
future<std::optional<struct group>> getgrnam(std::string_view name, char *buf, size_t buflen);

/// Change the owner and group of file. This is a wrapper around chown syscall.
/// The function throws std::system_error, when the chown syscall fails.
/// \param filepath
/// \param owner
/// \param group
future<> chown(std::string_view filepath, uid_t owner, gid_t group);
/// Return the size of a file.
///
/// \param name name of the file to return the size
Expand Down
31 changes: 31 additions & 0 deletions src/core/reactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,14 @@ module;
#include <cassert>
#include <chrono>
#include <cmath>
#include <coroutine>
#include <exception>
#include <filesystem>
#include <fstream>
#include <regex>
#include <thread>

#include <grp.h>
#include <spawn.h>
#include <sys/syscall.h>
#include <sys/vfs.h>
Expand Down Expand Up @@ -2200,6 +2202,35 @@ void reactor::kill(pid_t pid, int sig) {
ret.throw_if_error();
}

future<std::optional<struct group>> reactor::getgrnam(std::string_view name, char *buf, size_t buflen) {
syscall_result_extra<std::optional<struct group>> sr = co_await _thread_pool->submit<syscall_result_extra<std::optional<struct group>>>(
[name = sstring(name), buf, buflen] {
struct group grp;
struct group *result;
memset(&grp, 0, sizeof(struct group));
errno = 0;
int ret = ::getgrnam_r(name.c_str(), &grp, buf, buflen, &result);
return wrap_syscall(ret, result ? std::optional<struct group>(*result) : std::nullopt);
});

if (sr.result != 0) {
throw std::system_error(sr.error_code());
}

co_return std::move(sr.extra);
}

future<> reactor::chown(std::string_view filepath, uid_t owner, gid_t group) {
syscall_result<int> sr = co_await _thread_pool->submit<syscall_result<int>>(
[filepath = sstring(filepath), owner, group] {
int ret = ::chown(filepath.c_str(), owner, group);
return wrap_syscall(ret);
});

sr.throw_if_error();
co_return;
}

future<stat_data>
reactor::file_stat(std::string_view pathname, follow_symlink follow) noexcept {
// Allocating memory for a sstring can throw, hence the futurize_invoke
Expand Down
4 changes: 4 additions & 0 deletions src/core/syscall_result.hh
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ struct syscall_result_extra : public syscall_result<int> {
Extra extra;
syscall_result_extra(int result, int error, Extra e) : syscall_result<int>{result, error}, extra{std::move(e)} {
}

std::error_code error_code() const {
return this->ec();
}
};

template <typename T>
Expand Down
1 change: 1 addition & 0 deletions src/seastar.cc
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ module;
#include <sys/un.h>
#include <execinfo.h>
#include <fcntl.h>
#include <grp.h>
#include <malloc.h>
#include <pthread.h>
#include <setjmp.h>
Expand Down
9 changes: 9 additions & 0 deletions src/util/file.cc
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ module;
#include <iostream>
#include <list>
#include <vector>
#include <grp.h>
#include <sys/statvfs.h>

#ifdef SEASTAR_MODULE
Expand Down Expand Up @@ -132,6 +133,14 @@ future<stat_data> file_stat(std::string_view name, follow_symlink follow) noexce
return engine().file_stat(name, follow);
}

future<std::optional<struct group>> getgrnam(std::string_view name, char *buf, size_t buflen) {
return engine().getgrnam(name, buf, buflen);
}

future<> chown(std::string_view filepath, uid_t owner, gid_t group) {
return engine().chown(filepath, owner, group);
}

future<uint64_t> file_size(std::string_view name) noexcept {
return engine().file_size(name);
}
Expand Down
3 changes: 3 additions & 0 deletions tests/unit/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -354,6 +354,9 @@ seastar_add_test (network_interface
seastar_add_test (json_formatter
SOURCES json_formatter_test.cc)

seastar_add_test (libc_wrapper
SOURCES libc_wrapper_test.cc)

seastar_add_test (locking
SOURCES locking_test.cc)

Expand Down
55 changes: 55 additions & 0 deletions tests/unit/libc_wrapper_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*
* This file is open source software, licensed to you under the terms
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
* distributed with this work for additional information regarding copyright
* ownership. You may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

/*
* Copyright (C) 2024 ScyllaDB.
*/
#include <coroutine>
#include <iostream>
#include <grp.h>

#include <seastar/core/coroutine.hh>
#include <seastar/core/reactor.hh>
#include <seastar/core/seastar.hh>

#include <seastar/testing/test_case.hh>

using namespace seastar;

SEASTAR_TEST_CASE(getgrnam_error_test) {
size_t buflen = 1;
char buf[1];
memset(&buf, 0, buflen);
BOOST_REQUIRE_THROW(co_await getgrnam("root", buf, buflen), std::system_error);
}

SEASTAR_TEST_CASE(getgrnam_group_name_does_not_exist_test) {
size_t buflen = 1024;
char buf[1024];
memset(&buf, 0, buflen);
std::optional<struct group> grp = co_await getgrnam("roo", buf, buflen);
BOOST_REQUIRE(!grp.has_value());
}

SEASTAR_TEST_CASE(getgrnam_group_name_exists_test) {
size_t buflen = 1024;
char buf[1024];
memset(&buf, 0, buflen);
std::optional<struct group> grp = co_await getgrnam("root", buf, buflen);
BOOST_REQUIRE(grp.has_value());
}

0 comments on commit da2ee2e

Please sign in to comment.