diff options
author | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:30 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2021-01-12 12:17:46 +0100 |
commit | 13d7c09125f8eec703d0a43a9a87fc8aa08f7319 (patch) | |
tree | 70fd643c429cea5c1f9362c2674511d17a53f3b5 /Libraries/LibCore | |
parent | dc28c07fa526841e05e16161c74a6c23984f1dd5 (diff) | |
download | serenity-13d7c09125f8eec703d0a43a9a87fc8aa08f7319.zip |
Libraries: Move to Userland/Libraries/
Diffstat (limited to 'Libraries/LibCore')
69 files changed, 0 insertions, 9063 deletions
diff --git a/Libraries/LibCore/Account.cpp b/Libraries/LibCore/Account.cpp deleted file mode 100644 index 7e4d40669a..0000000000 --- a/Libraries/LibCore/Account.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Base64.h> -#include <AK/Random.h> -#include <LibCore/Account.h> -#include <LibCore/File.h> -#include <grp.h> -#include <pwd.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> - -namespace Core { - -static String get_salt() -{ - char random_data[12]; - AK::fill_with_random(random_data, sizeof(random_data)); - - StringBuilder builder; - builder.append("$5$"); - builder.append(encode_base64(ReadonlyBytes(random_data, sizeof(random_data)))); - - return builder.build(); -} - -static Vector<gid_t> get_gids(const StringView& username) -{ - Vector<gid_t> extra_gids; - for (auto* group = getgrent(); group; group = getgrent()) { - for (size_t i = 0; group->gr_mem[i]; ++i) { - if (username == group->gr_mem[i]) { - extra_gids.append(group->gr_gid); - break; - } - } - } - endgrent(); - return extra_gids; -} - -Result<Account, String> Account::from_passwd(const passwd& pwd, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - RefPtr<Core::File> passwd_file; - if (open_passwd_file != Core::Account::OpenPasswdFile::No) { - auto open_mode = open_passwd_file == Core::Account::OpenPasswdFile::ReadOnly - ? Core::File::OpenMode::ReadOnly - : Core::File::OpenMode::ReadWrite; - auto file_or_error = Core::File::open("/etc/passwd", open_mode); - if (file_or_error.is_error()) - return file_or_error.error(); - passwd_file = file_or_error.value(); - } - - RefPtr<Core::File> shadow_file; - if (open_shadow_file != Core::Account::OpenShadowFile::No) { - auto open_mode = open_shadow_file == Core::Account::OpenShadowFile::ReadOnly - ? Core::File::OpenMode::ReadOnly - : Core::File::OpenMode::ReadWrite; - auto file_or_error = Core::File::open("/etc/shadow", open_mode); - if (file_or_error.is_error()) - return file_or_error.error(); - shadow_file = file_or_error.value(); - } - - Account account(pwd, get_gids(pwd.pw_name), move(passwd_file), move(shadow_file)); - endpwent(); - return account; -} - -Result<Account, String> Account::from_name(const char* username, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - struct passwd* pwd = nullptr; - errno = 0; - pwd = getpwnam(username); - if (!pwd) { - if (errno == 0) - return String("No such user"); - - return String(strerror(errno)); - } - return from_passwd(*pwd, open_passwd_file, open_shadow_file); -} - -Result<Account, String> Account::from_uid(uid_t uid, Core::Account::OpenPasswdFile open_passwd_file, Core::Account::OpenShadowFile open_shadow_file) -{ - struct passwd* pwd = nullptr; - errno = 0; - pwd = getpwuid(uid); - if (!pwd) { - if (errno == 0) - return String("No such user"); - - return String(strerror(errno)); - } - return from_passwd(*pwd, open_passwd_file, open_shadow_file); -} - -bool Account::authenticate(const char* password) const -{ - // An empty passwd field indicates that no password is required to log in. - if (m_password_hash.is_empty()) - return true; - - // FIXME: Use crypt_r if it can be built in lagom. - char* hash = crypt(password, m_password_hash.characters()); - return hash != nullptr && strcmp(hash, m_password_hash.characters()) == 0; -} - -bool Account::login() const -{ - if (setgroups(m_extra_gids.size(), m_extra_gids.data()) < 0) - return false; - - if (setgid(m_gid) < 0) - return false; - - if (setuid(m_uid) < 0) - return false; - - return true; -} - -void Account::set_password(const char* password) -{ - m_password_hash = crypt(password, get_salt().characters()); -} - -void Account::set_password_enabled(bool enabled) -{ - if (enabled && m_password_hash != "" && m_password_hash[0] == '!') { - m_password_hash = m_password_hash.substring(1, m_password_hash.length() - 1); - } else if (!enabled && (m_password_hash == "" || m_password_hash[0] != '!')) { - StringBuilder builder; - builder.append('!'); - builder.append(m_password_hash); - m_password_hash = builder.build(); - } -} - -void Account::delete_password() -{ - m_password_hash = ""; -} - -Account::Account(const passwd& pwd, Vector<gid_t> extra_gids, RefPtr<Core::File> passwd_file, RefPtr<Core::File> shadow_file) - : m_passwd_file(move(passwd_file)) - , m_shadow_file(move(shadow_file)) - , m_username(pwd.pw_name) - , m_uid(pwd.pw_uid) - , m_gid(pwd.pw_gid) - , m_gecos(pwd.pw_gecos) - , m_home_directory(pwd.pw_dir) - , m_shell(pwd.pw_shell) - , m_extra_gids(extra_gids) -{ - if (m_shadow_file) { - load_shadow_file(); - } -} - -String Account::generate_passwd_file() const -{ - StringBuilder builder; - - setpwent(); - - struct passwd* p; - errno = 0; - while ((p = getpwent())) { - if (p->pw_uid == m_uid) { - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - m_username, - m_uid, m_gid, - m_gecos, - m_home_directory, - m_shell); - - } else { - builder.appendff("{}:!:{}:{}:{}:{}:{}\n", - p->pw_name, p->pw_uid, - p->pw_gid, p->pw_gecos, p->pw_dir, - p->pw_shell); - } - } - endpwent(); - - if (errno) { - dbgln("errno was non-zero after generating new passwd file."); - return {}; - } - - return builder.to_string(); -} - -void Account::load_shadow_file() -{ - ASSERT(m_shadow_file); - ASSERT(m_shadow_file->is_open()); - - if (!m_shadow_file->seek(0)) { - ASSERT_NOT_REACHED(); - } - - Vector<ShadowEntry> entries; - - for (;;) { - auto line = m_shadow_file->read_line(); - if (line.is_null()) - break; - auto parts = line.split(':'); - if (parts.size() != 2) { - dbgln("Malformed shadow entry, ignoring."); - continue; - } - const auto& username = parts[0]; - const auto& password_hash = parts[1]; - entries.append({ username, password_hash }); - - if (username == m_username) { - m_password_hash = password_hash; - } - } - - m_shadow_entries = move(entries); -} - -String Account::generate_shadow_file() const -{ - StringBuilder builder; - bool updated_entry_in_place = false; - for (auto& entry : m_shadow_entries) { - if (entry.username == m_username) { - updated_entry_in_place = true; - builder.appendff("{}:{}\n", m_username, m_password_hash); - } else { - builder.appendff("{}:{}\n", entry.username, entry.password_hash); - } - } - if (!updated_entry_in_place) - builder.appendff("{}:{}\n", m_username, m_password_hash); - return builder.to_string(); -} - -bool Account::sync() -{ - ASSERT(m_passwd_file); - ASSERT(m_passwd_file->mode() == Core::File::OpenMode::ReadWrite); - ASSERT(m_shadow_file); - ASSERT(m_shadow_file->mode() == Core::File::OpenMode::ReadWrite); - - // FIXME: Maybe reorganize this to create temporary files and finish it completely before renaming them to /etc/{passwd,shadow} - // If truncation succeeds but write fails, we'll have an empty file :( - - auto new_passwd_file = generate_passwd_file(); - auto new_shadow_file = generate_shadow_file(); - - if (new_passwd_file.is_null() || new_shadow_file.is_null()) { - ASSERT_NOT_REACHED(); - } - - if (!m_passwd_file->seek(0) || !m_shadow_file->seek(0)) { - ASSERT_NOT_REACHED(); - } - - if (!m_passwd_file->truncate(0)) { - dbgln("Truncating passwd file failed."); - return false; - } - - if (!m_passwd_file->write(new_passwd_file)) { - // FIXME: Improve Core::File::write() error reporting. - dbgln("Writing to passwd file failed."); - return false; - } - - if (!m_shadow_file->truncate(0)) { - dbgln("Truncating shadow file failed."); - return false; - } - - if (!m_shadow_file->write(new_shadow_file)) { - // FIXME: Improve Core::File::write() error reporting. - dbgln("Writing to shadow file failed."); - return false; - } - - return true; - // FIXME: Sync extra groups. -} - -} diff --git a/Libraries/LibCore/Account.h b/Libraries/LibCore/Account.h deleted file mode 100644 index fdd7d9bea9..0000000000 --- a/Libraries/LibCore/Account.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Result.h> -#include <AK/String.h> -#include <AK/Types.h> -#include <AK/Vector.h> -#include <LibCore/File.h> -#include <pwd.h> -#include <sys/types.h> - -namespace Core { - -class Account { -public: - enum class OpenPasswdFile { - No, - ReadOnly, - ReadWrite, - }; - - enum class OpenShadowFile { - No, - ReadOnly, - ReadWrite, - }; - - static Result<Account, String> from_name(const char* username, OpenPasswdFile = OpenPasswdFile::No, OpenShadowFile = OpenShadowFile::No); - static Result<Account, String> from_uid(uid_t uid, OpenPasswdFile = OpenPasswdFile::No, OpenShadowFile = OpenShadowFile::No); - - bool authenticate(const char* password) const; - bool login() const; - - String username() const { return m_username; } - String password_hash() const { return m_password_hash; } - - // Setters only affect in-memory copy of password. - // You must call sync to apply changes. - void set_password(const char* password); - void set_password_enabled(bool enabled); - void delete_password(); - bool has_password() const { return !m_password_hash.is_empty(); } - - uid_t uid() const { return m_uid; } - gid_t gid() const { return m_gid; } - const String& gecos() const { return m_gecos; } - const String& home_directory() const { return m_home_directory; } - const String& shell() const { return m_shell; } - const Vector<gid_t>& extra_gids() const { return m_extra_gids; } - - bool sync(); - -private: - static Result<Account, String> from_passwd(const passwd&, OpenPasswdFile, OpenShadowFile); - - Account(const passwd& pwd, Vector<gid_t> extra_gids, RefPtr<Core::File> passwd_file, RefPtr<Core::File> shadow_file); - void load_shadow_file(); - - String generate_passwd_file() const; - String generate_shadow_file() const; - - RefPtr<Core::File> m_passwd_file; - RefPtr<Core::File> m_shadow_file; - - String m_username; - - // Contents of passwd field in passwd entry. - // Can be empty, "x", or contain a leading '!' - String m_password_hash; - uid_t m_uid { 0 }; - gid_t m_gid { 0 }; - String m_gecos; - String m_home_directory; - String m_shell; - Vector<gid_t> m_extra_gids; - - struct ShadowEntry { - String username; - String password_hash; - }; - Vector<ShadowEntry> m_shadow_entries; -}; - -} diff --git a/Libraries/LibCore/ArgsParser.cpp b/Libraries/LibCore/ArgsParser.cpp deleted file mode 100644 index 121272e38b..0000000000 --- a/Libraries/LibCore/ArgsParser.cpp +++ /dev/null @@ -1,392 +0,0 @@ -/* - * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Format.h> -#include <AK/StringBuilder.h> -#include <LibCore/ArgsParser.h> -#include <getopt.h> -#include <limits.h> -#include <stdio.h> -#include <string.h> - -static constexpr bool isnan(double __x) { return __builtin_isnan(__x); } - -static Optional<double> convert_to_double(const char* s) -{ - char* p; - double v = strtod(s, &p); - if (isnan(v) || p == s) - return {}; - return v; -} - -namespace Core { - -ArgsParser::ArgsParser() -{ - add_option(m_show_help, "Display this message", "help", 0); -} - -bool ArgsParser::parse(int argc, char** argv, bool exit_on_failure) -{ - auto print_usage_and_exit = [this, argv, exit_on_failure] { - print_usage(stderr, argv[0]); - if (exit_on_failure) - exit(1); - }; - - Vector<option> long_options; - StringBuilder short_options_builder; - - int index_of_found_long_option = -1; - - // Tell getopt() to reset its internal state, and start scanning from optind = 1. - // We could also set optreset = 1, but the host platform may not support that. - optind = 0; - - for (size_t i = 0; i < m_options.size(); i++) { - auto& opt = m_options[i]; - if (opt.long_name) { - option long_opt { - opt.long_name, - opt.requires_argument ? required_argument : no_argument, - &index_of_found_long_option, - static_cast<int>(i) - }; - long_options.append(long_opt); - } - if (opt.short_name) { - short_options_builder.append(opt.short_name); - if (opt.requires_argument) - short_options_builder.append(':'); - } - } - long_options.append({ 0, 0, 0, 0 }); - - String short_options = short_options_builder.build(); - - while (true) { - int c = getopt_long(argc, argv, short_options.characters(), long_options.data(), nullptr); - if (c == -1) { - // We have reached the end. - break; - } else if (c == '?') { - // There was an error, and getopt() has already - // printed its error message. - print_usage_and_exit(); - return false; - } - - // Let's see what option we just found. - Option* found_option = nullptr; - if (c == 0) { - // It was a long option. - ASSERT(index_of_found_long_option >= 0); - found_option = &m_options[index_of_found_long_option]; - index_of_found_long_option = -1; - } else { - // It was a short option, look it up. - auto it = m_options.find_if([c](auto& opt) { return c == opt.short_name; }); - ASSERT(!it.is_end()); - found_option = &*it; - } - ASSERT(found_option); - - const char* arg = found_option->requires_argument ? optarg : nullptr; - if (!found_option->accept_value(arg)) { - warnln("\033[31mInvalid value for option \033[1m{}\033[22m, dude\033[0m", found_option->name_for_display()); - print_usage_and_exit(); - return false; - } - } - - // We're done processing options, now let's parse positional arguments. - - int values_left = argc - optind; - int num_values_for_arg[m_positional_args.size()]; - int total_values_required = 0; - for (size_t i = 0; i < m_positional_args.size(); i++) { - auto& arg = m_positional_args[i]; - num_values_for_arg[i] = arg.min_values; - total_values_required += arg.min_values; - } - - if (total_values_required > values_left) { - print_usage_and_exit(); - return false; - } - int extra_values_to_distribute = values_left - total_values_required; - - for (size_t i = 0; i < m_positional_args.size(); i++) { - auto& arg = m_positional_args[i]; - int extra_values_to_this_arg = min(arg.max_values - arg.min_values, extra_values_to_distribute); - num_values_for_arg[i] += extra_values_to_this_arg; - extra_values_to_distribute -= extra_values_to_this_arg; - if (extra_values_to_distribute == 0) - break; - } - - if (extra_values_to_distribute > 0) { - // We still have too many values :( - print_usage_and_exit(); - return false; - } - - for (size_t i = 0; i < m_positional_args.size(); i++) { - auto& arg = m_positional_args[i]; - for (int j = 0; j < num_values_for_arg[i]; j++) { - const char* value = argv[optind++]; - if (!arg.accept_value(value)) { - warnln("Invalid value for argument {}", arg.name); - print_usage_and_exit(); - return false; - } - } - } - - // We're done parsing! :) - // Now let's show help if requested. - if (m_show_help) { - print_usage(stdout, argv[0]); - if (exit_on_failure) - exit(0); - return false; - } - - return true; -} - -void ArgsParser::print_usage(FILE* file, const char* argv0) -{ - out(file, "Usage:\n\t\033[1m{}\033[0m", argv0); - - for (auto& opt : m_options) { - if (opt.long_name && !strcmp(opt.long_name, "help")) - continue; - if (opt.requires_argument) - out(file, " [{} {}]", opt.name_for_display(), opt.value_name); - else - out(file, " [{}]", opt.name_for_display()); - } - for (auto& arg : m_positional_args) { - bool required = arg.min_values > 0; - bool repeated = arg.max_values > 1; - - if (required && repeated) - out(file, " <{}...>", arg.name); - else if (required && !repeated) - out(file, " <{}>", arg.name); - else if (!required && repeated) - out(file, " [{}...]", arg.name); - else if (!required && !repeated) - out(file, " [{}]", arg.name); - } - outln(file); - - if (m_general_help != nullptr && m_general_help[0] != '\0') { - outln(file, "\nDescription:"); - outln(file, m_general_help); - } - - if (!m_options.is_empty()) - outln(file, "\nOptions:"); - for (auto& opt : m_options) { - auto print_argument = [&]() { - if (opt.value_name) { - if (opt.requires_argument) - out(file, " {}", opt.value_name); - else - out(file, " [{}]", opt.value_name); - } - }; - out(file, "\t"); - if (opt.short_name) { - out(file, "\033[1m-{}\033[0m", opt.short_name); - print_argument(); - } - if (opt.short_name && opt.long_name) - out(file, ", "); - if (opt.long_name) { - out(file, "\033[1m--{}\033[0m", opt.long_name); - print_argument(); - } - - if (opt.help_string) - out(file, "\t{}", opt.help_string); - outln(file); - } - - if (!m_positional_args.is_empty()) - outln(file, "\nArguments:"); - - for (auto& arg : m_positional_args) { - out(file, "\t\033[1m{}\033[0m", arg.name); - if (arg.help_string) - out(file, "\t{}", arg.help_string); - outln(file); - } -} - -void ArgsParser::add_option(Option&& option) -{ - m_options.append(move(option)); -} - -void ArgsParser::add_option(bool& value, const char* help_string, const char* long_name, char short_name) -{ - Option option { - false, - help_string, - long_name, - short_name, - nullptr, - [&value](const char* s) { - ASSERT(s == nullptr); - value = true; - return true; - } - }; - add_option(move(option)); -} - -void ArgsParser::add_option(const char*& value, const char* help_string, const char* long_name, char short_name, const char* value_name) -{ - Option option { - true, - help_string, - long_name, - short_name, - value_name, - [&value](const char* s) { - value = s; - return true; - } - }; - add_option(move(option)); -} - -void ArgsParser::add_option(int& value, const char* help_string, const char* long_name, char short_name, const char* value_name) -{ - Option option { - true, - help_string, - long_name, - short_name, - value_name, - [&value](const char* s) { - auto opt = StringView(s).to_int(); - value = opt.value_or(0); - return opt.has_value(); - } - }; - add_option(move(option)); -} - -void ArgsParser::add_option(double& value, const char* help_string, const char* long_name, char short_name, const char* value_name) -{ - Option option { - true, - help_string, - long_name, - short_name, - value_name, - [&value](const char* s) { - auto opt = convert_to_double(s); - value = opt.value_or(0.0); - return opt.has_value(); - } - }; - add_option(move(option)); -} - -void ArgsParser::add_positional_argument(Arg&& arg) -{ - m_positional_args.append(move(arg)); -} - -void ArgsParser::add_positional_argument(const char*& value, const char* help_string, const char* name, Required required) -{ - Arg arg { - help_string, - name, - required == Required::Yes ? 1 : 0, - 1, - [&value](const char* s) { - value = s; - return true; - } - }; - add_positional_argument(move(arg)); -} - -void ArgsParser::add_positional_argument(int& value, const char* help_string, const char* name, Required required) -{ - Arg arg { - help_string, - name, - required == Required::Yes ? 1 : 0, - 1, - [&value](const char* s) { - auto opt = StringView(s).to_int(); - value = opt.value_or(0); - return opt.has_value(); - } - }; - add_positional_argument(move(arg)); -} - -void ArgsParser::add_positional_argument(double& value, const char* help_string, const char* name, Required required) -{ - Arg arg { - help_string, - name, - required == Required::Yes ? 1 : 0, - 1, - [&value](const char* s) { - auto opt = convert_to_double(s); - value = opt.value_or(0.0); - return opt.has_value(); - } - }; - add_positional_argument(move(arg)); -} - -void ArgsParser::add_positional_argument(Vector<const char*>& values, const char* help_string, const char* name, Required required) -{ - Arg arg { - help_string, - name, - required == Required::Yes ? 1 : 0, - INT_MAX, - [&values](const char* s) { - values.append(s); - return true; - } - }; - add_positional_argument(move(arg)); -} - -} diff --git a/Libraries/LibCore/ArgsParser.h b/Libraries/LibCore/ArgsParser.h deleted file mode 100644 index 2f7b923a9d..0000000000 --- a/Libraries/LibCore/ArgsParser.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2020, Sergey Bugaev <bugaevc@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/String.h> -#include <AK/Vector.h> -#include <stdio.h> - -namespace Core { - -class ArgsParser { -public: - ArgsParser(); - - enum class Required { - Yes, - No - }; - - struct Option { - bool requires_argument { true }; - const char* help_string { nullptr }; - const char* long_name { nullptr }; - char short_name { 0 }; - const char* value_name { nullptr }; - Function<bool(const char*)> accept_value; - - String name_for_display() const - { - if (long_name) - return String::format("--%s", long_name); - return String::format("-%c", short_name); - } - }; - - struct Arg { - const char* help_string { nullptr }; - const char* name { nullptr }; - int min_values { 0 }; - int max_values { 1 }; - Function<bool(const char*)> accept_value; - }; - - bool parse(int argc, char** argv, bool exit_on_failure = true); - // *Without* trailing newline! - void set_general_help(const char* help_string) { m_general_help = help_string; }; - void print_usage(FILE*, const char* argv0); - - void add_option(Option&&); - void add_option(bool& value, const char* help_string, const char* long_name, char short_name); - void add_option(const char*& value, const char* help_string, const char* long_name, char short_name, const char* value_name); - void add_option(int& value, const char* help_string, const char* long_name, char short_name, const char* value_name); - void add_option(double& value, const char* help_string, const char* long_name, char short_name, const char* value_name); - - void add_positional_argument(Arg&&); - void add_positional_argument(const char*& value, const char* help_string, const char* name, Required required = Required::Yes); - void add_positional_argument(int& value, const char* help_string, const char* name, Required required = Required::Yes); - void add_positional_argument(double& value, const char* help_string, const char* name, Required required = Required::Yes); - void add_positional_argument(Vector<const char*>& value, const char* help_string, const char* name, Required required = Required::Yes); - -private: - Vector<Option> m_options; - Vector<Arg> m_positional_args; - - bool m_show_help { false }; - const char* m_general_help { nullptr }; -}; - -} diff --git a/Libraries/LibCore/CMakeLists.txt b/Libraries/LibCore/CMakeLists.txt deleted file mode 100644 index de16c64990..0000000000 --- a/Libraries/LibCore/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -set(SOURCES - Account.cpp - ArgsParser.cpp - ConfigFile.cpp - Command.cpp - DateTime.cpp - DirectoryWatcher.cpp - DirIterator.cpp - ElapsedTimer.cpp - Event.cpp - EventLoop.cpp - File.cpp - GetPassword.cpp - Gzip.cpp - IODevice.cpp - LocalServer.cpp - LocalSocket.cpp - MimeData.cpp - NetworkJob.cpp - NetworkResponse.cpp - Notifier.cpp - Object.cpp - ProcessStatisticsReader.cpp - Property.cpp - puff.cpp - SocketAddress.cpp - Socket.cpp - StandardPaths.cpp - TCPServer.cpp - TCPSocket.cpp - Timer.cpp - UDPServer.cpp - UDPSocket.cpp -) - -serenity_lib(LibCore core) -target_link_libraries(LibCore LibC LibCrypt) diff --git a/Libraries/LibCore/Command.cpp b/Libraries/LibCore/Command.cpp deleted file mode 100644 index e4fb717473..0000000000 --- a/Libraries/LibCore/Command.cpp +++ /dev/null @@ -1,127 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "Command.h" -#include <AK/ByteBuffer.h> -#include <AK/LogStream.h> -#include <AK/ScopeGuard.h> -#include <LibCore/File.h> -#include <fcntl.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/wait.h> -#include <unistd.h> - -// #define DBG_FAILED_COMMANDS - -namespace Core { - -// Only supported in serenity mode because we use `posix_spawn_file_actions_addchdir` -#ifdef __serenity__ - -String command(const String& command_string, Optional<LexicalPath> chdir) -{ - auto parts = command_string.split(' '); - if (parts.is_empty()) - return {}; - auto program = parts[0]; - parts.remove(0); - return command(program, parts, chdir); -} - -String command(const String& program, const Vector<String>& arguments, Optional<LexicalPath> chdir) -{ - int stdout_pipe[2] = {}; - int stderr_pipe[2] = {}; - if (pipe2(stdout_pipe, O_CLOEXEC)) { - perror("pipe2"); - ASSERT_NOT_REACHED(); - } - if (pipe2(stderr_pipe, O_CLOEXEC)) { - perror("pipe2"); - ASSERT_NOT_REACHED(); - } - - auto close_pipes = ScopeGuard([stderr_pipe, stdout_pipe] { - // The write-ends of these pipes are closed manually - close(stdout_pipe[0]); - close(stderr_pipe[0]); - }); - - Vector<const char*> parts = { program.characters() }; - for (const auto& part : arguments) { - parts.append(part.characters()); - } - parts.append(nullptr); - - const char** argv = parts.data(); - - posix_spawn_file_actions_t action; - posix_spawn_file_actions_init(&action); - if (chdir.has_value()) { - posix_spawn_file_actions_addchdir(&action, chdir.value().string().characters()); - } - posix_spawn_file_actions_adddup2(&action, stdout_pipe[1], STDOUT_FILENO); - posix_spawn_file_actions_adddup2(&action, stderr_pipe[1], STDERR_FILENO); - - pid_t pid; - if ((errno = posix_spawnp(&pid, program.characters(), &action, nullptr, const_cast<char**>(argv), environ))) { - perror("posix_spawn"); - ASSERT_NOT_REACHED(); - } - int wstatus; - waitpid(pid, &wstatus, 0); - posix_spawn_file_actions_destroy(&action); - - // close the write-ends so reading wouldn't block - close(stdout_pipe[1]); - close(stderr_pipe[1]); - - auto read_all_from_pipe = [](int pipe[2]) { - auto result_file = Core::File::construct(); - if (!result_file->open(pipe[0], Core::IODevice::ReadOnly, Core::File::ShouldCloseFileDescriptor::Yes)) { - perror("open"); - ASSERT_NOT_REACHED(); - } - return String::copy(result_file->read_all()); - }; - - if (WEXITSTATUS(wstatus) != 0) { -# ifdef DBG_FAILED_COMMANDS - dbgln("command failed. stderr: {}", read_all_from_pipe(stderr_pipe)); -# endif - return {}; - } - - auto result = read_all_from_pipe(stdout_pipe); - if (result.is_null()) - return ""; - return result; -} - -#endif - -} diff --git a/Libraries/LibCore/Command.h b/Libraries/LibCore/Command.h deleted file mode 100644 index 725c6b55a2..0000000000 --- a/Libraries/LibCore/Command.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/LexicalPath.h> -#include <AK/Optional.h> -#include <AK/String.h> -#include <spawn.h> - -namespace Core { - -// If the executed command fails, the returned String will be in the null state. -String command(const String& program, const Vector<String>& arguments, Optional<LexicalPath> chdir); -String command(const String& command_string, Optional<LexicalPath> chdir); - -} diff --git a/Libraries/LibCore/ConfigFile.cpp b/Libraries/LibCore/ConfigFile.cpp deleted file mode 100644 index cb7e68576c..0000000000 --- a/Libraries/LibCore/ConfigFile.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/ByteBuffer.h> -#include <AK/StringBuilder.h> -#include <LibCore/ConfigFile.h> -#include <LibCore/File.h> -#include <LibCore/StandardPaths.h> -#include <pwd.h> -#include <stdio.h> -#include <unistd.h> - -namespace Core { - -NonnullRefPtr<ConfigFile> ConfigFile::get_for_lib(const String& lib_name) -{ - String directory = StandardPaths::config_directory(); - auto path = String::formatted("{}/lib/{}.ini", directory, lib_name); - - return adopt(*new ConfigFile(path)); -} - -NonnullRefPtr<ConfigFile> ConfigFile::get_for_app(const String& app_name) -{ - String directory = StandardPaths::config_directory(); - auto path = String::formatted("{}/{}.ini", directory, app_name); - return adopt(*new ConfigFile(path)); -} - -NonnullRefPtr<ConfigFile> ConfigFile::get_for_system(const String& app_name) -{ - auto path = String::formatted("/etc/{}.ini", app_name); - return adopt(*new ConfigFile(path)); -} - -NonnullRefPtr<ConfigFile> ConfigFile::open(const String& path) -{ - return adopt(*new ConfigFile(path)); -} - -ConfigFile::ConfigFile(const String& file_name) - : m_file_name(file_name) -{ - reparse(); -} - -ConfigFile::~ConfigFile() -{ - sync(); -} - -void ConfigFile::reparse() -{ - m_groups.clear(); - - auto file = File::construct(m_file_name); - if (!file->open(IODevice::OpenMode::ReadOnly)) - return; - - HashMap<String, String>* current_group = nullptr; - - while (file->can_read_line()) { - auto line = file->read_line(); - auto* cp = line.characters(); - - while (*cp && (*cp == ' ' || *cp == '\t' || *cp == '\n')) - ++cp; - - switch (*cp) { - case '\0': // EOL... - case '#': // Comment, skip entire line. - case ';': // -||- - continue; - case '[': { // Start of new group. - StringBuilder builder; - ++cp; // Skip the '[' - while (*cp && (*cp != ']')) - builder.append(*(cp++)); - current_group = &m_groups.ensure(builder.to_string()); - break; - } - default: { // Start of key{ - StringBuilder key_builder; - StringBuilder value_builder; - while (*cp && (*cp != '=')) - key_builder.append(*(cp++)); - ++cp; // Skip the '=' - while (*cp && (*cp != '\n')) - value_builder.append(*(cp++)); - if (!current_group) { - // We're not in a group yet, create one with the name ""... - current_group = &m_groups.ensure(""); - } - current_group->set(key_builder.to_string(), value_builder.to_string()); - } - } - } -} - -String ConfigFile::read_entry(const String& group, const String& key, const String& default_value) const -{ - if (!has_key(group, key)) { - return default_value; - } - auto it = m_groups.find(group); - auto jt = it->value.find(key); - return jt->value; -} - -int ConfigFile::read_num_entry(const String& group, const String& key, int default_value) const -{ - if (!has_key(group, key)) { - return default_value; - } - - return read_entry(group, key).to_int().value_or(default_value); -} - -bool ConfigFile::read_bool_entry(const String& group, const String& key, bool default_value) const -{ - auto value = read_entry(group, key, default_value ? "1" : "0"); - if (value == "1" || value.to_lowercase() == "true") - return 1; - return 0; -} - -void ConfigFile::write_entry(const String& group, const String& key, const String& value) -{ - m_groups.ensure(group).ensure(key) = value; - m_dirty = true; -} - -void ConfigFile::write_num_entry(const String& group, const String& key, int value) -{ - write_entry(group, key, String::number(value)); -} -void ConfigFile::write_bool_entry(const String& group, const String& key, bool value) -{ - write_entry(group, key, value ? "1" : "0"); -} -void ConfigFile::write_color_entry(const String& group, const String& key, Color value) -{ - write_entry(group, key, String::formatted("{},{},{},{}", value.red(), value.green(), value.blue(), value.alpha())); -} - -bool ConfigFile::sync() -{ - if (!m_dirty) - return true; - - FILE* fp = fopen(m_file_name.characters(), "wb"); - if (!fp) - return false; - - for (auto& it : m_groups) { - outln(fp, "[{}]", it.key); - for (auto& jt : it.value) - outln(fp, "{}={}", jt.key, jt.value); - outln(fp); - } - - fclose(fp); - - m_dirty = false; - return true; -} - -void ConfigFile::dump() const -{ - for (auto& it : m_groups) { - outln("[{}]", it.key); - for (auto& jt : it.value) - outln("{}={}", jt.key, jt.value); - outln(); - } -} - -Vector<String> ConfigFile::groups() const -{ - return m_groups.keys(); -} - -Vector<String> ConfigFile::keys(const String& group) const -{ - auto it = m_groups.find(group); - if (it == m_groups.end()) - return {}; - return it->value.keys(); -} - -bool ConfigFile::has_key(const String& group, const String& key) const -{ - auto it = m_groups.find(group); - if (it == m_groups.end()) - return {}; - return it->value.contains(key); -} - -bool ConfigFile::has_group(const String& group) const -{ - return m_groups.contains(group); -} - -void ConfigFile::remove_group(const String& group) -{ - m_groups.remove(group); - m_dirty = true; -} - -void ConfigFile::remove_entry(const String& group, const String& key) -{ - auto it = m_groups.find(group); - if (it == m_groups.end()) - return; - it->value.remove(key); - m_dirty = true; -} - -} diff --git a/Libraries/LibCore/ConfigFile.h b/Libraries/LibCore/ConfigFile.h deleted file mode 100644 index 24865a0e48..0000000000 --- a/Libraries/LibCore/ConfigFile.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/HashMap.h> -#include <AK/RefCounted.h> -#include <AK/RefPtr.h> -#include <AK/String.h> -#include <AK/Vector.h> -#include <LibGfx/Color.h> - -namespace Core { - -class ConfigFile : public RefCounted<ConfigFile> { -public: - static NonnullRefPtr<ConfigFile> get_for_lib(const String& lib_name); - static NonnullRefPtr<ConfigFile> get_for_app(const String& app_name); - static NonnullRefPtr<ConfigFile> get_for_system(const String& app_name); - static NonnullRefPtr<ConfigFile> open(const String& path); - ~ConfigFile(); - - bool has_group(const String&) const; - bool has_key(const String& group, const String& key) const; - - Vector<String> groups() const; - Vector<String> keys(const String& group) const; - - String read_entry(const String& group, const String& key, const String& default_value = String()) const; - int read_num_entry(const String& group, const String& key, int default_value = 0) const; - bool read_bool_entry(const String& group, const String& key, bool default_value = false) const; - - void write_entry(const String& group, const String& key, const String& value); - void write_num_entry(const String& group, const String& key, int value); - void write_bool_entry(const String& group, const String& key, bool value); - void write_color_entry(const String& group, const String& key, Color value); - - void dump() const; - - bool is_dirty() const { return m_dirty; } - - bool sync(); - - void remove_group(const String& group); - void remove_entry(const String& group, const String& key); - - String file_name() const { return m_file_name; } - -private: - explicit ConfigFile(const String& file_name); - - void reparse(); - - String m_file_name; - HashMap<String, HashMap<String, String>> m_groups; - bool m_dirty { false }; -}; - -} diff --git a/Libraries/LibCore/DateTime.cpp b/Libraries/LibCore/DateTime.cpp deleted file mode 100644 index 804abac3de..0000000000 --- a/Libraries/LibCore/DateTime.cpp +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/StringBuilder.h> -#include <AK/Time.h> -#include <LibCore/DateTime.h> -#include <sys/time.h> -#include <time.h> - -namespace Core { - -DateTime DateTime::now() -{ - return from_timestamp(time(nullptr)); -} - -DateTime DateTime::create(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned minute, unsigned second) -{ - DateTime dt; - dt.set_time(year, month, day, hour, minute, second); - return dt; -} - -DateTime DateTime::from_timestamp(time_t timestamp) -{ - struct tm tm; - localtime_r(×tamp, &tm); - DateTime dt; - dt.m_year = tm.tm_year + 1900; - dt.m_month = tm.tm_mon + 1; - dt.m_day = tm.tm_mday; - dt.m_hour = tm.tm_hour; - dt.m_minute = tm.tm_min; - dt.m_second = tm.tm_sec; - dt.m_timestamp = timestamp; - return dt; -} - -unsigned DateTime::weekday() const -{ - return ::day_of_week(m_year, m_month, m_day); -} - -unsigned DateTime::days_in_month() const -{ - return ::days_in_month(m_year, m_month); -} - -unsigned DateTime::day_of_year() const -{ - return ::day_of_year(m_year, m_month, m_day); -} - -bool DateTime::is_leap_year() const -{ - return ::is_leap_year(m_year); -} - -void DateTime::set_time(unsigned year, unsigned month, unsigned day, unsigned hour, unsigned minute, unsigned second) -{ - struct tm tm = {}; - tm.tm_sec = (int)second; - tm.tm_min = (int)minute; - tm.tm_hour = (int)hour; - tm.tm_mday = (int)day; - tm.tm_mon = (int)month - 1; - tm.tm_year = (int)year - 1900; - tm.tm_isdst = -1; - // mktime() doesn't read tm.tm_wday and tm.tm_yday, no need to fill them in. - - m_timestamp = mktime(&tm); - - // mktime() normalizes the components to the right ranges (Jan 32 -> Feb 1 etc), so read fields back out from tm. - m_year = tm.tm_year + 1900; - m_month = tm.tm_mon + 1; - m_day = tm.tm_mday; - m_hour = tm.tm_hour; - m_minute = tm.tm_min; - m_second = tm.tm_sec; -} - -String DateTime::to_string(const String& format) const -{ - - const char wday_short_names[7][4] = { - "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" - }; - const char wday_long_names[7][10] = { - "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" - }; - const char mon_short_names[12][4] = { - "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" - }; - const char mon_long_names[12][10] = { - "January", "February", "March", "April", "May", "June", - "July", "August", "September", "October", "November", "December" - }; - - struct tm tm; - localtime_r(&m_timestamp, &tm); - StringBuilder builder; - const int format_len = format.length(); - - for (int i = 0; i < format_len; ++i) { - if (format[i] != '%') { - builder.append(format[i]); - } else { - if (++i == format_len) - return String(); - - switch (format[i]) { - case 'a': - builder.append(wday_short_names[tm.tm_wday]); - break; - case 'A': - builder.append(wday_long_names[tm.tm_wday]); - break; - case 'b': - builder.append(mon_short_names[tm.tm_mon]); - break; - case 'B': - builder.append(mon_long_names[tm.tm_mon]); - break; - case 'C': - builder.appendf("%02d", (tm.tm_year + 1900) / 100); - break; - case 'd': - builder.appendf("%02d", tm.tm_mday); - break; - case 'D': - builder.appendf("%02d/%02d/%02d", tm.tm_mon + 1, tm.tm_mday, (tm.tm_year + 1900) % 100); - break; - case 'e': - builder.appendf("%2d", tm.tm_mday); - break; - case 'h': - builder.append(mon_short_names[tm.tm_mon]); - break; - case 'H': - builder.appendf("%02d", tm.tm_hour); - break; - case 'I': - builder.appendf("%02d", tm.tm_hour % 12); - break; - case 'j': - builder.appendf("%03d", tm.tm_yday + 1); - break; - case 'm': - builder.appendf("%02d", tm.tm_mon + 1); - break; - case 'M': - builder.appendf("%02d", tm.tm_min); - break; - case 'n': - builder.append('\n'); - break; - case 'p': - builder.append(tm.tm_hour < 12 ? "a.m." : "p.m."); - break; - case 'r': - builder.appendf("%02d:%02d:%02d %s", tm.tm_hour % 12, tm.tm_min, tm.tm_sec, tm.tm_hour < 12 ? "a.m." : "p.m."); - break; - case 'R': - builder.appendf("%02d:%02d", tm.tm_hour, tm.tm_min); - break; - case 'S': - builder.appendf("%02d", tm.tm_sec); - break; - case 't': - builder.append('\t'); - break; - case 'T': - builder.appendf("%02d:%02d:%02d", tm.tm_hour, tm.tm_min, tm.tm_sec); - break; - case 'u': - builder.appendf("%d", tm.tm_wday ? tm.tm_wday : 7); - break; - case 'U': { - const int wday_of_year_beginning = (tm.tm_wday + 6 * tm.tm_yday) % 7; - const int week_number = (tm.tm_yday + wday_of_year_beginning) / 7; - builder.appendf("%02d", week_number); - break; - } - case 'V': { - const int wday_of_year_beginning = (tm.tm_wday + 6 + 6 * tm.tm_yday) % 7; - int week_number = (tm.tm_yday + wday_of_year_beginning) / 7 + 1; - if (wday_of_year_beginning > 3) { - if (tm.tm_yday >= 7 - wday_of_year_beginning) - --week_number; - else { - const int days_of_last_year = days_in_year(tm.tm_year + 1900 - 1); - const int wday_of_last_year_beginning = (wday_of_year_beginning + 6 * days_of_last_year) % 7; - week_number = (days_of_last_year + wday_of_last_year_beginning) / 7 + 1; - if (wday_of_last_year_beginning > 3) - --week_number; - } - } - builder.appendf("%02d", week_number); - break; - } - case 'w': - builder.appendf("%d", tm.tm_wday); - break; - case 'W': { - const int wday_of_year_beginning = (tm.tm_wday + 6 + 6 * tm.tm_yday) % 7; - const int week_number = (tm.tm_yday + wday_of_year_beginning) / 7; - builder.appendf("%02d", week_number); - break; - } - case 'y': - builder.appendf("%02d", (tm.tm_year + 1900) % 100); - break; - case 'Y': - builder.appendf("%d", tm.tm_year + 1900); - break; - case '%': - builder.append('%'); - break; - default: - return String(); - } - } - } - - return builder.build(); -} - -bool DateTime::is_before(const String& other) const -{ - auto now_string = String::formatted("{:04}{:02}{:02}{:02}{:02}{:02}Z", year(), month(), weekday(), hour(), minute(), second()); - return __builtin_strcasecmp(now_string.characters(), other.characters()) < 0; -} - -const LogStream& operator<<(const LogStream& stream, const DateTime& value) -{ - return stream << value.to_string(); -} - -} diff --git a/Libraries/LibCore/DateTime.h b/Libraries/LibCore/DateTime.h deleted file mode 100644 index 15515cc0fd..0000000000 --- a/Libraries/LibCore/DateTime.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/String.h> -#include <time.h> - -namespace Core { - -// Represents a time in local time. -class DateTime { -public: - time_t timestamp() const { return m_timestamp; } - - unsigned year() const { return m_year; } - unsigned month() const { return m_month; } - unsigned day() const { return m_day; } - - unsigned hour() const { return m_hour; } - unsigned minute() const { return m_minute; } - unsigned second() const { return m_second; } - unsigned weekday() const; - unsigned days_in_month() const; - unsigned day_of_year() const; - bool is_leap_year() const; - - void set_time(unsigned year, unsigned month = 1, unsigned day = 0, unsigned hour = 0, unsigned minute = 0, unsigned second = 0); - String to_string(const String& format = "%Y-%m-%d %H:%M:%S") const; - - static DateTime create(unsigned year, unsigned month = 1, unsigned day = 0, unsigned hour = 0, unsigned minute = 0, unsigned second = 0); - static DateTime now(); - static DateTime from_timestamp(time_t); - - // FIXME: This should be replaced with a proper comparison - // operator when we get the equivalent of strptime - bool is_before(const String&) const; - -private: - time_t m_timestamp { 0 }; - unsigned m_year { 0 }; - unsigned m_month { 0 }; - unsigned m_day { 0 }; - unsigned m_hour { 0 }; - unsigned m_minute { 0 }; - unsigned m_second { 0 }; -}; - -const LogStream& operator<<(const LogStream&, const DateTime&); - -} diff --git a/Libraries/LibCore/DirIterator.cpp b/Libraries/LibCore/DirIterator.cpp deleted file mode 100644 index 3dbeecf24f..0000000000 --- a/Libraries/LibCore/DirIterator.cpp +++ /dev/null @@ -1,121 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Vector.h> -#include <LibCore/DirIterator.h> -#include <errno.h> - -namespace Core { - -DirIterator::DirIterator(const StringView& path, Flags flags) - : m_path(path) - , m_flags(flags) -{ - m_dir = opendir(path.to_string().characters()); - if (!m_dir) { - m_error = errno; - } -} - -DirIterator::~DirIterator() -{ - if (m_dir) { - closedir(m_dir); - m_dir = nullptr; - } -} - -bool DirIterator::advance_next() -{ - if (!m_dir) - return false; - - while (true) { - errno = 0; - auto* de = readdir(m_dir); - if (!de) { - m_error = errno; - m_next = String(); - return false; - } - - m_next = de->d_name; - if (m_next.is_null()) - return false; - - if (m_flags & Flags::SkipDots && m_next.starts_with('.')) - continue; - - if (m_flags & Flags::SkipParentAndBaseDir && (m_next == "." || m_next == "..")) - continue; - - return !m_next.is_empty(); - } -} - -bool DirIterator::has_next() -{ - if (!m_next.is_null()) - return true; - - return advance_next(); -} - -String DirIterator::next_path() -{ - if (m_next.is_null()) - advance_next(); - - auto tmp = m_next; - m_next = String(); - return tmp; -} - -String DirIterator::next_full_path() -{ - return String::formatted("{}/{}", m_path, next_path()); -} - -String find_executable_in_path(String filename) -{ - if (filename.starts_with('/')) { - if (access(filename.characters(), X_OK) == 0) - return filename; - - return {}; - } - - for (auto directory : String { getenv("PATH") }.split(':')) { - auto fullpath = String::formatted("{}/{}", directory, filename); - - if (access(fullpath.characters(), X_OK) == 0) - return fullpath; - } - - return {}; -} - -} diff --git a/Libraries/LibCore/DirIterator.h b/Libraries/LibCore/DirIterator.h deleted file mode 100644 index 7f423b4f17..0000000000 --- a/Libraries/LibCore/DirIterator.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/String.h> -#include <dirent.h> -#include <string.h> - -namespace Core { - -class DirIterator { -public: - enum Flags { - NoFlags = 0x0, - SkipDots = 0x1, - SkipParentAndBaseDir = 0x2, - }; - - DirIterator(const StringView& path, Flags = Flags::NoFlags); - ~DirIterator(); - - bool has_error() const { return m_error != 0; } - int error() const { return m_error; } - const char* error_string() const { return strerror(m_error); } - bool has_next(); - String next_path(); - String next_full_path(); - -private: - DIR* m_dir = nullptr; - int m_error = 0; - String m_next; - String m_path; - int m_flags; - - bool advance_next(); -}; - -String find_executable_in_path(String filename); - -} diff --git a/Libraries/LibCore/DirectoryWatcher.cpp b/Libraries/LibCore/DirectoryWatcher.cpp deleted file mode 100644 index a363c2461d..0000000000 --- a/Libraries/LibCore/DirectoryWatcher.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "DirectoryWatcher.h" -#include <AK/LexicalPath.h> -#include <AK/Optional.h> -#include <LibCore/DirIterator.h> -#include <fcntl.h> -#include <sys/stat.h> - -namespace Core { - -// Only supported in serenity mode because we use `watch_file` -#ifdef __serenity__ - -DirectoryWatcher::DirectoryWatcher(const String& path) - : m_path(path) -{ - m_watcher_fd = watch_file(path.characters(), path.length()); - ASSERT(m_watcher_fd != -1); -} - -DirectoryWatcher::~DirectoryWatcher() -{ - close(m_watcher_fd); -} - -Optional<DirectoryWatcher::Event> DirectoryWatcher::wait_for_event() -{ - InodeWatcherEvent event {}; - int rc = read(m_watcher_fd, &event, sizeof(event)); - if (rc <= 0) - return {}; - - Event result; - if (event.type == InodeWatcherEvent::Type::ChildAdded) - result.type = Event::Type::ChildAdded; - else if (event.type == InodeWatcherEvent::Type::ChildRemoved) - result.type = Event::Type::ChildRemoved; - else - return {}; - - auto child_path = get_child_with_inode_index(event.inode_index); - if (!LexicalPath(child_path).is_valid()) - return {}; - - result.child_path = child_path; - return result; -} - -String DirectoryWatcher::get_child_with_inode_index(unsigned child_inode_index) const -{ - DirIterator iterator(m_path, Core::DirIterator::SkipDots); - if (iterator.has_error()) { - return {}; - } - - while (iterator.has_next()) { - auto child_full_path = String::formatted("{}/{}", m_path, iterator.next_path()); - struct stat st; - - if (lstat(child_full_path.characters(), &st)) { - return {}; - } - - if (st.st_ino == child_inode_index) { - return child_full_path; - } - } - return {}; -} - -#endif - -} diff --git a/Libraries/LibCore/DirectoryWatcher.h b/Libraries/LibCore/DirectoryWatcher.h deleted file mode 100644 index 63be2c1aa7..0000000000 --- a/Libraries/LibCore/DirectoryWatcher.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/Noncopyable.h> -#include <AK/String.h> -#include <Kernel/API/InodeWatcherEvent.h> - -namespace Core { - -class DirectoryWatcher { - AK_MAKE_NONCOPYABLE(DirectoryWatcher); - -public: - explicit DirectoryWatcher(const String& path); - ~DirectoryWatcher(); - - struct Event { - enum class Type { - ChildAdded, - ChildRemoved, - }; - Type type; - String child_path; - }; - - Optional<Event> wait_for_event(); - -private: - String get_child_with_inode_index(unsigned) const; - - String m_path; - int m_watcher_fd { -1 }; -}; - -} diff --git a/Libraries/LibCore/ElapsedTimer.cpp b/Libraries/LibCore/ElapsedTimer.cpp deleted file mode 100644 index 9d0fc95378..0000000000 --- a/Libraries/LibCore/ElapsedTimer.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Assertions.h> -#include <AK/Time.h> -#include <LibCore/ElapsedTimer.h> -#include <sys/time.h> -#include <time.h> - -namespace Core { - -void ElapsedTimer::start() -{ - m_valid = true; - timespec now_spec; - clock_gettime(m_precise ? CLOCK_MONOTONIC : CLOCK_MONOTONIC_COARSE, &now_spec); - m_origin_time.tv_sec = now_spec.tv_sec; - m_origin_time.tv_usec = now_spec.tv_nsec / 1000; -} - -int ElapsedTimer::elapsed() const -{ - ASSERT(is_valid()); - struct timeval now; - timespec now_spec; - clock_gettime(m_precise ? CLOCK_MONOTONIC : CLOCK_MONOTONIC_COARSE, &now_spec); - now.tv_sec = now_spec.tv_sec; - now.tv_usec = now_spec.tv_nsec / 1000; - struct timeval diff; - timeval_sub(now, m_origin_time, diff); - return diff.tv_sec * 1000 + diff.tv_usec / 1000; -} - -} diff --git a/Libraries/LibCore/ElapsedTimer.h b/Libraries/LibCore/ElapsedTimer.h deleted file mode 100644 index 224eb139e3..0000000000 --- a/Libraries/LibCore/ElapsedTimer.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <sys/time.h> - -namespace Core { - -class ElapsedTimer { -public: - ElapsedTimer(bool precise = false) - : m_precise(precise) - { - } - - bool is_valid() const { return m_valid; } - void start(); - int elapsed() const; - - const struct timeval& origin_time() const { return m_origin_time; } - -private: - bool m_precise { false }; - bool m_valid { false }; - struct timeval m_origin_time { - 0, 0 - }; -}; - -} diff --git a/Libraries/LibCore/Event.cpp b/Libraries/LibCore/Event.cpp deleted file mode 100644 index fac44e5537..0000000000 --- a/Libraries/LibCore/Event.cpp +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/WeakPtr.h> -#include <LibCore/Event.h> -#include <LibCore/Object.h> - -namespace Core { - -ChildEvent::ChildEvent(Type type, Object& child, Object* insertion_before_child) - : Core::Event(type) - , m_child(child.make_weak_ptr()) - , m_insertion_before_child(AK::try_make_weak_ptr(insertion_before_child)) -{ -} - -ChildEvent::~ChildEvent() -{ -} - -Object* ChildEvent::child() -{ - if (auto ref = m_child.strong_ref()) - return ref.ptr(); - return nullptr; -} - -const Object* ChildEvent::child() const -{ - if (auto ref = m_child.strong_ref()) - return ref.ptr(); - return nullptr; -} - -Object* ChildEvent::insertion_before_child() -{ - if (auto ref = m_insertion_before_child.strong_ref()) - return ref.ptr(); - return nullptr; -} - -const Object* ChildEvent::insertion_before_child() const -{ - if (auto ref = m_insertion_before_child.strong_ref()) - return ref.ptr(); - return nullptr; -} - -} diff --git a/Libraries/LibCore/Event.h b/Libraries/LibCore/Event.h deleted file mode 100644 index 46dc3dc375..0000000000 --- a/Libraries/LibCore/Event.h +++ /dev/null @@ -1,159 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/String.h> -#include <AK/Types.h> -#include <AK/WeakPtr.h> -#include <LibCore/Forward.h> - -namespace Core { - -class Event { -public: - enum Type { - Invalid = 0, - Quit, - Timer, - NotifierRead, - NotifierWrite, - DeferredInvoke, - ChildAdded, - ChildRemoved, - Custom, - }; - - Event() { } - explicit Event(unsigned type) - : m_type(type) - { - } - virtual ~Event() { } - - unsigned type() const { return m_type; } - - bool is_accepted() const { return m_accepted; } - void accept() { m_accepted = true; } - void ignore() { m_accepted = false; } - -private: - unsigned m_type { Type::Invalid }; - bool m_accepted { true }; -}; - -class DeferredInvocationEvent : public Event { - friend class EventLoop; - -public: - DeferredInvocationEvent(Function<void(Object&)> invokee) - : Event(Event::Type::DeferredInvoke) - , m_invokee(move(invokee)) - { - } - -private: - Function<void(Object&)> m_invokee; -}; - -class TimerEvent final : public Event { -public: - explicit TimerEvent(int timer_id) - : Event(Event::Timer) - , m_timer_id(timer_id) - { - } - ~TimerEvent() { } - - int timer_id() const { return m_timer_id; } - -private: - int m_timer_id; -}; - -class NotifierReadEvent final : public Event { -public: - explicit NotifierReadEvent(int fd) - : Event(Event::NotifierRead) - , m_fd(fd) - { - } - ~NotifierReadEvent() { } - - int fd() const { return m_fd; } - -private: - int m_fd; -}; - -class NotifierWriteEvent final : public Event { -public: - explicit NotifierWriteEvent(int fd) - : Event(Event::NotifierWrite) - , m_fd(fd) - { - } - ~NotifierWriteEvent() { } - - int fd() const { return m_fd; } - -private: - int m_fd; -}; - -class ChildEvent final : public Event { -public: - ChildEvent(Type, Object& child, Object* insertion_before_child = nullptr); - ~ChildEvent(); - - Object* child(); - const Object* child() const; - - Object* insertion_before_child(); - const Object* insertion_before_child() const; - -private: - WeakPtr<Object> m_child; - WeakPtr<Object> m_insertion_before_child; -}; - -class CustomEvent : public Event { -public: - CustomEvent(int custom_type) - : Event(Event::Type::Custom) - , m_custom_type(custom_type) - { - } - ~CustomEvent() { } - - int custom_type() const { return m_custom_type; } - -private: - int m_custom_type { 0 }; -}; - -} diff --git a/Libraries/LibCore/EventLoop.cpp b/Libraries/LibCore/EventLoop.cpp deleted file mode 100644 index c13cc986ea..0000000000 --- a/Libraries/LibCore/EventLoop.cpp +++ /dev/null @@ -1,835 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Badge.h> -#include <AK/ByteBuffer.h> -#include <AK/IDAllocator.h> -#include <AK/JsonObject.h> -#include <AK/JsonValue.h> -#include <AK/NeverDestroyed.h> -#include <AK/Singleton.h> -#include <AK/TemporaryChange.h> -#include <AK/Time.h> -#include <LibCore/Event.h> -#include <LibCore/EventLoop.h> -#include <LibCore/LocalServer.h> -#include <LibCore/LocalSocket.h> -#include <LibCore/Notifier.h> -#include <LibCore/Object.h> -#include <LibCore/SyscallUtils.h> -#include <LibThread/Lock.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/select.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <time.h> -#include <unistd.h> - -//#define EVENTLOOP_DEBUG -//#define DEFERRED_INVOKE_DEBUG - -namespace Core { - -class RPCClient; - -struct EventLoopTimer { - int timer_id { 0 }; - int interval { 0 }; - timeval fire_time { 0, 0 }; - bool should_reload { false }; - TimerShouldFireWhenNotVisible fire_when_not_visible { TimerShouldFireWhenNotVisible::No }; - WeakPtr<Object> owner; - - void reload(const timeval& now); - bool has_expired(const timeval& now) const; -}; - -struct EventLoop::Private { - LibThread::Lock lock; -}; - -static EventLoop* s_main_event_loop; -static Vector<EventLoop*>* s_event_loop_stack; -static NeverDestroyed<IDAllocator> s_id_allocator; -static HashMap<int, NonnullOwnPtr<EventLoopTimer>>* s_timers; -static HashTable<Notifier*>* s_notifiers; -int EventLoop::s_wake_pipe_fds[2]; -static RefPtr<LocalServer> s_rpc_server; -HashMap<int, RefPtr<RPCClient>> s_rpc_clients; - -class SignalHandlers : public RefCounted<SignalHandlers> { - AK_MAKE_NONCOPYABLE(SignalHandlers); - AK_MAKE_NONMOVABLE(SignalHandlers); - -public: - SignalHandlers(int signo, void (*handle_signal)(int)); - ~SignalHandlers(); - - void dispatch(); - int add(Function<void(int)>&& handler); - bool remove(int handler_id); - - bool is_empty() const - { - if (m_calling_handlers) { - for (auto& handler : m_handlers_pending) { - if (handler.value) - return false; // an add is pending - } - } - return m_handlers.is_empty(); - } - - bool have(int handler_id) const - { - if (m_calling_handlers) { - auto it = m_handlers_pending.find(handler_id); - if (it != m_handlers_pending.end()) { - if (!it->value) - return false; // a deletion is pending - } - } - return m_handlers.contains(handler_id); - } - - int m_signo; - void (*m_original_handler)(int); // TODO: can't use sighandler_t? - HashMap<int, Function<void(int)>> m_handlers; - HashMap<int, Function<void(int)>> m_handlers_pending; - bool m_calling_handlers { false }; -}; - -struct SignalHandlersInfo { - HashMap<int, NonnullRefPtr<SignalHandlers>> signal_handlers; - int next_signal_id { 0 }; -}; - -template<bool create_if_null = true> -inline SignalHandlersInfo* signals_info() -{ - static SignalHandlersInfo* s_signals; - return AK::Singleton<SignalHandlersInfo>::get(s_signals); -} - -pid_t EventLoop::s_pid; - -class RPCClient : public Object { - C_OBJECT(RPCClient) -public: - explicit RPCClient(RefPtr<LocalSocket> socket) - : m_socket(move(socket)) - , m_client_id(s_id_allocator->allocate()) - { - s_rpc_clients.set(m_client_id, this); - add_child(*m_socket); - m_socket->on_ready_to_read = [this] { - u32 length; - int nread = m_socket->read((u8*)&length, sizeof(length)); - if (nread == 0) { -#ifdef EVENTLOOP_DEBUG - dbgln("RPC client disconnected"); -#endif - shutdown(); - return; - } - ASSERT(nread == sizeof(length)); - auto request = m_socket->read(length); - - auto request_json = JsonValue::from_string(request); - if (!request_json.has_value() || !request_json.value().is_object()) { - dbgln("RPC client sent invalid request"); - shutdown(); - return; - } - - handle_request(request_json.value().as_object()); - }; - } - virtual ~RPCClient() override - { - if (auto inspected_object = m_inspected_object.strong_ref()) - inspected_object->decrement_inspector_count({}); - } - - void send_response(const JsonObject& response) - { - auto serialized = response.to_string(); - u32 length = serialized.length(); - m_socket->write((const u8*)&length, sizeof(length)); - m_socket->write(serialized); - } - - void handle_request(const JsonObject& request) - { - auto type = request.get("type").as_string_or({}); - - if (type.is_null()) { - dbgln("RPC client sent request without type field"); - return; - } - - if (type == "Identify") { - JsonObject response; - response.set("type", type); - response.set("pid", getpid()); -#ifdef __serenity__ - char buffer[1024]; - if (get_process_name(buffer, sizeof(buffer)) >= 0) { - response.set("process_name", buffer); - } else { - response.set("process_name", JsonValue()); - } -#endif - send_response(response); - return; - } - - if (type == "GetAllObjects") { - JsonObject response; - response.set("type", type); - JsonArray objects; - for (auto& object : Object::all_objects()) { - JsonObject json_object; - object.save_to(json_object); - objects.append(move(json_object)); - } - response.set("objects", move(objects)); - send_response(response); - return; - } - - if (type == "SetInspectedObject") { - auto address = request.get("address").to_number<FlatPtr>(); - for (auto& object : Object::all_objects()) { - if ((FlatPtr)&object == address) { - if (auto inspected_object = m_inspected_object.strong_ref()) - inspected_object->decrement_inspector_count({}); - m_inspected_object = object; - object.increment_inspector_count({}); - break; - } - } - return; - } - - if (type == "SetProperty") { - auto address = request.get("address").to_number<FlatPtr>(); - for (auto& object : Object::all_objects()) { - if ((FlatPtr)&object == address) { - bool success = object.set_property(request.get("name").to_string(), request.get("value")); - JsonObject response; - response.set("type", "SetProperty"); - response.set("success", success); - send_response(response); - break; - } - } - return; - } - - if (type == "Disconnect") { - shutdown(); - return; - } - } - - void shutdown() - { - s_rpc_clients.remove(m_client_id); - s_id_allocator->deallocate(m_client_id); - } - -private: - RefPtr<LocalSocket> m_socket; - WeakPtr<Object> m_inspected_object; - int m_client_id { -1 }; -}; - -EventLoop::EventLoop() - : m_private(make<Private>()) -{ - if (!s_event_loop_stack) { - s_event_loop_stack = new Vector<EventLoop*>; - s_timers = new HashMap<int, NonnullOwnPtr<EventLoopTimer>>; - s_notifiers = new HashTable<Notifier*>; - } - - if (!s_main_event_loop) { - s_main_event_loop = this; - s_pid = getpid(); -#if defined(SOCK_NONBLOCK) - int rc = pipe2(s_wake_pipe_fds, O_CLOEXEC); -#else - int rc = pipe(s_wake_pipe_fds); - fcntl(s_wake_pipe_fds[0], F_SETFD, FD_CLOEXEC); - fcntl(s_wake_pipe_fds[1], F_SETFD, FD_CLOEXEC); - -#endif - ASSERT(rc == 0); - s_event_loop_stack->append(this); - - if (!s_rpc_server) { - if (!start_rpc_server()) - dbgln("Core::EventLoop: Failed to start an RPC server"); - } - } - -#ifdef EVENTLOOP_DEBUG - dbgln("{} Core::EventLoop constructed :)", getpid()); -#endif -} - -EventLoop::~EventLoop() -{ -} - -bool EventLoop::start_rpc_server() -{ - s_rpc_server = LocalServer::construct(); - s_rpc_server->set_name("Core::EventLoop_RPC_server"); - s_rpc_server->on_ready_to_accept = [&] { - RPCClient::construct(s_rpc_server->accept()); - }; - return s_rpc_server->listen(String::formatted("/tmp/rpc/{}", getpid())); -} - -EventLoop& EventLoop::main() -{ - ASSERT(s_main_event_loop); - return *s_main_event_loop; -} - -EventLoop& EventLoop::current() -{ - EventLoop* event_loop = s_event_loop_stack->last(); - ASSERT(event_loop != nullptr); - return *event_loop; -} - -void EventLoop::quit(int code) -{ -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop::quit({})", code); -#endif - m_exit_requested = true; - m_exit_code = code; -} - -void EventLoop::unquit() -{ -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop::unquit()"); -#endif - m_exit_requested = false; - m_exit_code = 0; -} - -struct EventLoopPusher { -public: - EventLoopPusher(EventLoop& event_loop) - : m_event_loop(event_loop) - { - if (&m_event_loop != s_main_event_loop) { - m_event_loop.take_pending_events_from(EventLoop::current()); - s_event_loop_stack->append(&event_loop); - } - } - ~EventLoopPusher() - { - if (&m_event_loop != s_main_event_loop) { - s_event_loop_stack->take_last(); - EventLoop::current().take_pending_events_from(m_event_loop); - } - } - -private: - EventLoop& m_event_loop; -}; - -int EventLoop::exec() -{ - EventLoopPusher pusher(*this); - for (;;) { - if (m_exit_requested) - return m_exit_code; - pump(); - } - ASSERT_NOT_REACHED(); -} - -void EventLoop::pump(WaitMode mode) -{ - wait_for_event(mode); - - decltype(m_queued_events) events; - { - LOCKER(m_private->lock); - events = move(m_queued_events); - } - - for (size_t i = 0; i < events.size(); ++i) { - auto& queued_event = events.at(i); - auto receiver = queued_event.receiver.strong_ref(); - auto& event = *queued_event.event; -#ifdef EVENTLOOP_DEBUG - if (receiver) - dbgln("Core::EventLoop: {} event {}", *receiver, event.type()); -#endif - if (!receiver) { - switch (event.type()) { - case Event::Quit: - ASSERT_NOT_REACHED(); - return; - default: -#ifdef EVENTLOOP_DEBUG - dbgln("Event type {} with no receiver :(", event.type()); -#endif - break; - } - } else if (event.type() == Event::Type::DeferredInvoke) { -#ifdef DEFERRED_INVOKE_DEBUG - dbgln("DeferredInvoke: receiver = {}", *receiver); -#endif - static_cast<DeferredInvocationEvent&>(event).m_invokee(*receiver); - } else { - NonnullRefPtr<Object> protector(*receiver); - receiver->dispatch_event(event); - } - - if (m_exit_requested) { - LOCKER(m_private->lock); -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop: Exit requested. Rejigging {} events.", events.size() - i); -#endif - decltype(m_queued_events) new_event_queue; - new_event_queue.ensure_capacity(m_queued_events.size() + events.size()); - for (++i; i < events.size(); ++i) - new_event_queue.unchecked_append(move(events[i])); - new_event_queue.append(move(m_queued_events)); - m_queued_events = move(new_event_queue); - return; - } - } -} - -void EventLoop::post_event(Object& receiver, NonnullOwnPtr<Event>&& event) -{ - LOCKER(m_private->lock); -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop::post_event: ({}) << receivier={}, event={}", m_queued_events.size(), receiver, event); -#endif - m_queued_events.empend(receiver, move(event)); -} - -SignalHandlers::SignalHandlers(int signo, void (*handle_signal)(int)) - : m_signo(signo) - , m_original_handler(signal(signo, handle_signal)) -{ -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop: Registered handler for signal {}", m_signo); -#endif -} - -SignalHandlers::~SignalHandlers() -{ -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop: Unregistering handler for signal {}", m_signo); -#endif - signal(m_signo, m_original_handler); -} - -void SignalHandlers::dispatch() -{ - TemporaryChange change(m_calling_handlers, true); - for (auto& handler : m_handlers) - handler.value(m_signo); - if (!m_handlers_pending.is_empty()) { - // Apply pending adds/removes - for (auto& handler : m_handlers_pending) { - if (handler.value) { - auto result = m_handlers.set(handler.key, move(handler.value)); - ASSERT(result == AK::HashSetResult::InsertedNewEntry); - } else { - m_handlers.remove(handler.key); - } - } - m_handlers_pending.clear(); - } -} - -int SignalHandlers::add(Function<void(int)>&& handler) -{ - int id = ++signals_info()->next_signal_id; // TODO: worry about wrapping and duplicates? - if (m_calling_handlers) - m_handlers_pending.set(id, move(handler)); - else - m_handlers.set(id, move(handler)); - return id; -} - -bool SignalHandlers::remove(int handler_id) -{ - ASSERT(handler_id != 0); - if (m_calling_handlers) { - auto it = m_handlers.find(handler_id); - if (it != m_handlers.end()) { - // Mark pending remove - m_handlers_pending.set(handler_id, {}); - return true; - } - it = m_handlers_pending.find(handler_id); - if (it != m_handlers_pending.end()) { - if (!it->value) - return false; // already was marked as deleted - it->value = nullptr; - return true; - } - return false; - } - return m_handlers.remove(handler_id); -} - -void EventLoop::dispatch_signal(int signo) -{ - auto& info = *signals_info(); - auto handlers = info.signal_handlers.find(signo); - if (handlers != info.signal_handlers.end()) { - // Make sure we bump the ref count while dispatching the handlers! - // This allows a handler to unregister/register while the handlers - // are being called! - auto handler = handlers->value; -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop: dispatching signal {}", signo); -#endif - handler->dispatch(); - } -} - -void EventLoop::handle_signal(int signo) -{ - ASSERT(signo != 0); - // We MUST check if the current pid still matches, because there - // is a window between fork() and exec() where a signal delivered - // to our fork could be inadvertedly routed to the parent process! - if (getpid() == s_pid) { - int nwritten = write(s_wake_pipe_fds[1], &signo, sizeof(signo)); - if (nwritten < 0) { - perror("EventLoop::register_signal: write"); - ASSERT_NOT_REACHED(); - } - } else { - // We're a fork who received a signal, reset s_pid - s_pid = 0; - } -} - -int EventLoop::register_signal(int signo, Function<void(int)> handler) -{ - ASSERT(signo != 0); - auto& info = *signals_info(); - auto handlers = info.signal_handlers.find(signo); - if (handlers == info.signal_handlers.end()) { - auto signal_handlers = adopt(*new SignalHandlers(signo, EventLoop::handle_signal)); - auto handler_id = signal_handlers->add(move(handler)); - info.signal_handlers.set(signo, move(signal_handlers)); - return handler_id; - } else { - return handlers->value->add(move(handler)); - } -} - -void EventLoop::unregister_signal(int handler_id) -{ - ASSERT(handler_id != 0); - int remove_signo = 0; - auto& info = *signals_info(); - for (auto& h : info.signal_handlers) { - auto& handlers = *h.value; - if (handlers.remove(handler_id)) { - if (handlers.is_empty()) - remove_signo = handlers.m_signo; - break; - } - } - if (remove_signo != 0) - info.signal_handlers.remove(remove_signo); -} - -void EventLoop::notify_forked(ForkEvent event) -{ - switch (event) { - case ForkEvent::Child: - s_main_event_loop = nullptr; - s_event_loop_stack->clear(); - s_timers->clear(); - s_notifiers->clear(); - if (auto* info = signals_info<false>()) { - info->signal_handlers.clear(); - info->next_signal_id = 0; - } - s_pid = 0; - s_rpc_server = nullptr; - s_rpc_clients.clear(); - return; - } - - ASSERT_NOT_REACHED(); -} - -void EventLoop::wait_for_event(WaitMode mode) -{ - fd_set rfds; - fd_set wfds; -retry: - FD_ZERO(&rfds); - FD_ZERO(&wfds); - - int max_fd = 0; - auto add_fd_to_set = [&max_fd](int fd, fd_set& set) { - FD_SET(fd, &set); - if (fd > max_fd) - max_fd = fd; - }; - - int max_fd_added = -1; - add_fd_to_set(s_wake_pipe_fds[0], rfds); - max_fd = max(max_fd, max_fd_added); - for (auto& notifier : *s_notifiers) { - if (notifier->event_mask() & Notifier::Read) - add_fd_to_set(notifier->fd(), rfds); - if (notifier->event_mask() & Notifier::Write) - add_fd_to_set(notifier->fd(), wfds); - if (notifier->event_mask() & Notifier::Exceptional) - ASSERT_NOT_REACHED(); - } - - bool queued_events_is_empty; - { - LOCKER(m_private->lock); - queued_events_is_empty = m_queued_events.is_empty(); - } - - timeval now; - struct timeval timeout = { 0, 0 }; - bool should_wait_forever = false; - if (mode == WaitMode::WaitForEvents && queued_events_is_empty) { - auto next_timer_expiration = get_next_timer_expiration(); - if (next_timer_expiration.has_value()) { - timespec now_spec; - clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); - now.tv_sec = now_spec.tv_sec; - now.tv_usec = now_spec.tv_nsec / 1000; - timeval_sub(next_timer_expiration.value(), now, timeout); - if (timeout.tv_sec < 0 || (timeout.tv_sec == 0 && timeout.tv_usec < 0)) { - timeout.tv_sec = 0; - timeout.tv_usec = 0; - } - } else { - should_wait_forever = true; - } - } - -try_select_again: - int marked_fd_count = select(max_fd + 1, &rfds, &wfds, nullptr, should_wait_forever ? nullptr : &timeout); - if (marked_fd_count < 0) { - int saved_errno = errno; - if (saved_errno == EINTR) { - if (m_exit_requested) - return; - goto try_select_again; - } -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop::wait_for_event: {} ({}: {})", marked_fd_count, saved_errno, strerror(saved_errno)); -#endif - // Blow up, similar to Core::safe_syscall. - ASSERT_NOT_REACHED(); - } - if (FD_ISSET(s_wake_pipe_fds[0], &rfds)) { - int wake_events[8]; - auto nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events)); - if (nread < 0) { - perror("read from wake pipe"); - ASSERT_NOT_REACHED(); - } - ASSERT(nread > 0); - bool wake_requested = false; - int event_count = nread / sizeof(wake_events[0]); - for (int i = 0; i < event_count; i++) { - if (wake_events[i] != 0) - dispatch_signal(wake_events[i]); - else - wake_requested = true; - } - - if (!wake_requested && nread == sizeof(wake_events)) - goto retry; - } - - if (!s_timers->is_empty()) { - timespec now_spec; - clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); - now.tv_sec = now_spec.tv_sec; - now.tv_usec = now_spec.tv_nsec / 1000; - } - - for (auto& it : *s_timers) { - auto& timer = *it.value; - if (!timer.has_expired(now)) - continue; - auto owner = timer.owner.strong_ref(); - if (timer.fire_when_not_visible == TimerShouldFireWhenNotVisible::No - && owner && !owner->is_visible_for_timer_purposes()) { - continue; - } -#ifdef EVENTLOOP_DEBUG - dbgln("Core::EventLoop: Timer {} has expired, sending Core::TimerEvent to {}", timer.timer_id, *owner); -#endif - if (owner) - post_event(*owner, make<TimerEvent>(timer.timer_id)); - if (timer.should_reload) { - timer.reload(now); - } else { - // FIXME: Support removing expired timers that don't want to reload. - ASSERT_NOT_REACHED(); - } - } - - if (!marked_fd_count) - return; - - for (auto& notifier : *s_notifiers) { - if (FD_ISSET(notifier->fd(), &rfds)) { - if (notifier->event_mask() & Notifier::Event::Read) - post_event(*notifier, make<NotifierReadEvent>(notifier->fd())); - } - if (FD_ISSET(notifier->fd(), &wfds)) { - if (notifier->event_mask() & Notifier::Event::Write) - post_event(*notifier, make<NotifierWriteEvent>(notifier->fd())); - } - } -} - -bool EventLoopTimer::has_expired(const timeval& now) const -{ - return now.tv_sec > fire_time.tv_sec || (now.tv_sec == fire_time.tv_sec && now.tv_usec >= fire_time.tv_usec); -} - -void EventLoopTimer::reload(const timeval& now) -{ - fire_time = now; - fire_time.tv_sec += interval / 1000; - fire_time.tv_usec += (interval % 1000) * 1000; -} - -Optional<struct timeval> EventLoop::get_next_timer_expiration() -{ - Optional<struct timeval> soonest {}; - for (auto& it : *s_timers) { - auto& fire_time = it.value->fire_time; - auto owner = it.value->owner.strong_ref(); - if (it.value->fire_when_not_visible == TimerShouldFireWhenNotVisible::No - && owner && !owner->is_visible_for_timer_purposes()) { - continue; - } - if (!soonest.has_value() || fire_time.tv_sec < soonest.value().tv_sec || (fire_time.tv_sec == soonest.value().tv_sec && fire_time.tv_usec < soonest.value().tv_usec)) - soonest = fire_time; - } - return soonest; -} - -int EventLoop::register_timer(Object& object, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible fire_when_not_visible) -{ - ASSERT(milliseconds >= 0); - auto timer = make<EventLoopTimer>(); - timer->owner = object; - timer->interval = milliseconds; - timeval now; - timespec now_spec; - clock_gettime(CLOCK_MONOTONIC_COARSE, &now_spec); - now.tv_sec = now_spec.tv_sec; - now.tv_usec = now_spec.tv_nsec / 1000; - timer->reload(now); - timer->should_reload = should_reload; - timer->fire_when_not_visible = fire_when_not_visible; - int timer_id = s_id_allocator->allocate(); - timer->timer_id = timer_id; - s_timers->set(timer_id, move(timer)); - return timer_id; -} - -bool EventLoop::unregister_timer(int timer_id) -{ - s_id_allocator->deallocate(timer_id); - auto it = s_timers->find(timer_id); - if (it == s_timers->end()) - return false; - s_timers->remove(it); - return true; -} - -void EventLoop::register_notifier(Badge<Notifier>, Notifier& notifier) -{ - s_notifiers->set(¬ifier); -} - -void EventLoop::unregister_notifier(Badge<Notifier>, Notifier& notifier) -{ - s_notifiers->remove(¬ifier); -} - -void EventLoop::wake() -{ - int wake_event = 0; - int nwritten = write(s_wake_pipe_fds[1], &wake_event, sizeof(wake_event)); - if (nwritten < 0) { - perror("EventLoop::wake: write"); - ASSERT_NOT_REACHED(); - } -} - -EventLoop::QueuedEvent::QueuedEvent(Object& receiver, NonnullOwnPtr<Event> event) - : receiver(receiver) - , event(move(event)) -{ -} - -EventLoop::QueuedEvent::QueuedEvent(QueuedEvent&& other) - : receiver(other.receiver) - , event(move(other.event)) -{ -} - -EventLoop::QueuedEvent::~QueuedEvent() -{ -} - -} diff --git a/Libraries/LibCore/EventLoop.h b/Libraries/LibCore/EventLoop.h deleted file mode 100644 index d299b93407..0000000000 --- a/Libraries/LibCore/EventLoop.h +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Forward.h> -#include <AK/Function.h> -#include <AK/HashMap.h> -#include <AK/Noncopyable.h> -#include <AK/NonnullOwnPtr.h> -#include <AK/Vector.h> -#include <AK/WeakPtr.h> -#include <LibCore/Forward.h> -#include <sys/time.h> -#include <sys/types.h> - -namespace Core { - -class EventLoop { -public: - EventLoop(); - ~EventLoop(); - - int exec(); - - enum class WaitMode { - WaitForEvents, - PollForEvents, - }; - - // processe events, generally called by exec() in a loop. - // this should really only be used for integrating with other event loops - void pump(WaitMode = WaitMode::WaitForEvents); - - void post_event(Object& receiver, NonnullOwnPtr<Event>&&); - - static EventLoop& main(); - static EventLoop& current(); - - bool was_exit_requested() const { return m_exit_requested; } - - static int register_timer(Object&, int milliseconds, bool should_reload, TimerShouldFireWhenNotVisible); - static bool unregister_timer(int timer_id); - - static void register_notifier(Badge<Notifier>, Notifier&); - static void unregister_notifier(Badge<Notifier>, Notifier&); - - void quit(int); - void unquit(); - - void take_pending_events_from(EventLoop& other) - { - m_queued_events.append(move(other.m_queued_events)); - } - - static void wake(); - - static int register_signal(int signo, Function<void(int)> handler); - static void unregister_signal(int handler_id); - - // Note: Boost uses Parent/Child/Prepare, but we don't really have anything - // interesting to do in the parent or before forking. - enum class ForkEvent { - Child, - }; - static void notify_forked(ForkEvent); - -private: - bool start_rpc_server(); - void wait_for_event(WaitMode); - Optional<struct timeval> get_next_timer_expiration(); - static void dispatch_signal(int); - static void handle_signal(int); - - struct QueuedEvent { - AK_MAKE_NONCOPYABLE(QueuedEvent); - - public: - QueuedEvent(Object& receiver, NonnullOwnPtr<Event>); - QueuedEvent(QueuedEvent&&); - ~QueuedEvent(); - - WeakPtr<Object> receiver; - NonnullOwnPtr<Event> event; - }; - - Vector<QueuedEvent, 64> m_queued_events; - static pid_t s_pid; - - bool m_exit_requested { false }; - int m_exit_code { 0 }; - - static int s_wake_pipe_fds[2]; - - struct Private; - NonnullOwnPtr<Private> m_private; -}; - -} diff --git a/Libraries/LibCore/File.cpp b/Libraries/LibCore/File.cpp deleted file mode 100644 index 07192a9b18..0000000000 --- a/Libraries/LibCore/File.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifdef __serenity__ -# include <Kernel/API/Syscall.h> -#endif -#include <AK/ScopeGuard.h> -#include <LibCore/File.h> -#include <errno.h> -#include <fcntl.h> -#include <libgen.h> -#include <stdio.h> -#include <string.h> -#include <sys/stat.h> -#include <unistd.h> - -namespace Core { - -Result<NonnullRefPtr<File>, String> File::open(const String& filename, IODevice::OpenMode mode, mode_t permissions) -{ - auto file = File::construct(filename); - if (!file->open_impl(mode, permissions)) - return String(file->error_string()); - return file; -} - -File::File(const StringView& filename, Object* parent) - : IODevice(parent) - , m_filename(filename) -{ -} - -File::~File() -{ - if (m_should_close_file_descriptor == ShouldCloseFileDescriptor::Yes && mode() != NotOpen) - close(); -} - -bool File::open(int fd, IODevice::OpenMode mode, ShouldCloseFileDescriptor should_close) -{ - set_fd(fd); - set_mode(mode); - m_should_close_file_descriptor = should_close; - return true; -} - -bool File::open(IODevice::OpenMode mode) -{ - return open_impl(mode, 0666); -} - -bool File::open_impl(IODevice::OpenMode mode, mode_t permissions) -{ - ASSERT(!m_filename.is_null()); - int flags = 0; - if ((mode & IODevice::ReadWrite) == IODevice::ReadWrite) { - flags |= O_RDWR | O_CREAT; - } else if (mode & IODevice::ReadOnly) { - flags |= O_RDONLY; - } else if (mode & IODevice::WriteOnly) { - flags |= O_WRONLY | O_CREAT; - bool should_truncate = !((mode & IODevice::Append) || (mode & IODevice::MustBeNew)); - if (should_truncate) - flags |= O_TRUNC; - } - if (mode & IODevice::Append) - flags |= O_APPEND; - if (mode & IODevice::Truncate) - flags |= O_TRUNC; - if (mode & IODevice::MustBeNew) - flags |= O_EXCL; - int fd = ::open(m_filename.characters(), flags, permissions); - if (fd < 0) { - set_error(errno); - return false; - } - - set_fd(fd); - set_mode(mode); - return true; -} - -bool File::is_directory() const -{ - struct stat stat; - if (fstat(fd(), &stat) < 0) - return false; - return S_ISDIR(stat.st_mode); -} - -bool File::is_directory(const String& filename) -{ - struct stat st; - if (stat(filename.characters(), &st) < 0) - return false; - return S_ISDIR(st.st_mode); -} - -bool File::exists(const String& filename) -{ - struct stat st; - return stat(filename.characters(), &st) == 0; -} - -String File::real_path_for(const String& filename) -{ - if (filename.is_null()) - return {}; - auto* path = realpath(filename.characters(), nullptr); - String real_path(path); - free(path); - return real_path; -} - -bool File::ensure_parent_directories(const String& path) -{ - ASSERT(path.starts_with("/")); - - int saved_errno = 0; - ScopeGuard restore_errno = [&saved_errno] { errno = saved_errno; }; - - char* parent_buffer = strdup(path.characters()); - ScopeGuard free_buffer = [parent_buffer] { free(parent_buffer); }; - - const char* parent = dirname(parent_buffer); - - int rc = mkdir(parent, 0755); - saved_errno = errno; - - if (rc == 0 || errno == EEXIST) - return true; - - if (errno != ENOENT) - return false; - - bool ok = ensure_parent_directories(parent); - saved_errno = errno; - if (!ok) - return false; - - rc = mkdir(parent, 0755); - saved_errno = errno; - return rc == 0; -} - -#ifdef __serenity__ - -String File::read_link(const StringView& link_path) -{ - // First, try using a 64-byte buffer, that ought to be enough for anybody. - char small_buffer[64]; - Syscall::SC_readlink_params small_params { - { link_path.characters_without_null_termination(), link_path.length() }, - { small_buffer, sizeof(small_buffer) } - }; - int rc = syscall(SC_readlink, &small_params); - if (rc < 0) { - errno = -rc; - return {}; - } - size_t size = rc; - // If the call was successful, the syscall (unlike the LibC wrapper) - // returns the full size of the link. Let's see if our small buffer - // was enough to read the whole link. - if (size <= sizeof(small_buffer)) - return { small_buffer, size }; - // Nope, but at least now we know the right size. - char* large_buffer_ptr; - auto large_buffer = StringImpl::create_uninitialized(size, large_buffer_ptr); - Syscall::SC_readlink_params large_params { - { link_path.characters_without_null_termination(), link_path.length() }, - { large_buffer_ptr, (size_t)size } - }; - rc = syscall(SC_readlink, &large_params); - if (rc < 0) { - errno = -rc; - return {}; - } - size_t new_size = rc; - if (new_size == size) - return { *large_buffer }; - - // If we're here, the symlink has changed while we were looking at it. - // If it became shorter, our buffer is valid, we just have to trim it a bit. - if (new_size < size) - return { large_buffer_ptr, new_size }; - // Otherwise, here's not much we can do, unless we want to loop endlessly - // in this case. Let's leave it up to the caller whether to loop. - errno = -EAGAIN; - return {}; -} - -#else - -// This is a sad version for other systems. It has to always make a copy of the -// link path, and to always make two syscalls to get the right size first. -String File::read_link(const StringView& link_path) -{ - String link_path_str = link_path; - struct stat statbuf; - int rc = lstat(link_path_str.characters(), &statbuf); - if (rc < 0) - return {}; - char* buffer_ptr; - auto buffer = StringImpl::create_uninitialized(statbuf.st_size, buffer_ptr); - rc = readlink(link_path_str.characters(), buffer_ptr, statbuf.st_size); - if (rc < 0) - return {}; - // (See above.) - if (rc == statbuf.st_size) - return { *buffer }; - return { buffer_ptr, (size_t)rc }; -} - -#endif - -static RefPtr<File> stdin_file; -static RefPtr<File> stdout_file; -static RefPtr<File> stderr_file; - -NonnullRefPtr<File> File::standard_input() -{ - if (!stdin_file) { - stdin_file = File::construct(); - stdin_file->open(STDIN_FILENO, IODevice::ReadOnly, ShouldCloseFileDescriptor::No); - } - return *stdin_file; -} - -NonnullRefPtr<File> File::standard_output() -{ - if (!stdout_file) { - stdout_file = File::construct(); - stdout_file->open(STDOUT_FILENO, IODevice::WriteOnly, ShouldCloseFileDescriptor::No); - } - return *stdout_file; -} - -NonnullRefPtr<File> File::standard_error() -{ - if (!stderr_file) { - stderr_file = File::construct(); - stderr_file->open(STDERR_FILENO, IODevice::WriteOnly, ShouldCloseFileDescriptor::No); - } - return *stderr_file; -} -} diff --git a/Libraries/LibCore/File.h b/Libraries/LibCore/File.h deleted file mode 100644 index 040a2813b7..0000000000 --- a/Libraries/LibCore/File.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Result.h> -#include <AK/String.h> -#include <LibCore/IODevice.h> - -namespace Core { - -class File final : public IODevice { - C_OBJECT(File) -public: - virtual ~File() override; - - static Result<NonnullRefPtr<File>, String> open(const String& filename, IODevice::OpenMode, mode_t = 0644); - - String filename() const { return m_filename; } - void set_filename(const StringView& filename) { m_filename = filename; } - - bool is_directory() const; - static bool is_directory(const String& filename); - - static bool exists(const String& filename); - static String real_path_for(const String& filename); - static String read_link(const StringView& link_path); - static bool ensure_parent_directories(const String& path); - - virtual bool open(IODevice::OpenMode) override; - - enum class ShouldCloseFileDescriptor { - No = 0, - Yes - }; - bool open(int fd, IODevice::OpenMode, ShouldCloseFileDescriptor); - - static NonnullRefPtr<File> standard_input(); - static NonnullRefPtr<File> standard_output(); - static NonnullRefPtr<File> standard_error(); - -private: - File(Object* parent = nullptr) - : IODevice(parent) - { - } - explicit File(const StringView&, Object* parent = nullptr); - - bool open_impl(IODevice::OpenMode, mode_t); - - String m_filename; - ShouldCloseFileDescriptor m_should_close_file_descriptor { ShouldCloseFileDescriptor::Yes }; -}; - -} diff --git a/Libraries/LibCore/FileStream.h b/Libraries/LibCore/FileStream.h deleted file mode 100644 index 0c8774d28a..0000000000 --- a/Libraries/LibCore/FileStream.h +++ /dev/null @@ -1,171 +0,0 @@ -/* - * Copyright (c) 2020, the SerenityOS developers. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Buffered.h> -#include <AK/ByteBuffer.h> -#include <AK/Stream.h> -#include <LibCore/File.h> - -namespace Core { - -class InputFileStream final : public InputStream { -public: - explicit InputFileStream(NonnullRefPtr<File> file) - : m_file(file) - { - } - - static Result<InputFileStream, String> open(StringView filename, IODevice::OpenMode mode = IODevice::OpenMode::ReadOnly, mode_t permissions = 0644) - { - ASSERT((mode & 0xf) == IODevice::OpenMode::ReadOnly || (mode & 0xf) == IODevice::OpenMode::ReadWrite); - - auto file_result = File::open(filename, mode, permissions); - - if (file_result.is_error()) - return file_result.error(); - - return InputFileStream { file_result.value() }; - } - - static Result<Buffered<InputFileStream>, String> open_buffered(StringView filename, IODevice::OpenMode mode = IODevice::OpenMode::ReadOnly, mode_t permissions = 0644) - { - ASSERT((mode & 0xf) == IODevice::OpenMode::ReadOnly || (mode & 0xf) == IODevice::OpenMode::ReadWrite); - - auto file_result = File::open(filename, mode, permissions); - - if (file_result.is_error()) - return file_result.error(); - - return Buffered<InputFileStream> { file_result.value() }; - } - - size_t read(Bytes bytes) override - { - if (has_any_error()) - return 0; - - const auto buffer = m_file->read(bytes.size()); - return buffer.bytes().copy_to(bytes); - } - - bool read_or_error(Bytes bytes) override - { - if (read(bytes) < bytes.size()) { - set_fatal_error(); - return false; - } - - return true; - } - - bool discard_or_error(size_t count) override { return m_file->seek(count, IODevice::SeekMode::FromCurrentPosition); } - - bool unreliable_eof() const override { return m_file->eof(); } - - void close() - { - if (!m_file->close()) - set_fatal_error(); - } - -private: - NonnullRefPtr<File> m_file; -}; - -class OutputFileStream : public OutputStream { -public: - explicit OutputFileStream(NonnullRefPtr<File> file) - : m_file(file) - { - } - - static Result<OutputFileStream, String> open(StringView filename, IODevice::OpenMode mode = IODevice::OpenMode::WriteOnly, mode_t permissions = 0644) - { - ASSERT((mode & 0xf) == IODevice::OpenMode::WriteOnly || (mode & 0xf) == IODevice::OpenMode::ReadWrite); - - auto file_result = File::open(filename, mode, permissions); - - if (file_result.is_error()) - return file_result.error(); - - return OutputFileStream { file_result.value() }; - } - - static Result<Buffered<OutputFileStream>, String> open_buffered(StringView filename, IODevice::OpenMode mode = IODevice::OpenMode::WriteOnly, mode_t permissions = 0644) - { - ASSERT((mode & 0xf) == IODevice::OpenMode::WriteOnly || (mode & 0xf) == IODevice::OpenMode::ReadWrite); - - auto file_result = File::open(filename, mode, permissions); - - if (file_result.is_error()) - return file_result.error(); - - return Buffered<OutputFileStream> { file_result.value() }; - } - - static OutputFileStream standard_output() - { - return OutputFileStream { Core::File::standard_output() }; - } - - static Buffered<OutputFileStream> stdout_buffered() - { - return Buffered<OutputFileStream> { Core::File::standard_output() }; - } - - size_t write(ReadonlyBytes bytes) override - { - if (!m_file->write(bytes.data(), bytes.size())) { - set_fatal_error(); - return 0; - } - - return bytes.size(); - } - - bool write_or_error(ReadonlyBytes bytes) override - { - if (write(bytes) < bytes.size()) { - set_fatal_error(); - return false; - } - - return true; - } - - void close() - { - if (!m_file->close()) - set_fatal_error(); - } - -private: - NonnullRefPtr<File> m_file; -}; - -} diff --git a/Libraries/LibCore/Forward.h b/Libraries/LibCore/Forward.h deleted file mode 100644 index 09497cb0bf..0000000000 --- a/Libraries/LibCore/Forward.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -namespace Core { - -class ArgsParser; -class ChildEvent; -class ConfigFile; -class CustomEvent; -class DateTime; -class DirIterator; -class ElapsedTimer; -class Event; -class EventLoop; -class File; -class IODevice; -class LocalServer; -class LocalSocket; -class MimeData; -class NetworkJob; -class NetworkResponse; -class Notifier; -class Object; -class ProcessStatisticsReader; -class Socket; -class SocketAddress; -class TCPServer; -class TCPSocket; -class Timer; -class TimerEvent; -class UDPServer; -class UDPSocket; - -enum class TimerShouldFireWhenNotVisible; - -} diff --git a/Libraries/LibCore/GetPassword.cpp b/Libraries/LibCore/GetPassword.cpp deleted file mode 100644 index dfcff21583..0000000000 --- a/Libraries/LibCore/GetPassword.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> - * Copyright (c) 2021, Emanuele Torre <torreemanuele6@gmail.com> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/GetPassword.h> -#include <stdio.h> -#include <stdlib.h> -#include <termios.h> - -namespace Core { - -Result<String, OSError> get_password(const StringView& prompt) -{ - if (write(STDOUT_FILENO, prompt.characters_without_null_termination(), prompt.length()) < 0) - return OSError(errno); - - termios original {}; - if (tcgetattr(STDIN_FILENO, &original) < 0) - return OSError(errno); - - termios no_echo = original; - no_echo.c_lflag &= ~ECHO; - if (tcsetattr(STDIN_FILENO, TCSAFLUSH, &no_echo) < 0) - return OSError(errno); - - char* password = nullptr; - size_t n = 0; - - auto line_length = getline(&password, &n, stdin); - auto saved_errno = errno; - - tcsetattr(STDIN_FILENO, TCSAFLUSH, &original); - putchar('\n'); - - if (line_length < 0) - return OSError(saved_errno); - - ASSERT(line_length != 0); - - // Remove trailing '\n' read by getline(). - password[line_length - 1] = '\0'; - - String s(password); - free(password); - return s; -} -} diff --git a/Libraries/LibCore/GetPassword.h b/Libraries/LibCore/GetPassword.h deleted file mode 100644 index c62a071935..0000000000 --- a/Libraries/LibCore/GetPassword.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright (c) 2020, Peter Elliott <pelliott@ualberta.ca> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/OSError.h> -#include <AK/Result.h> -#include <AK/String.h> - -namespace Core { - -Result<String, OSError> get_password(const StringView& prompt = "Password: "); - -} diff --git a/Libraries/LibCore/Gzip.cpp b/Libraries/LibCore/Gzip.cpp deleted file mode 100644 index 49cf14c3a0..0000000000 --- a/Libraries/LibCore/Gzip.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/ByteBuffer.h> -#include <AK/Optional.h> -#include <LibCore/Gzip.h> -#include <LibCore/puff.h> -#include <limits.h> -#include <stddef.h> - -//#define DEBUG_GZIP - -namespace Core { - -bool Gzip::is_compressed(const ByteBuffer& data) -{ - return data.size() > 2 && data[0] == 0x1F && data[1] == 0x8b; -} - -// skips the gzip header -// see: https://tools.ietf.org/html/rfc1952#page-5 -static Optional<ByteBuffer> get_gzip_payload(const ByteBuffer& data) -{ - size_t current = 0; - auto read_byte = [&]() { - if (current >= data.size()) { - ASSERT_NOT_REACHED(); - return (u8)0; - } - return data[current++]; - }; - -#ifdef DEBUG_GZIP - dbgln("get_gzip_payload: Skipping over gzip header."); -#endif - - // Magic Header - if (read_byte() != 0x1F || read_byte() != 0x8B) { - dbgln("get_gzip_payload: Wrong magic number."); - return Optional<ByteBuffer>(); - } - - // Compression method - auto method = read_byte(); - if (method != 8) { - dbgln("get_gzip_payload: Wrong compression method={}", method); - return Optional<ByteBuffer>(); - } - - u8 flags = read_byte(); - - // Timestamp, Extra flags, OS - current += 6; - - // FEXTRA - if (flags & 4) { - u16 length = read_byte() & read_byte() << 8; - dbgln("get_gzip_payload: Header has FEXTRA flag set. length={}", length); - current += length; - } - - // FNAME - if (flags & 8) { - dbgln("get_gzip_payload: Header has FNAME flag set."); - while (read_byte() != '\0') - ; - } - - // FCOMMENT - if (flags & 16) { - dbgln("get_gzip_payload: Header has FCOMMENT flag set."); - while (read_byte() != '\0') - ; - } - - // FHCRC - if (flags & 2) { - dbgln("get_gzip_payload: Header has FHCRC flag set."); - current += 2; - } - - auto new_size = data.size() - current; -#ifdef DEBUG_GZIP - dbg() << "get_gzip_payload: Returning slice from " << current << " with size " << new_size; -#endif - return data.slice(current, new_size); -} - -Optional<ByteBuffer> Gzip::decompress(const ByteBuffer& data) -{ - ASSERT(is_compressed(data)); - -#ifdef DEBUG_GZIP - dbg() << "Gzip::decompress: Decompressing gzip compressed data. Size = " << data.size(); -#endif - auto optional_payload = get_gzip_payload(data); - if (!optional_payload.has_value()) { - return Optional<ByteBuffer>(); - } - - auto source = optional_payload.value(); - unsigned long source_len = source.size(); - auto destination = ByteBuffer::create_uninitialized(1024); - while (true) { - unsigned long destination_len = destination.size(); - -#ifdef DEBUG_GZIP - dbg() << "Gzip::decompress: Calling puff()\n" - << " destination_data = " << destination.data() << "\n" - << " destination_len = " << destination_len << "\n" - << " source_data = " << source.data() << "\n" - << " source_len = " << source_len; -#endif - - auto puff_ret = puff( - destination.data(), &destination_len, - source.data(), &source_len); - - if (puff_ret == 0) { -#ifdef DEBUG_GZIP - dbgln("Gzip::decompress: Decompression success."); -#endif - destination.trim(destination_len); - break; - } - - if (puff_ret == 1) { - // FIXME: Find a better way of decompressing without needing to try over and over again. -#ifdef DEBUG_GZIP - dbgln("Gzip::decompress: Output buffer exhausted. Growing."); -#endif - destination.grow(destination.size() * 2); - } else { - dbgln("Gzip::decompress: Error. puff() returned: {}", puff_ret); - ASSERT_NOT_REACHED(); - } - } - - return destination; -} - -} diff --git a/Libraries/LibCore/Gzip.h b/Libraries/LibCore/Gzip.h deleted file mode 100644 index a96af59536..0000000000 --- a/Libraries/LibCore/Gzip.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/ByteBuffer.h> -#include <AK/Optional.h> -#include <AK/String.h> - -namespace Core { - -class Gzip { -public: - static bool is_compressed(const ByteBuffer& data); - static Optional<ByteBuffer> decompress(const ByteBuffer& data); -}; - -} diff --git a/Libraries/LibCore/IODevice.cpp b/Libraries/LibCore/IODevice.cpp deleted file mode 100644 index 453526e408..0000000000 --- a/Libraries/LibCore/IODevice.cpp +++ /dev/null @@ -1,336 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/ByteBuffer.h> -#include <AK/PrintfImplementation.h> -#include <LibCore/IODevice.h> -#include <LibCore/SyscallUtils.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <sys/select.h> -#include <sys/stat.h> -#include <sys/time.h> -#include <unistd.h> - -namespace Core { - -IODevice::IODevice(Object* parent) - : Object(parent) -{ -} - -IODevice::~IODevice() -{ -} - -const char* IODevice::error_string() const -{ - return strerror(m_error); -} - -int IODevice::read(u8* buffer, int length) -{ - auto read_buffer = read(length); - if (read_buffer.is_null()) - return 0; - memcpy(buffer, read_buffer.data(), length); - return read_buffer.size(); -} - -ByteBuffer IODevice::read(size_t max_size) -{ - if (m_fd < 0) - return {}; - if (!max_size) - return {}; - auto buffer = ByteBuffer::create_uninitialized(max_size); - auto* buffer_ptr = (char*)buffer.data(); - size_t remaining_buffer_space = buffer.size(); - size_t taken_from_buffered = 0; - if (!m_buffered_data.is_empty()) { - taken_from_buffered = min(remaining_buffer_space, m_buffered_data.size()); - memcpy(buffer_ptr, m_buffered_data.data(), taken_from_buffered); - Vector<u8> new_buffered_data; - new_buffered_data.append(m_buffered_data.data() + taken_from_buffered, m_buffered_data.size() - taken_from_buffered); - m_buffered_data = move(new_buffered_data); - remaining_buffer_space -= taken_from_buffered; - buffer_ptr += taken_from_buffered; - } - if (!remaining_buffer_space) - return buffer; - int nread = ::read(m_fd, buffer_ptr, remaining_buffer_space); - if (nread < 0) { - if (taken_from_buffered) { - buffer.trim(taken_from_buffered); - return buffer; - } - set_error(errno); - return {}; - } - if (nread == 0) { - set_eof(true); - if (taken_from_buffered) { - buffer.trim(taken_from_buffered); - return buffer; - } - return {}; - } - buffer.trim(taken_from_buffered + nread); - return buffer; -} - -bool IODevice::can_read_from_fd() const -{ - // FIXME: Can we somehow remove this once Core::Socket is implemented using non-blocking sockets? - fd_set rfds; - FD_ZERO(&rfds); - FD_SET(m_fd, &rfds); - struct timeval timeout { - 0, 0 - }; - int rc = Core::safe_syscall(select, m_fd + 1, &rfds, nullptr, nullptr, &timeout); - if (rc < 0) { - // NOTE: We don't set m_error here. - perror("IODevice::can_read: select"); - return false; - } - return FD_ISSET(m_fd, &rfds); -} - -bool IODevice::can_read_line() const -{ - if (m_eof && !m_buffered_data.is_empty()) - return true; - if (m_buffered_data.contains_slow('\n')) - return true; - if (!can_read_from_fd()) - return false; - populate_read_buffer(); - if (m_eof && !m_buffered_data.is_empty()) - return true; - return m_buffered_data.contains_slow('\n'); -} - -bool IODevice::can_read() const -{ - return !m_buffered_data.is_empty() || can_read_from_fd(); -} - -ByteBuffer IODevice::read_all() -{ - off_t file_size = 0; - struct stat st; - int rc = fstat(fd(), &st); - if (rc == 0) - file_size = st.st_size; - - Vector<u8> data; - data.ensure_capacity(file_size); - - if (!m_buffered_data.is_empty()) { - data.append(m_buffered_data.data(), m_buffered_data.size()); - m_buffered_data.clear(); - } - - while (true) { - char read_buffer[4096]; - int nread = ::read(m_fd, read_buffer, sizeof(read_buffer)); - if (nread < 0) { - set_error(errno); - break; - } - if (nread == 0) { - set_eof(true); - break; - } - data.append((const u8*)read_buffer, nread); - } - if (data.is_empty()) - return {}; - return ByteBuffer::copy(data.data(), data.size()); -} - -String IODevice::read_line(size_t max_size) -{ - if (m_fd < 0) - return {}; - if (!max_size) - return {}; - if (!can_read_line()) - return {}; - if (m_eof) { - if (m_buffered_data.size() > max_size) { - dbgprintf("IODevice::read_line: At EOF but there's more than max_size(%zu) buffered\n", max_size); - return {}; - } - auto line = String((const char*)m_buffered_data.data(), m_buffered_data.size(), Chomp); - m_buffered_data.clear(); - return line; - } - auto line = ByteBuffer::create_uninitialized(max_size + 1); - size_t line_index = 0; - while (line_index < max_size) { - u8 ch = m_buffered_data[line_index]; - line[line_index++] = ch; - if (ch == '\n') { - Vector<u8> new_buffered_data; - new_buffered_data.append(m_buffered_data.data() + line_index, m_buffered_data.size() - line_index); - m_buffered_data = move(new_buffered_data); - line.trim(line_index); - return String::copy(line, Chomp); - } - } - return {}; -} - -bool IODevice::populate_read_buffer() const -{ - if (m_fd < 0) - return false; - u8 buffer[1024]; - int nread = ::read(m_fd, buffer, sizeof(buffer)); - if (nread < 0) { - set_error(errno); - return false; - } - if (nread == 0) { - set_eof(true); - return false; - } - m_buffered_data.append(buffer, nread); - return true; -} - -bool IODevice::close() -{ - if (fd() < 0 || mode() == NotOpen) - return false; - int rc = ::close(fd()); - if (rc < 0) { - set_error(errno); - return false; - } - set_fd(-1); - set_mode(IODevice::NotOpen); - return true; -} - -bool IODevice::seek(i64 offset, SeekMode mode, off_t* pos) -{ - int m = SEEK_SET; - switch (mode) { - case SeekMode::SetPosition: - m = SEEK_SET; - break; - case SeekMode::FromCurrentPosition: - m = SEEK_CUR; - break; - case SeekMode::FromEndPosition: - m = SEEK_END; - break; - } - off_t rc = lseek(m_fd, offset, m); - if (rc < 0) { - set_error(errno); - if (pos) - *pos = -1; - return false; - } - m_buffered_data.clear(); - m_eof = false; - if (pos) - *pos = rc; - return true; -} - -bool IODevice::truncate(off_t size) -{ - int rc = ftruncate(m_fd, size); - if (rc < 0) { - set_error(errno); - return false; - } - return true; -} - -bool IODevice::write(const u8* data, int size) -{ - int rc = ::write(m_fd, data, size); - if (rc < 0) { - perror("IODevice::write: write"); - set_error(errno); - return false; - } - return rc == size; -} - -int IODevice::printf(const char* format, ...) -{ - va_list ap; - va_start(ap, format); - // FIXME: We're not propagating write() failures to client here! - int ret = printf_internal([this](char*&, char ch) { - write((const u8*)&ch, 1); - }, - nullptr, format, ap); - va_end(ap); - return ret; -} - -void IODevice::set_fd(int fd) -{ - if (m_fd == fd) - return; - - m_fd = fd; - did_update_fd(fd); -} - -bool IODevice::write(const StringView& v) -{ - return write((const u8*)v.characters_without_null_termination(), v.length()); -} - -LineIterator::LineIterator(IODevice& device, bool is_end) - : m_device(device) - , m_is_end(is_end) -{ - ++*this; -} - -bool LineIterator::at_end() const -{ - return m_device->eof(); -} - -LineIterator& LineIterator::operator++() -{ - m_buffer = m_device->read_line(); - return *this; -} - -} diff --git a/Libraries/LibCore/IODevice.h b/Libraries/LibCore/IODevice.h deleted file mode 100644 index 70a75532a1..0000000000 --- a/Libraries/LibCore/IODevice.h +++ /dev/null @@ -1,133 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Forward.h> -#include <LibCore/Object.h> - -namespace Core { - -// This is not necessarily a valid iterator in all contexts, -// if we had concepts, this would be InputIterator, not Copyable, Movable. -class LineIterator { - AK_MAKE_NONCOPYABLE(LineIterator); - -public: - explicit LineIterator(IODevice&, bool is_end = false); - - bool operator==(const LineIterator& other) const { return &other == this || (at_end() && other.is_end()) || (other.at_end() && is_end()); } - bool is_end() const { return m_is_end; } - bool at_end() const; - - LineIterator& operator++(); - - StringView operator*() const { return m_buffer; } - -private: - NonnullRefPtr<IODevice> m_device; - bool m_is_end { false }; - String m_buffer; -}; - -class IODevice : public Object { - C_OBJECT_ABSTRACT(IODevice) -public: - enum OpenMode { - NotOpen = 0, - ReadOnly = 1, - WriteOnly = 2, - ReadWrite = 3, - Append = 4, - Truncate = 8, - MustBeNew = 16, - }; - - virtual ~IODevice() override; - - int fd() const { return m_fd; } - unsigned mode() const { return m_mode; } - bool is_open() const { return m_mode != NotOpen; } - bool eof() const { return m_eof; } - - int error() const { return m_error; } - const char* error_string() const; - - bool has_error() const { return m_error != 0; } - - int read(u8* buffer, int length); - - ByteBuffer read(size_t max_size); - ByteBuffer read_all(); - String read_line(size_t max_size = 16384); - - bool write(const u8*, int size); - bool write(const StringView&); - - bool truncate(off_t); - - bool can_read_line() const; - - bool can_read() const; - - enum class SeekMode { - SetPosition, - FromCurrentPosition, - FromEndPosition, - }; - - bool seek(i64, SeekMode = SeekMode::SetPosition, off_t* = nullptr); - - virtual bool open(IODevice::OpenMode) = 0; - virtual bool close(); - - int printf(const char*, ...); - - LineIterator line_begin() & { return LineIterator(*this); } - LineIterator line_end() { return LineIterator(*this, true); } - -protected: - explicit IODevice(Object* parent = nullptr); - - void set_fd(int); - void set_mode(OpenMode mode) { m_mode = mode; } - void set_error(int error) const { m_error = error; } - void set_eof(bool eof) const { m_eof = eof; } - - virtual void did_update_fd(int) { } - -private: - bool populate_read_buffer() const; - bool can_read_from_fd() const; - - int m_fd { -1 }; - OpenMode m_mode { NotOpen }; - mutable int m_error { 0 }; - mutable bool m_eof { false }; - mutable Vector<u8> m_buffered_data; -}; - -} diff --git a/Libraries/LibCore/IODeviceStreamReader.h b/Libraries/LibCore/IODeviceStreamReader.h deleted file mode 100644 index 0339c30272..0000000000 --- a/Libraries/LibCore/IODeviceStreamReader.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/StdLibExtras.h> -#include <LibCore/IODevice.h> - -namespace Core { - -class IODeviceStreamReader { -public: - IODeviceStreamReader(IODevice& device) - : m_device(device) - { - } - - bool handle_read_failure() - { - return exchange(m_had_failure, false); - } - - template<typename T> - IODeviceStreamReader& operator>>(T& value) - { - int nread = m_device.read((u8*)&value, sizeof(T)); - ASSERT(nread == sizeof(T)); - if (nread != sizeof(T)) - m_had_failure = true; - return *this; - } - -private: - IODevice& m_device; - bool m_had_failure { false }; -}; - -} diff --git a/Libraries/LibCore/LocalServer.cpp b/Libraries/LibCore/LocalServer.cpp deleted file mode 100644 index 092cf82388..0000000000 --- a/Libraries/LibCore/LocalServer.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/LocalServer.h> -#include <LibCore/LocalSocket.h> -#include <LibCore/Notifier.h> -#include <stdio.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <unistd.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif - -namespace Core { - -LocalServer::LocalServer(Object* parent) - : Object(parent) -{ -} - -LocalServer::~LocalServer() -{ - if (m_fd >= 0) - ::close(m_fd); -} - -bool LocalServer::take_over_from_system_server() -{ - if (m_listening) - return false; - - constexpr auto socket_takeover = "SOCKET_TAKEOVER"; - - if (getenv(socket_takeover)) { - // Sanity check: it has to be a socket. - struct stat stat; - int rc = fstat(3, &stat); - if (rc == 0 && S_ISSOCK(stat.st_mode)) { - // The SystemServer has passed us the socket as fd 3, - // so use that instead of creating our own. - m_fd = 3; - // It had to be !CLOEXEC for obvious reasons, but we - // don't need it to be !CLOEXEC anymore, so set the - // CLOEXEC flag now. - fcntl(m_fd, F_SETFD, FD_CLOEXEC); - // We wouldn't want our children to think we're passing - // them a socket either, so unset the env variable. - unsetenv(socket_takeover); - - m_listening = true; - setup_notifier(); - return true; - } else { - if (rc != 0) - perror("fstat"); - dbgln("It's not a socket, what the heck??"); - } - } - - dbgln("Failed to take the socket over from SystemServer"); - - return false; -} - -void LocalServer::setup_notifier() -{ - m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); - m_notifier->on_ready_to_read = [this] { - if (on_ready_to_accept) - on_ready_to_accept(); - }; -} - -bool LocalServer::listen(const String& address) -{ - if (m_listening) - return false; - - int rc; - -#ifdef SOCK_NONBLOCK - m_fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); -#else - m_fd = socket(AF_LOCAL, SOCK_STREAM, 0); - int option = 1; - ioctl(m_fd, FIONBIO, &option); - fcntl(m_fd, F_SETFD, FD_CLOEXEC); -#endif - ASSERT(m_fd >= 0); -#ifndef __APPLE__ - rc = fchmod(m_fd, 0600); - if (rc < 0) { - perror("fchmod"); - ASSERT_NOT_REACHED(); - } -#endif - - auto socket_address = SocketAddress::local(address); - auto un_optional = socket_address.to_sockaddr_un(); - if (!un_optional.has_value()) { - perror("bind"); - return false; - } - auto un = un_optional.value(); - rc = ::bind(m_fd, (const sockaddr*)&un, sizeof(un)); - if (rc < 0) { - perror("bind"); - return false; - } - - rc = ::listen(m_fd, 5); - if (rc < 0) { - perror("listen"); - return false; - } - - m_listening = true; - setup_notifier(); - return true; -} - -RefPtr<LocalSocket> LocalServer::accept() -{ - ASSERT(m_listening); - sockaddr_un un; - socklen_t un_size = sizeof(un); - int accepted_fd = ::accept(m_fd, (sockaddr*)&un, &un_size); - if (accepted_fd < 0) { - perror("accept"); - return nullptr; - } - - return LocalSocket::construct(accepted_fd); -} - -} diff --git a/Libraries/LibCore/LocalServer.h b/Libraries/LibCore/LocalServer.h deleted file mode 100644 index bcb4fa6c00..0000000000 --- a/Libraries/LibCore/LocalServer.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibCore/Notifier.h> -#include <LibCore/Object.h> - -namespace Core { - -class LocalServer : public Object { - C_OBJECT(LocalServer) -public: - virtual ~LocalServer() override; - - bool take_over_from_system_server(); - bool is_listening() const { return m_listening; } - bool listen(const String& address); - - RefPtr<LocalSocket> accept(); - - Function<void()> on_ready_to_accept; - -private: - explicit LocalServer(Object* parent = nullptr); - - void setup_notifier(); - - int m_fd { -1 }; - bool m_listening { false }; - RefPtr<Notifier> m_notifier; -}; - -} diff --git a/Libraries/LibCore/LocalSocket.cpp b/Libraries/LibCore/LocalSocket.cpp deleted file mode 100644 index d49aa1d166..0000000000 --- a/Libraries/LibCore/LocalSocket.cpp +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/LocalSocket.h> -#include <errno.h> -#include <stdio.h> -#include <sys/socket.h> -#include <sys/stat.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif - -namespace Core { - -LocalSocket::LocalSocket(int fd, Object* parent) - : Socket(Socket::Type::Local, parent) -{ - // NOTE: This constructor is used by LocalServer::accept(), so the socket is already connected. - m_connected = true; - set_fd(fd); - set_mode(IODevice::ReadWrite); - set_error(0); -} - -LocalSocket::LocalSocket(Object* parent) - : Socket(Socket::Type::Local, parent) -{ - -#ifdef SOCK_NONBLOCK - int fd = socket(AF_LOCAL, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); -#else - int fd = socket(AF_LOCAL, SOCK_STREAM, 0); - int option = 1; - ioctl(fd, FIONBIO, &option); - fcntl(fd, F_SETFD, FD_CLOEXEC); -#endif - - if (fd < 0) { - set_error(errno); - } else { - set_fd(fd); - set_mode(IODevice::ReadWrite); - set_error(0); - } -} - -LocalSocket::~LocalSocket() -{ -} - -RefPtr<LocalSocket> LocalSocket::take_over_accepted_socket_from_system_server() -{ - constexpr auto socket_takeover = "SOCKET_TAKEOVER"; - if (!getenv(socket_takeover)) - return nullptr; - - // The SystemServer has passed us the socket as fd 3, - // so use that instead of creating our own. - constexpr int fd = 3; - - // Sanity check: it has to be a socket. - struct stat stat; - int rc = fstat(fd, &stat); - if (rc < 0 || !S_ISSOCK(stat.st_mode)) { - if (rc != 0) - perror("fstat"); - dbgln("ERROR: The fd we got from SystemServer is not a socket"); - return nullptr; - } - - auto socket = LocalSocket::construct(fd); - - // It had to be !CLOEXEC for obvious reasons, but we - // don't need it to be !CLOEXEC anymore, so set the - // CLOEXEC flag now. - fcntl(fd, F_SETFD, FD_CLOEXEC); - // We wouldn't want our children to think we're passing - // them a socket either, so unset the env variable. - unsetenv(socket_takeover); - return socket; -} - -} diff --git a/Libraries/LibCore/LocalSocket.h b/Libraries/LibCore/LocalSocket.h deleted file mode 100644 index 921e16aaa2..0000000000 --- a/Libraries/LibCore/LocalSocket.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibCore/Socket.h> - -namespace Core { - -class LocalSocket final : public Socket { - C_OBJECT(LocalSocket) -public: - virtual ~LocalSocket() override; - - static RefPtr<LocalSocket> take_over_accepted_socket_from_system_server(); - -private: - explicit LocalSocket(Object* parent = nullptr); - LocalSocket(int fd, Object* parent = nullptr); -}; - -} diff --git a/Libraries/LibCore/MimeData.cpp b/Libraries/LibCore/MimeData.cpp deleted file mode 100644 index e48908661c..0000000000 --- a/Libraries/LibCore/MimeData.cpp +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/StringBuilder.h> -#include <LibCore/MimeData.h> - -namespace Core { - -Vector<String> MimeData::formats() const -{ - Vector<String> mime_types; - mime_types.ensure_capacity(m_data.size()); - for (auto it : m_data) - mime_types.unchecked_append(it.key); - return mime_types; -} - -Vector<URL> MimeData::urls() const -{ - auto it = m_data.find("text/uri-list"); - if (it == m_data.end()) - return {}; - Vector<URL> urls; - for (auto& line : StringView(it->value).split_view('\n')) { - urls.append(URL(line)); - } - return urls; -} - -void MimeData::set_urls(const Vector<URL>& urls) -{ - StringBuilder builder; - for (auto& url : urls) { - builder.append(url.to_string()); - builder.append('\n'); - } - set_data("text/uri-list", builder.to_byte_buffer()); -} - -String MimeData::text() const -{ - return String::copy(m_data.get("text/plain").value_or({})); -} - -void MimeData::set_text(const String& text) -{ - set_data("text/plain", text.to_byte_buffer()); -} - -String guess_mime_type_based_on_filename(const StringView& path) -{ - if (path.ends_with(".pbm", CaseSensitivity::CaseInsensitive)) - return "image/x‑portable‑bitmap"; - if (path.ends_with(".pgm", CaseSensitivity::CaseInsensitive)) - return "image/x‑portable‑graymap"; - if (path.ends_with(".png", CaseSensitivity::CaseInsensitive)) - return "image/png"; - if (path.ends_with(".ppm", CaseSensitivity::CaseInsensitive)) - return "image/x‑portable‑pixmap"; - if (path.ends_with(".gif", CaseSensitivity::CaseInsensitive)) - return "image/gif"; - if (path.ends_with(".bmp", CaseSensitivity::CaseInsensitive)) - return "image/bmp"; - if (path.ends_with(".jpg", CaseSensitivity::CaseInsensitive) || path.ends_with(".jpeg", CaseSensitivity::CaseInsensitive)) - return "image/jpeg"; - if (path.ends_with(".svg", CaseSensitivity::CaseInsensitive)) - return "image/svg+xml"; - if (path.ends_with(".md", CaseSensitivity::CaseInsensitive)) - return "text/markdown"; - if (path.ends_with(".html", CaseSensitivity::CaseInsensitive) || path.ends_with(".htm", CaseSensitivity::CaseInsensitive)) - return "text/html"; - if (path.ends_with("/", CaseSensitivity::CaseInsensitive)) - return "text/html"; - if (path.ends_with(".csv", CaseSensitivity::CaseInsensitive)) - return "text/csv"; - return "text/plain"; -} - -} diff --git a/Libraries/LibCore/MimeData.h b/Libraries/LibCore/MimeData.h deleted file mode 100644 index fe575ab675..0000000000 --- a/Libraries/LibCore/MimeData.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/ByteBuffer.h> -#include <AK/HashMap.h> -#include <AK/URL.h> -#include <LibCore/Object.h> - -namespace Core { - -class MimeData : public Object { - C_OBJECT(MimeData); - -public: - virtual ~MimeData() { } - - ByteBuffer data(const String& mime_type) const { return m_data.get(mime_type).value_or({}); } - void set_data(const String& mime_type, const ByteBuffer& data) { m_data.set(mime_type, data); } - - bool has_format(const String& mime_type) const { return m_data.contains(mime_type); } - Vector<String> formats() const; - - // Convenience helpers for "text/plain" - bool has_text() const { return has_format("text/plain"); } - String text() const; - void set_text(const String&); - - // Convenience helpers for "text/uri-list" - bool has_urls() const { return has_format("text/uri-list"); } - Vector<URL> urls() const; - void set_urls(const Vector<URL>&); - - const HashMap<String, ByteBuffer>& all_data() const { return m_data; } - -private: - MimeData() { } - explicit MimeData(const HashMap<String, ByteBuffer>& data) - : m_data(data) - { - } - - HashMap<String, ByteBuffer> m_data; -}; - -String guess_mime_type_based_on_filename(const StringView&); - -} diff --git a/Libraries/LibCore/NetworkJob.cpp b/Libraries/LibCore/NetworkJob.cpp deleted file mode 100644 index 0b48a93a72..0000000000 --- a/Libraries/LibCore/NetworkJob.cpp +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/NetworkJob.h> -#include <LibCore/NetworkResponse.h> -#include <stdio.h> - -//#define CNETWORKJOB_DEBUG - -namespace Core { - -NetworkJob::NetworkJob(OutputStream& output_stream) - : m_output_stream(output_stream) -{ -} - -NetworkJob::~NetworkJob() -{ -} - -void NetworkJob::start() -{ -} - -void NetworkJob::shutdown() -{ -} - -void NetworkJob::did_finish(NonnullRefPtr<NetworkResponse>&& response) -{ - // NOTE: We protect ourselves here, since the on_finish callback may otherwise - // trigger destruction of this job somehow. - NonnullRefPtr<NetworkJob> protector(*this); - - m_response = move(response); -#ifdef CNETWORKJOB_DEBUG - dbg() << *this << " job did_finish!"; -#endif - ASSERT(on_finish); - on_finish(true); - shutdown(); -} - -void NetworkJob::did_fail(Error error) -{ - // NOTE: We protect ourselves here, since the on_finish callback may otherwise - // trigger destruction of this job somehow. - NonnullRefPtr<NetworkJob> protector(*this); - - m_error = error; -#ifdef CNETWORKJOB_DEBUG - dbgprintf("%s{%p} job did_fail! error: %u (%s)\n", class_name(), this, (unsigned)error, to_string(error)); -#endif - ASSERT(on_finish); - on_finish(false); - shutdown(); -} - -void NetworkJob::did_progress(Optional<u32> total_size, u32 downloaded) -{ - // NOTE: We protect ourselves here, since the callback may otherwise - // trigger destruction of this job somehow. - NonnullRefPtr<NetworkJob> protector(*this); - - if (on_progress) - on_progress(total_size, downloaded); -} - -const char* to_string(NetworkJob::Error error) -{ - switch (error) { - case NetworkJob::Error::ProtocolFailed: - return "ProtocolFailed"; - case NetworkJob::Error::ConnectionFailed: - return "ConnectionFailed"; - case NetworkJob::Error::TransmissionFailed: - return "TransmissionFailed"; - case NetworkJob::Error::Cancelled: - return "Cancelled"; - default: - return "(Unknown error)"; - } -} - -} diff --git a/Libraries/LibCore/NetworkJob.h b/Libraries/LibCore/NetworkJob.h deleted file mode 100644 index 94ead44805..0000000000 --- a/Libraries/LibCore/NetworkJob.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/Stream.h> -#include <LibCore/Object.h> - -namespace Core { - -class NetworkJob : public Object { - C_OBJECT_ABSTRACT(NetworkJob) -public: - enum class Error { - None, - ConnectionFailed, - TransmissionFailed, - ProtocolFailed, - Cancelled, - }; - virtual ~NetworkJob() override; - - // Could fire twice, after Headers and after Trailers! - Function<void(const HashMap<String, String, CaseInsensitiveStringTraits>& response_headers, Optional<u32> response_code)> on_headers_received; - Function<void(bool success)> on_finish; - Function<void(Optional<u32>, u32)> on_progress; - - bool is_cancelled() const { return m_error == Error::Cancelled; } - bool has_error() const { return m_error != Error::None; } - Error error() const { return m_error; } - NetworkResponse* response() { return m_response.ptr(); } - const NetworkResponse* response() const { return m_response.ptr(); } - - virtual void start() = 0; - virtual void shutdown() = 0; - - void cancel() - { - shutdown(); - m_error = Error::Cancelled; - } - -protected: - NetworkJob(OutputStream&); - void did_finish(NonnullRefPtr<NetworkResponse>&&); - void did_fail(Error); - void did_progress(Optional<u32> total_size, u32 downloaded); - - size_t do_write(ReadonlyBytes bytes) { return m_output_stream.write(bytes); } - -private: - RefPtr<NetworkResponse> m_response; - OutputStream& m_output_stream; - Error m_error { Error::None }; -}; - -const char* to_string(NetworkJob::Error); - -} diff --git a/Libraries/LibCore/NetworkResponse.cpp b/Libraries/LibCore/NetworkResponse.cpp deleted file mode 100644 index ebaf7eff7d..0000000000 --- a/Libraries/LibCore/NetworkResponse.cpp +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/NetworkResponse.h> - -namespace Core { - -NetworkResponse::NetworkResponse() -{ -} - -NetworkResponse::~NetworkResponse() -{ -} - -} diff --git a/Libraries/LibCore/NetworkResponse.h b/Libraries/LibCore/NetworkResponse.h deleted file mode 100644 index d2ff33a569..0000000000 --- a/Libraries/LibCore/NetworkResponse.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/ByteBuffer.h> -#include <AK/RefCounted.h> - -namespace Core { - -class NetworkResponse : public RefCounted<NetworkResponse> { -public: - virtual ~NetworkResponse(); - - bool is_error() const { return m_error; } - -protected: - explicit NetworkResponse(); - - bool m_error { false }; -}; - -} diff --git a/Libraries/LibCore/Notifier.cpp b/Libraries/LibCore/Notifier.cpp deleted file mode 100644 index 655a73ed1b..0000000000 --- a/Libraries/LibCore/Notifier.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Badge.h> -#include <LibCore/Event.h> -#include <LibCore/EventLoop.h> -#include <LibCore/Notifier.h> - -namespace Core { - -Notifier::Notifier(int fd, unsigned event_mask, Object* parent) - : Object(parent) - , m_fd(fd) - , m_event_mask(event_mask) -{ - set_enabled(true); -} - -Notifier::~Notifier() -{ - set_enabled(false); -} - -void Notifier::set_enabled(bool enabled) -{ - if (m_fd < 0) - return; - if (enabled) - Core::EventLoop::register_notifier({}, *this); - else - Core::EventLoop::unregister_notifier({}, *this); -} - -void Notifier::close() -{ - if (m_fd < 0) - return; - set_enabled(false); - m_fd = -1; -} - -void Notifier::event(Core::Event& event) -{ - if (event.type() == Core::Event::NotifierRead && on_ready_to_read) { - on_ready_to_read(); - } else if (event.type() == Core::Event::NotifierWrite && on_ready_to_write) { - on_ready_to_write(); - } else { - Object::event(event); - } -} - -} diff --git a/Libraries/LibCore/Notifier.h b/Libraries/LibCore/Notifier.h deleted file mode 100644 index b197b55204..0000000000 --- a/Libraries/LibCore/Notifier.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <LibCore/Object.h> - -namespace Core { - -class Notifier : public Object { - C_OBJECT(Notifier) -public: - enum Event { - None = 0, - Read = 1, - Write = 2, - Exceptional = 4, - }; - - virtual ~Notifier() override; - - void set_enabled(bool); - - Function<void()> on_ready_to_read; - Function<void()> on_ready_to_write; - - void close(); - - int fd() const { return m_fd; } - unsigned event_mask() const { return m_event_mask; } - void set_event_mask(unsigned event_mask) { m_event_mask = event_mask; } - - void event(Core::Event&) override; - -private: - Notifier(int fd, unsigned event_mask, Object* parent = nullptr); - - int m_fd { -1 }; - unsigned m_event_mask { 0 }; -}; - -} diff --git a/Libraries/LibCore/Object.cpp b/Libraries/LibCore/Object.cpp deleted file mode 100644 index 55cd102409..0000000000 --- a/Libraries/LibCore/Object.cpp +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/Assertions.h> -#include <AK/Badge.h> -#include <AK/JsonObject.h> -#include <LibCore/Event.h> -#include <LibCore/EventLoop.h> -#include <LibCore/Object.h> -#include <stdio.h> - -namespace Core { - -IntrusiveList<Object, &Object::m_all_objects_list_node>& Object::all_objects() -{ - static IntrusiveList<Object, &Object::m_all_objects_list_node> objects; - return objects; -} - -Object::Object(Object* parent) - : m_parent(parent) -{ - all_objects().append(*this); - if (m_parent) - m_parent->add_child(*this); - - REGISTER_READONLY_STRING_PROPERTY("class_name", class_name); - REGISTER_STRING_PROPERTY("name", name, set_name); - - register_property( - "address", [this] { return FlatPtr(this); }, - [](auto&) { return false; }); - - register_property( - "parent", [this] { return FlatPtr(this->parent()); }, - [](auto&) { return false; }); -} - -Object::~Object() -{ - // NOTE: We move our children out to a stack vector to prevent other - // code from trying to iterate over them. - auto children = move(m_children); - // NOTE: We also unparent the children, so that they won't try to unparent - // themselves in their own destructors. - for (auto& child : children) - child.m_parent = nullptr; - - all_objects().remove(*this); - stop_timer(); - if (m_parent) - m_parent->remove_child(*this); -} - -void Object::event(Core::Event& event) -{ - switch (event.type()) { - case Core::Event::Timer: - return timer_event(static_cast<TimerEvent&>(event)); - case Core::Event::ChildAdded: - case Core::Event::ChildRemoved: - return child_event(static_cast<ChildEvent&>(event)); - case Core::Event::Invalid: - ASSERT_NOT_REACHED(); - break; - case Core::Event::Custom: - return custom_event(static_cast<CustomEvent&>(event)); - default: - break; - } -} - -void Object::add_child(Object& object) -{ - // FIXME: Should we support reparenting objects? - ASSERT(!object.parent() || object.parent() == this); - object.m_parent = this; - m_children.append(object); - Core::ChildEvent child_event(Core::Event::ChildAdded, object); - event(child_event); -} - -void Object::insert_child_before(Object& new_child, Object& before_child) -{ - // FIXME: Should we support reparenting objects? - ASSERT(!new_child.parent() || new_child.parent() == this); - new_child.m_parent = this; - m_children.insert_before_matching(new_child, [&](auto& existing_child) { return existing_child.ptr() == &before_child; }); - Core::ChildEvent child_event(Core::Event::ChildAdded, new_child, &before_child); - event(child_event); -} - -void Object::remove_child(Object& object) -{ - for (size_t i = 0; i < m_children.size(); ++i) { - if (m_children.ptr_at(i).ptr() == &object) { - // NOTE: We protect the child so it survives the handling of ChildRemoved. - NonnullRefPtr<Object> protector = object; - object.m_parent = nullptr; - m_children.remove(i); - Core::ChildEvent child_event(Core::Event::ChildRemoved, object); - event(child_event); - return; - } - } - ASSERT_NOT_REACHED(); -} - -void Object::remove_all_children() -{ - while (!m_children.is_empty()) - m_children.first().remove_from_parent(); -} - -void Object::timer_event(Core::TimerEvent&) -{ -} - -void Object::child_event(Core::ChildEvent&) -{ -} - -void Object::custom_event(CustomEvent&) -{ -} - -void Object::start_timer(int ms, TimerShouldFireWhenNotVisible fire_when_not_visible) -{ - if (m_timer_id) { - dbgln("{} {:p} already has a timer!", class_name(), this); - ASSERT_NOT_REACHED(); - } - - m_timer_id = Core::EventLoop::register_timer(*this, ms, true, fire_when_not_visible); -} - -void Object::stop_timer() -{ - if (!m_timer_id) - return; - bool success = Core::EventLoop::unregister_timer(m_timer_id); - ASSERT(success); - m_timer_id = 0; -} - -void Object::dump_tree(int indent) -{ - for (int i = 0; i < indent; ++i) { - printf(" "); - } - printf("%s{%p}", class_name(), this); - if (!name().is_null()) - printf(" %s", name().characters()); - printf("\n"); - - for_each_child([&](auto& child) { - child.dump_tree(indent + 2); - return IterationDecision::Continue; - }); -} - -void Object::deferred_invoke(Function<void(Object&)> invokee) -{ - Core::EventLoop::current().post_event(*this, make<Core::DeferredInvocationEvent>(move(invokee))); -} - -void Object::save_to(JsonObject& json) -{ - for (auto& it : m_properties) { - auto& property = it.value; - json.set(property->name(), property->get()); - } -} - -JsonValue Object::property(const StringView& name) const -{ - auto it = m_properties.find(name); - if (it == m_properties.end()) - return JsonValue(); - return it->value->get(); -} - -bool Object::set_property(const StringView& name, const JsonValue& value) -{ - auto it = m_properties.find(name); - if (it == m_properties.end()) - return false; - return it->value->set(value); -} - -bool Object::is_ancestor_of(const Object& other) const -{ - if (&other == this) - return false; - for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) { - if (ancestor == this) - return true; - } - return false; -} - -void Object::dispatch_event(Core::Event& e, Object* stay_within) -{ - ASSERT(!stay_within || stay_within == this || stay_within->is_ancestor_of(*this)); - auto* target = this; - do { - target->event(e); - target = target->parent(); - if (target == stay_within) { - // Prevent the event from bubbling any further. - return; - } - } while (target && !e.is_accepted()); -} - -bool Object::is_visible_for_timer_purposes() const -{ - if (parent()) - return parent()->is_visible_for_timer_purposes(); - return true; -} - -void Object::increment_inspector_count(Badge<RPCClient>) -{ - ++m_inspector_count; - if (m_inspector_count == 1) - did_begin_inspection(); -} - -void Object::decrement_inspector_count(Badge<RPCClient>) -{ - --m_inspector_count; - if (!m_inspector_count) - did_end_inspection(); -} - -void Object::register_property(const String& name, Function<JsonValue()> getter, Function<bool(const JsonValue&)> setter) -{ - m_properties.set(name, make<Property>(name, move(getter), move(setter))); -} - -const LogStream& operator<<(const LogStream& stream, const Object& object) -{ - return stream << object.class_name() << '{' << &object << '}'; -} - -} diff --git a/Libraries/LibCore/Object.h b/Libraries/LibCore/Object.h deleted file mode 100644 index 9270d347d0..0000000000 --- a/Libraries/LibCore/Object.h +++ /dev/null @@ -1,346 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Forward.h> -#include <AK/HashMap.h> -#include <AK/IntrusiveList.h> -#include <AK/Noncopyable.h> -#include <AK/NonnullRefPtrVector.h> -#include <AK/String.h> -#include <AK/TypeCasts.h> -#include <AK/Weakable.h> -#include <LibCore/Forward.h> -#include <LibCore/Property.h> - -namespace Core { - -class RPCClient; - -enum class TimerShouldFireWhenNotVisible { - No = 0, - Yes -}; - -#define C_OBJECT(klass) \ -public: \ - virtual const char* class_name() const override { return #klass; } \ - template<class... Args> \ - static inline NonnullRefPtr<klass> construct(Args&&... args) \ - { \ - return adopt(*new klass(forward<Args>(args)...)); \ - } - -#define C_OBJECT_ABSTRACT(klass) \ -public: \ - virtual const char* class_name() const override { return #klass; } - -class Object - : public RefCounted<Object> - , public Weakable<Object> { - // NOTE: No C_OBJECT macro for Core::Object itself. - - AK_MAKE_NONCOPYABLE(Object); - AK_MAKE_NONMOVABLE(Object); - - IntrusiveListNode m_all_objects_list_node; - -public: - virtual ~Object(); - - virtual const char* class_name() const = 0; - virtual void event(Core::Event&); - - const String& name() const { return m_name; } - void set_name(const StringView& name) { m_name = name; } - - NonnullRefPtrVector<Object>& children() { return m_children; } - const NonnullRefPtrVector<Object>& children() const { return m_children; } - - template<typename Callback> - void for_each_child(Callback callback) - { - for (auto& child : m_children) { - if (callback(child) == IterationDecision::Break) - return; - } - } - - template<typename T, typename Callback> - void for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T>::value; - - template<typename T> - T* find_child_of_type_named(const String&) requires IsBaseOf<Object, T>::value; - - template<typename T> - T* find_descendant_of_type_named(const String&) requires IsBaseOf<Object, T>::value; - - bool is_ancestor_of(const Object&) const; - - Object* parent() { return m_parent; } - const Object* parent() const { return m_parent; } - - void start_timer(int ms, TimerShouldFireWhenNotVisible = TimerShouldFireWhenNotVisible::No); - void stop_timer(); - bool has_timer() const { return m_timer_id; } - - void add_child(Object&); - void insert_child_before(Object& new_child, Object& before_child); - void remove_child(Object&); - void remove_all_children(); - - void dump_tree(int indent = 0); - - void deferred_invoke(Function<void(Object&)>); - - void save_to(AK::JsonObject&); - - bool set_property(const StringView& name, const JsonValue& value); - JsonValue property(const StringView& name) const; - const HashMap<String, NonnullOwnPtr<Property>>& properties() const { return m_properties; } - - static IntrusiveList<Object, &Object::m_all_objects_list_node>& all_objects(); - - void dispatch_event(Core::Event&, Object* stay_within = nullptr); - - void remove_from_parent() - { - if (m_parent) - m_parent->remove_child(*this); - } - - template<class T, class... Args> - inline T& add(Args&&... args) - { - auto child = T::construct(forward<Args>(args)...); - add_child(*child); - return child; - } - - virtual bool is_visible_for_timer_purposes() const; - - bool is_being_inspected() const { return m_inspector_count; } - - void increment_inspector_count(Badge<RPCClient>); - void decrement_inspector_count(Badge<RPCClient>); - -protected: - explicit Object(Object* parent = nullptr); - - void register_property(const String& name, Function<JsonValue()> getter, Function<bool(const JsonValue&)> setter = nullptr); - - virtual void timer_event(TimerEvent&); - virtual void custom_event(CustomEvent&); - - // NOTE: You may get child events for children that are not yet fully constructed! - virtual void child_event(ChildEvent&); - - virtual void did_begin_inspection() { } - virtual void did_end_inspection() { } - -private: - Object* m_parent { nullptr }; - String m_name; - int m_timer_id { 0 }; - unsigned m_inspector_count { 0 }; - HashMap<String, NonnullOwnPtr<Property>> m_properties; - NonnullRefPtrVector<Object> m_children; -}; - -} - -template<> -struct AK::Formatter<Core::Object> : AK::Formatter<FormatString> { - void format(FormatBuilder& builder, const Core::Object& value) - { - return AK::Formatter<FormatString>::format(builder, "{}({})", value.class_name(), &value); - } -}; - -namespace Core { -template<typename T, typename Callback> -inline void Object::for_each_child_of_type(Callback callback) requires IsBaseOf<Object, T>::value -{ - for_each_child([&](auto& child) { - if (auto* child_as_t = dynamic_cast<T*>(&child); child_as_t) - return callback(*child_as_t); - return IterationDecision::Continue; - }); -} - -template<typename T> -T* Object::find_child_of_type_named(const String& name) requires IsBaseOf<Object, T>::value -{ - T* found_child = nullptr; - for_each_child_of_type<T>([&](auto& child) { - if (child.name() == name) { - found_child = &child; - return IterationDecision::Break; - } - return IterationDecision::Continue; - }); - - return found_child; -} - -template<typename T> -T* Object::find_descendant_of_type_named(const String& name) requires IsBaseOf<Object, T>::value -{ - auto* this_as_t = dynamic_cast<T*>(this); - if (this_as_t && this->name() == name) - return this_as_t; - T* found_child = nullptr; - for_each_child([&](auto& child) { - found_child = child.template find_descendant_of_type_named<T>(name); - if (found_child) - return IterationDecision::Break; - return IterationDecision::Continue; - }); - return found_child; -} - -const LogStream& operator<<(const LogStream&, const Object&); - -#define REGISTER_INT_PROPERTY(property_name, getter, setter) \ - register_property( \ - property_name, \ - [this] { return this->getter(); }, \ - [this](auto& value) { \ - this->setter(value.template to_number<int>()); \ - return true; \ - }); - -#define REGISTER_BOOL_PROPERTY(property_name, getter, setter) \ - register_property( \ - property_name, \ - [this] { return this->getter(); }, \ - [this](auto& value) { \ - this->setter(value.to_bool()); \ - return true; \ - }); - -#define REGISTER_STRING_PROPERTY(property_name, getter, setter) \ - register_property( \ - property_name, \ - [this] { return this->getter(); }, \ - [this](auto& value) { \ - this->setter(value.to_string()); \ - return true; \ - }); - -#define REGISTER_READONLY_STRING_PROPERTY(property_name, getter) \ - register_property( \ - property_name, \ - [this] { return this->getter(); }, \ - {}); - -#define REGISTER_RECT_PROPERTY(property_name, getter, setter) \ - register_property( \ - property_name, \ - [this] { \ - auto rect = this->getter(); \ - JsonObject rect_object; \ - rect_object.set("x", rect.x()); \ - rect_object.set("y", rect.y()); \ - rect_object.set("width", rect.width()); \ - rect_object.set("height", rect.height()); \ - return rect_object; \ - }, \ - [this](auto& value) { \ - if (!value.is_object()) \ - return false; \ - Gfx::IntRect rect; \ - rect.set_x(value.as_object().get("x").to_i32()); \ - rect.set_y(value.as_object().get("y").to_i32()); \ - rect.set_width(value.as_object().get("width").to_i32()); \ - rect.set_height(value.as_object().get("height").to_i32()); \ - setter(rect); \ - return true; \ - }); - -#define REGISTER_SIZE_PROPERTY(property_name, getter, setter) \ - register_property( \ - property_name, \ - [this] { \ - auto size = this->getter(); \ - JsonObject size_object; \ - size_object.set("width", size.width()); \ - size_object.set("height", size.height()); \ - return size_object; \ - }, \ - [this](auto& value) { \ - if (!value.is_object()) \ - return false; \ - Gfx::IntSize size; \ - size.set_width(value.as_object().get("width").to_i32()); \ - size.set_height(value.as_object().get("height").to_i32()); \ - setter(size); \ - return true; \ - }); - -#define REGISTER_ENUM_PROPERTY(property_name, getter, setter, EnumType, ...) \ - register_property( \ - property_name, \ - [this]() -> JsonValue { \ - struct { \ - EnumType enum_value; \ - String string_value; \ - } options[] = { __VA_ARGS__ }; \ - auto enum_value = getter(); \ - for (size_t i = 0; i < array_size(options); ++i) { \ - auto& option = options[i]; \ - if (enum_value == option.enum_value) \ - return option.string_value; \ - } \ - return JsonValue(); \ - }, \ - [this](auto& value) { \ - struct { \ - EnumType enum_value; \ - String string_value; \ - } options[] = { __VA_ARGS__ }; \ - auto string_value = value.as_string(); \ - for (size_t i = 0; i < array_size(options); ++i) { \ - auto& option = options[i]; \ - if (string_value == option.string_value) { \ - setter(option.enum_value); \ - return true; \ - } \ - } \ - return false; \ - }) - -#define REGISTER_TEXT_ALIGNMENT_PROPERTY(property_name, getter, setter) \ - REGISTER_ENUM_PROPERTY( \ - property_name, getter, setter, Gfx::TextAlignment, \ - { Gfx::TextAlignment::TopLeft, "TopLeft" }, \ - { Gfx::TextAlignment::CenterLeft, "CenterLeft" }, \ - { Gfx::TextAlignment::Center, "Center" }, \ - { Gfx::TextAlignment::CenterRight, "CenterRight" }, \ - { Gfx::TextAlignment::TopRight, "TopRight" }, \ - { Gfx::TextAlignment::BottomRight, "BottomRight" }) -} diff --git a/Libraries/LibCore/ProcessStatisticsReader.cpp b/Libraries/LibCore/ProcessStatisticsReader.cpp deleted file mode 100644 index 566053d3af..0000000000 --- a/Libraries/LibCore/ProcessStatisticsReader.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/ByteBuffer.h> -#include <AK/JsonArray.h> -#include <AK/JsonObject.h> -#include <AK/JsonValue.h> -#include <LibCore/File.h> -#include <LibCore/ProcessStatisticsReader.h> -#include <pwd.h> -#include <stdio.h> - -namespace Core { - -HashMap<uid_t, String> ProcessStatisticsReader::s_usernames; - -Optional<HashMap<pid_t, Core::ProcessStatistics>> ProcessStatisticsReader::get_all(RefPtr<Core::File>& proc_all_file) -{ - if (proc_all_file) { - if (!proc_all_file->seek(0, Core::File::SeekMode::SetPosition)) { - fprintf(stderr, "ProcessStatisticsReader: Failed to refresh /proc/all: %s\n", proc_all_file->error_string()); - return {}; - } - } else { - proc_all_file = Core::File::construct("/proc/all"); - if (!proc_all_file->open(Core::IODevice::ReadOnly)) { - fprintf(stderr, "ProcessStatisticsReader: Failed to open /proc/all: %s\n", proc_all_file->error_string()); - return {}; - } - } - - HashMap<pid_t, Core::ProcessStatistics> map; - - auto file_contents = proc_all_file->read_all(); - auto json = JsonValue::from_string(file_contents); - if (!json.has_value()) - return {}; - json.value().as_array().for_each([&](auto& value) { - const JsonObject& process_object = value.as_object(); - Core::ProcessStatistics process; - - // kernel data first - process.pid = process_object.get("pid").to_u32(); - process.pgid = process_object.get("pgid").to_u32(); - process.pgp = process_object.get("pgp").to_u32(); - process.sid = process_object.get("sid").to_u32(); - process.uid = process_object.get("uid").to_u32(); - process.gid = process_object.get("gid").to_u32(); - process.ppid = process_object.get("ppid").to_u32(); - process.nfds = process_object.get("nfds").to_u32(); - process.name = process_object.get("name").to_string(); - process.executable = process_object.get("executable").to_string(); - process.tty = process_object.get("tty").to_string(); - process.pledge = process_object.get("pledge").to_string(); - process.veil = process_object.get("veil").to_string(); - process.amount_virtual = process_object.get("amount_virtual").to_u32(); - process.amount_resident = process_object.get("amount_resident").to_u32(); - process.amount_shared = process_object.get("amount_shared").to_u32(); - process.amount_dirty_private = process_object.get("amount_dirty_private").to_u32(); - process.amount_clean_inode = process_object.get("amount_clean_inode").to_u32(); - process.amount_purgeable_volatile = process_object.get("amount_purgeable_volatile").to_u32(); - process.amount_purgeable_nonvolatile = process_object.get("amount_purgeable_nonvolatile").to_u32(); - - auto& thread_array = process_object.get_ptr("threads")->as_array(); - process.threads.ensure_capacity(thread_array.size()); - thread_array.for_each([&](auto& value) { - auto& thread_object = value.as_object(); - Core::ThreadStatistics thread; - thread.tid = thread_object.get("tid").to_u32(); - thread.times_scheduled = thread_object.get("times_scheduled").to_u32(); - thread.name = thread_object.get("name").to_string(); - thread.state = thread_object.get("state").to_string(); - thread.ticks_user = thread_object.get("ticks_user").to_u32(); - thread.ticks_kernel = thread_object.get("ticks_kernel").to_u32(); - thread.cpu = thread_object.get("cpu").to_u32(); - thread.priority = thread_object.get("priority").to_u32(); - thread.effective_priority = thread_object.get("effective_priority").to_u32(); - thread.syscall_count = thread_object.get("syscall_count").to_u32(); - thread.inode_faults = thread_object.get("inode_faults").to_u32(); - thread.zero_faults = thread_object.get("zero_faults").to_u32(); - thread.cow_faults = thread_object.get("cow_faults").to_u32(); - thread.unix_socket_read_bytes = thread_object.get("unix_socket_read_bytes").to_u32(); - thread.unix_socket_write_bytes = thread_object.get("unix_socket_write_bytes").to_u32(); - thread.ipv4_socket_read_bytes = thread_object.get("ipv4_socket_read_bytes").to_u32(); - thread.ipv4_socket_write_bytes = thread_object.get("ipv4_socket_write_bytes").to_u32(); - thread.file_read_bytes = thread_object.get("file_read_bytes").to_u32(); - thread.file_write_bytes = thread_object.get("file_write_bytes").to_u32(); - process.threads.append(move(thread)); - }); - - // and synthetic data last - process.username = username_from_uid(process.uid); - map.set(process.pid, process); - }); - - return map; -} - -Optional<HashMap<pid_t, Core::ProcessStatistics>> ProcessStatisticsReader::get_all() -{ - RefPtr<Core::File> proc_all_file; - return get_all(proc_all_file); -} - -String ProcessStatisticsReader::username_from_uid(uid_t uid) -{ - if (s_usernames.is_empty()) { - setpwent(); - while (auto* passwd = getpwent()) - s_usernames.set(passwd->pw_uid, passwd->pw_name); - endpwent(); - } - - auto it = s_usernames.find(uid); - if (it != s_usernames.end()) - return (*it).value; - return String::number(uid); -} -} diff --git a/Libraries/LibCore/ProcessStatisticsReader.h b/Libraries/LibCore/ProcessStatisticsReader.h deleted file mode 100644 index b6e506cd9d..0000000000 --- a/Libraries/LibCore/ProcessStatisticsReader.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/HashMap.h> -#include <AK/String.h> -#include <LibCore/File.h> -#include <unistd.h> - -namespace Core { - -struct ThreadStatistics { - pid_t tid; - unsigned times_scheduled; - unsigned ticks_user; - unsigned ticks_kernel; - unsigned syscall_count; - unsigned inode_faults; - unsigned zero_faults; - unsigned cow_faults; - unsigned unix_socket_read_bytes; - unsigned unix_socket_write_bytes; - unsigned ipv4_socket_read_bytes; - unsigned ipv4_socket_write_bytes; - unsigned file_read_bytes; - unsigned file_write_bytes; - String state; - u32 cpu; - u32 priority; - u32 effective_priority; - String name; -}; - -struct ProcessStatistics { - // Keep this in sync with /proc/all. - // From the kernel side: - pid_t pid; - pid_t pgid; - pid_t pgp; - pid_t sid; - uid_t uid; - gid_t gid; - pid_t ppid; - unsigned nfds; - String name; - String executable; - String tty; - String pledge; - String veil; - size_t amount_virtual; - size_t amount_resident; - size_t amount_shared; - size_t amount_dirty_private; - size_t amount_clean_inode; - size_t amount_purgeable_volatile; - size_t amount_purgeable_nonvolatile; - - Vector<Core::ThreadStatistics> threads; - - // synthetic - String username; -}; - -class ProcessStatisticsReader { -public: - static Optional<HashMap<pid_t, Core::ProcessStatistics>> get_all(RefPtr<Core::File>&); - static Optional<HashMap<pid_t, Core::ProcessStatistics>> get_all(); - -private: - static String username_from_uid(uid_t); - static HashMap<uid_t, String> s_usernames; -}; - -} diff --git a/Libraries/LibCore/Property.cpp b/Libraries/LibCore/Property.cpp deleted file mode 100644 index 8c6c2587c6..0000000000 --- a/Libraries/LibCore/Property.cpp +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/Property.h> - -namespace Core { - -Property::Property(String name, Function<JsonValue()> getter, Function<bool(const JsonValue&)> setter) - : m_name(move(name)) - , m_getter(move(getter)) - , m_setter(move(setter)) -{ -} - -Property::~Property() -{ -} - -} diff --git a/Libraries/LibCore/Property.h b/Libraries/LibCore/Property.h deleted file mode 100644 index aa04e833fb..0000000000 --- a/Libraries/LibCore/Property.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/JsonValue.h> - -namespace Core { - -class Property { - AK_MAKE_NONCOPYABLE(Property); - -public: - Property(String name, Function<JsonValue()> getter, Function<bool(const JsonValue&)> setter = nullptr); - ~Property(); - - bool set(const JsonValue& value) - { - if (!m_setter) - return false; - return m_setter(value); - } - - JsonValue get() const { return m_getter(); } - - const String& name() const { return m_name; } - bool is_readonly() const { return !m_setter; } - -private: - String m_name; - Function<JsonValue()> m_getter; - Function<bool(const JsonValue&)> m_setter; -}; - -} diff --git a/Libraries/LibCore/Socket.cpp b/Libraries/LibCore/Socket.cpp deleted file mode 100644 index 4ced6734b1..0000000000 --- a/Libraries/LibCore/Socket.cpp +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/ByteBuffer.h> -#include <LibCore/Notifier.h> -#include <LibCore/Socket.h> -#include <arpa/inet.h> -#include <errno.h> -#include <fcntl.h> -#include <netdb.h> -#include <netinet/in.h> -#include <stdio.h> -#include <stdlib.h> -#include <sys/socket.h> -#include <unistd.h> - -//#define CSOCKET_DEBUG - -namespace Core { - -Socket::Socket(Type type, Object* parent) - : IODevice(parent) - , m_type(type) -{ - register_property( - "source_address", [this] { return m_source_address.to_string(); }, - [](auto&) { return false; }); - - register_property( - "destination_address", [this] { return m_destination_address.to_string(); }, - [](auto&) { return false; }); - - register_property( - "source_port", [this] { return m_source_port; }, - [](auto&) { return false; }); - - register_property( - "destination_port", [this] { return m_destination_port; }, - [](auto&) { return false; }); - - register_property( - "connected", [this] { return m_connected; }, - [](auto&) { return false; }); -} - -Socket::~Socket() -{ - close(); -} - -bool Socket::connect(const String& hostname, int port) -{ - auto* hostent = gethostbyname(hostname.characters()); - if (!hostent) { - dbgln("Socket::connect: Unable to resolve '{}'", hostname); - return false; - } - - IPv4Address host_address((const u8*)hostent->h_addr_list[0]); -#ifdef CSOCKET_DEBUG - dbg() << "Socket::connect: Resolved '" << hostname << "' to " << host_address; -#endif - return connect(host_address, port); -} - -void Socket::set_blocking(bool blocking) -{ - int flags = fcntl(fd(), F_GETFL, 0); - ASSERT(flags >= 0); - if (blocking) - flags = fcntl(fd(), F_SETFL, flags & ~O_NONBLOCK); - else - flags = fcntl(fd(), F_SETFL, flags | O_NONBLOCK); - ASSERT(flags == 0); -} - -bool Socket::connect(const SocketAddress& address, int port) -{ - ASSERT(!is_connected()); - ASSERT(address.type() == SocketAddress::Type::IPv4); -#ifdef CSOCKET_DEBUG - dbg() << *this << " connecting to " << address << "..."; -#endif - - ASSERT(port > 0 && port <= 65535); - - struct sockaddr_in addr; - memset(&addr, 0, sizeof(addr)); - auto ipv4_address = address.ipv4_address(); - memcpy(&addr.sin_addr.s_addr, &ipv4_address, sizeof(IPv4Address)); - addr.sin_family = AF_INET; - addr.sin_port = htons(port); - - m_destination_address = address; - m_destination_port = port; - - return common_connect((struct sockaddr*)&addr, sizeof(addr)); -} - -bool Socket::connect(const SocketAddress& address) -{ - ASSERT(!is_connected()); - ASSERT(address.type() == SocketAddress::Type::Local); -#ifdef CSOCKET_DEBUG - dbg() << *this << " connecting to " << address << "..."; -#endif - - sockaddr_un saddr; - saddr.sun_family = AF_LOCAL; - auto dest_address = address.to_string(); - bool fits = dest_address.copy_characters_to_buffer(saddr.sun_path, sizeof(saddr.sun_path)); - if (!fits) { - fprintf(stderr, "Core::Socket: Failed to connect() to %s: Path is too long!\n", dest_address.characters()); - errno = EINVAL; - return false; - } - m_destination_address = address; - - return common_connect((const sockaddr*)&saddr, sizeof(saddr)); -} - -bool Socket::common_connect(const struct sockaddr* addr, socklen_t addrlen) -{ - auto connected = [this] { -#ifdef CSOCKET_DEBUG - dbg() << *this << " connected!"; -#endif - if (!m_connected) { - m_connected = true; - ensure_read_notifier(); - if (m_notifier) { - m_notifier->remove_from_parent(); - m_notifier = nullptr; - } - if (on_connected) - on_connected(); - } - }; - int rc = ::connect(fd(), addr, addrlen); - if (rc < 0) { - if (errno == EINPROGRESS) { -#ifdef CSOCKET_DEBUG - dbg() << *this << " connection in progress (EINPROGRESS)"; -#endif - m_notifier = Notifier::construct(fd(), Notifier::Event::Write, this); - m_notifier->on_ready_to_write = move(connected); - return true; - } - int saved_errno = errno; - fprintf(stderr, "Core::Socket: Failed to connect() to %s: %s\n", destination_address().to_string().characters(), strerror(saved_errno)); - errno = saved_errno; - return false; - } -#ifdef CSOCKET_DEBUG - dbg() << *this << " connected ok!"; -#endif - connected(); - return true; -} - -ByteBuffer Socket::receive(int max_size) -{ - auto buffer = read(max_size); - if (eof()) - m_connected = false; - return buffer; -} - -bool Socket::send(ReadonlyBytes data) -{ - ssize_t nsent = ::send(fd(), data.data(), data.size(), 0); - if (nsent < 0) { - set_error(errno); - return false; - } - ASSERT(static_cast<size_t>(nsent) == data.size()); - return true; -} - -void Socket::did_update_fd(int fd) -{ - if (fd < 0) { - if (m_read_notifier) { - m_read_notifier->remove_from_parent(); - m_read_notifier = nullptr; - } - if (m_notifier) { - m_notifier->remove_from_parent(); - m_notifier = nullptr; - } - return; - } - if (m_connected) { - ensure_read_notifier(); - } else { - // I don't think it would be right if we updated the fd while not connected *but* while having a notifier.. - ASSERT(!m_read_notifier); - } -} - -void Socket::ensure_read_notifier() -{ - ASSERT(m_connected); - m_read_notifier = Notifier::construct(fd(), Notifier::Event::Read, this); - m_read_notifier->on_ready_to_read = [this] { - if (!can_read()) - return; - if (on_ready_to_read) - on_ready_to_read(); - }; -} - -} diff --git a/Libraries/LibCore/Socket.h b/Libraries/LibCore/Socket.h deleted file mode 100644 index fcbd2af31d..0000000000 --- a/Libraries/LibCore/Socket.h +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <AK/Span.h> -#include <LibCore/IODevice.h> -#include <LibCore/SocketAddress.h> - -namespace Core { - -class Socket : public IODevice { - C_OBJECT(Socket) -public: - enum class Type { - Invalid, - TCP, - UDP, - Local, - }; - virtual ~Socket() override; - - Type type() const { return m_type; } - - virtual bool connect(const String& hostname, int port); - bool connect(const SocketAddress&, int port); - bool connect(const SocketAddress&); - - ByteBuffer receive(int max_size); - bool send(ReadonlyBytes); - - bool is_connected() const { return m_connected; } - void set_blocking(bool blocking); - - SocketAddress source_address() const { return m_source_address; } - int source_port() const { return m_source_port; } - - SocketAddress destination_address() const { return m_destination_address; } - int destination_port() const { return m_destination_port; } - - Function<void()> on_connected; - Function<void()> on_ready_to_read; - -protected: - Socket(Type, Object* parent); - - SocketAddress m_source_address; - SocketAddress m_destination_address; - int m_source_port { -1 }; - int m_destination_port { -1 }; - bool m_connected { false }; - - virtual void did_update_fd(int) override; - virtual bool common_connect(const struct sockaddr*, socklen_t); - -private: - virtual bool open(IODevice::OpenMode) override { ASSERT_NOT_REACHED(); } - void ensure_read_notifier(); - - Type m_type { Type::Invalid }; - RefPtr<Notifier> m_notifier; - RefPtr<Notifier> m_read_notifier; -}; - -} diff --git a/Libraries/LibCore/SocketAddress.cpp b/Libraries/LibCore/SocketAddress.cpp deleted file mode 100644 index d4d451a150..0000000000 --- a/Libraries/LibCore/SocketAddress.cpp +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/SocketAddress.h> - -namespace Core { - -const LogStream& operator<<(const LogStream& stream, const SocketAddress& value) -{ - return stream << value.to_string(); -} - -} diff --git a/Libraries/LibCore/SocketAddress.h b/Libraries/LibCore/SocketAddress.h deleted file mode 100644 index 717f4e8fd3..0000000000 --- a/Libraries/LibCore/SocketAddress.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/IPv4Address.h> -#include <arpa/inet.h> -#include <netinet/in.h> -#include <string.h> -#include <sys/socket.h> -#include <sys/un.h> - -namespace Core { - -class SocketAddress { -public: - enum class Type { - Invalid, - IPv4, - Local - }; - - SocketAddress() { } - SocketAddress(const IPv4Address& address) - : m_type(Type::IPv4) - , m_ipv4_address(address) - { - } - - SocketAddress(const IPv4Address& address, u16 port) - : m_type(Type::IPv4) - , m_ipv4_address(address) - , m_port(port) - { - } - - static SocketAddress local(const String& address) - { - SocketAddress addr; - addr.m_type = Type::Local; - addr.m_local_address = address; - return addr; - } - - Type type() const { return m_type; } - bool is_valid() const { return m_type != Type::Invalid; } - IPv4Address ipv4_address() const { return m_ipv4_address; } - u16 port() const { return m_port; } - - String to_string() const - { - switch (m_type) { - case Type::IPv4: - return String::format("%s:%d", m_ipv4_address.to_string().characters(), m_port); - case Type::Local: - return m_local_address; - default: - return "[SocketAddress]"; - } - } - - Optional<sockaddr_un> to_sockaddr_un() const - { - ASSERT(type() == Type::Local); - sockaddr_un address; - address.sun_family = AF_LOCAL; - bool fits = m_local_address.copy_characters_to_buffer(address.sun_path, sizeof(address.sun_path)); - if (!fits) - return {}; - return address; - } - - sockaddr_in to_sockaddr_in() const - { - ASSERT(type() == Type::IPv4); - sockaddr_in address {}; - address.sin_family = AF_INET; - address.sin_addr.s_addr = m_ipv4_address.to_in_addr_t(); - address.sin_port = htons(m_port); - return address; - } - -private: - Type m_type { Type::Invalid }; - IPv4Address m_ipv4_address; - u16 m_port { 0 }; - String m_local_address; -}; - -const LogStream& operator<<(const LogStream&, const SocketAddress&); - -} diff --git a/Libraries/LibCore/StandardPaths.cpp b/Libraries/LibCore/StandardPaths.cpp deleted file mode 100644 index 3ed9197835..0000000000 --- a/Libraries/LibCore/StandardPaths.cpp +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/LexicalPath.h> -#include <AK/String.h> -#include <AK/StringBuilder.h> -#include <LibCore/StandardPaths.h> -#include <pwd.h> -#include <stdlib.h> -#include <unistd.h> - -namespace Core { - -String StandardPaths::home_directory() -{ - if (auto* home_env = getenv("HOME")) - return LexicalPath::canonicalized_path(home_env); - - auto* pwd = getpwuid(getuid()); - String path = pwd ? pwd->pw_dir : "/"; - endpwent(); - return LexicalPath::canonicalized_path(path); -} - -String StandardPaths::desktop_directory() -{ - StringBuilder builder; - builder.append(home_directory()); - builder.append("/Desktop"); - return LexicalPath::canonicalized_path(builder.to_string()); -} - -String StandardPaths::downloads_directory() -{ - StringBuilder builder; - builder.append(home_directory()); - builder.append("/Downloads"); - return LexicalPath::canonicalized_path(builder.to_string()); -} - -String StandardPaths::config_directory() -{ - StringBuilder builder; - builder.append(home_directory()); - builder.append("/.config"); - return LexicalPath::canonicalized_path(builder.to_string()); -} - -String StandardPaths::tempfile_directory() -{ - return "/tmp"; -} - -} diff --git a/Libraries/LibCore/StandardPaths.h b/Libraries/LibCore/StandardPaths.h deleted file mode 100644 index 51346250c2..0000000000 --- a/Libraries/LibCore/StandardPaths.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Forward.h> - -namespace Core { - -class StandardPaths { -public: - static String home_directory(); - static String desktop_directory(); - static String downloads_directory(); - static String tempfile_directory(); - static String config_directory(); -}; - -} diff --git a/Libraries/LibCore/SyscallUtils.h b/Libraries/LibCore/SyscallUtils.h deleted file mode 100644 index 1c24efd9c2..0000000000 --- a/Libraries/LibCore/SyscallUtils.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/LogStream.h> -#include <AK/StdLibExtras.h> -#include <errno.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> - -namespace Core { - -template<typename Syscall, class... Args> -inline int safe_syscall(Syscall syscall, Args&&... args) -{ - for (;;) { - int sysret = syscall(forward<Args>(args)...); - if (sysret == -1) { -#ifdef SAFE_SYSCALL_DEBUG - int saved_errno = errno; - dbg() << "Core::safe_syscall: " << sysret << " (" << saved_errno << ": " << strerror(saved_errno) << ")"; -#endif - if (errno == EINTR) - continue; - ASSERT_NOT_REACHED(); - } - return sysret; - } -} - -} diff --git a/Libraries/LibCore/TCPServer.cpp b/Libraries/LibCore/TCPServer.cpp deleted file mode 100644 index 0ef241b717..0000000000 --- a/Libraries/LibCore/TCPServer.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/IPv4Address.h> -#include <AK/Types.h> -#include <LibCore/Notifier.h> -#include <LibCore/TCPServer.h> -#include <LibCore/TCPSocket.h> -#include <stdio.h> -#include <sys/socket.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif -namespace Core { - -TCPServer::TCPServer(Object* parent) - : Object(parent) -{ -#ifdef SOCK_NONBLOCK - m_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); -#else - m_fd = socket(AF_INET, SOCK_STREAM, 0); - int option = 1; - ioctl(m_fd, FIONBIO, &option); - fcntl(m_fd, F_SETFD, FD_CLOEXEC); -#endif - ASSERT(m_fd >= 0); -} - -TCPServer::~TCPServer() -{ - ::close(m_fd); -} - -bool TCPServer::listen(const IPv4Address& address, u16 port) -{ - if (m_listening) - return false; - - auto socket_address = SocketAddress(address, port); - auto in = socket_address.to_sockaddr_in(); - if (::bind(m_fd, (const sockaddr*)&in, sizeof(in)) < 0) { - perror("TCPServer::listen: bind"); - return false; - } - - if (::listen(m_fd, 5) < 0) { - perror("TCPServer::listen: listen"); - return false; - } - m_listening = true; - - m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); - m_notifier->on_ready_to_read = [this] { - if (on_ready_to_accept) - on_ready_to_accept(); - }; - return true; -} - -RefPtr<TCPSocket> TCPServer::accept() -{ - ASSERT(m_listening); - sockaddr_in in; - socklen_t in_size = sizeof(in); - int accepted_fd = ::accept(m_fd, (sockaddr*)&in, &in_size); - if (accepted_fd < 0) { - perror("accept"); - return nullptr; - } - - return TCPSocket::construct(accepted_fd); -} - -Optional<IPv4Address> TCPServer::local_address() const -{ - if (m_fd == -1) - return {}; - - sockaddr_in address; - socklen_t len = sizeof(address); - if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) - return {}; - - return IPv4Address(address.sin_addr.s_addr); -} - -Optional<u16> TCPServer::local_port() const -{ - if (m_fd == -1) - return {}; - - sockaddr_in address; - socklen_t len = sizeof(address); - if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) - return {}; - - return ntohs(address.sin_port); -} - -} diff --git a/Libraries/LibCore/TCPServer.h b/Libraries/LibCore/TCPServer.h deleted file mode 100644 index b516ec1500..0000000000 --- a/Libraries/LibCore/TCPServer.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/IPv4Address.h> -#include <LibCore/Notifier.h> -#include <LibCore/Object.h> - -namespace Core { - -class TCPServer : public Object { - C_OBJECT(TCPServer) -public: - virtual ~TCPServer() override; - - bool is_listening() const { return m_listening; } - bool listen(const IPv4Address& address, u16 port); - - RefPtr<TCPSocket> accept(); - - Optional<IPv4Address> local_address() const; - Optional<u16> local_port() const; - - Function<void()> on_ready_to_accept; - -private: - explicit TCPServer(Object* parent = nullptr); - - int m_fd { -1 }; - bool m_listening { false }; - RefPtr<Notifier> m_notifier; -}; - -} diff --git a/Libraries/LibCore/TCPSocket.cpp b/Libraries/LibCore/TCPSocket.cpp deleted file mode 100644 index 6029a82432..0000000000 --- a/Libraries/LibCore/TCPSocket.cpp +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/TCPSocket.h> -#include <errno.h> -#include <sys/socket.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif - -namespace Core { - -TCPSocket::TCPSocket(int fd, Object* parent) - : Socket(Socket::Type::TCP, parent) -{ - // NOTE: This constructor is used by TCPServer::accept(), so the socket is already connected. - m_connected = true; - set_fd(fd); - set_mode(IODevice::ReadWrite); - set_error(0); -} - -TCPSocket::TCPSocket(Object* parent) - : Socket(Socket::Type::TCP, parent) -{ -#ifdef SOCK_NONBLOCK - int fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); -#else - int fd = socket(AF_INET, SOCK_STREAM, 0); - int option = 1; - ioctl(fd, FIONBIO, &option); -#endif - if (fd < 0) { - set_error(errno); - } else { - set_fd(fd); - set_mode(IODevice::ReadWrite); - set_error(0); - } -} - -TCPSocket::~TCPSocket() -{ -} - -} diff --git a/Libraries/LibCore/TCPSocket.h b/Libraries/LibCore/TCPSocket.h deleted file mode 100644 index 8bdd1ae70c..0000000000 --- a/Libraries/LibCore/TCPSocket.h +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Badge.h> -#include <LibCore/Socket.h> - -namespace Core { - -class TCPSocket final : public Socket { - C_OBJECT(TCPSocket) -public: - virtual ~TCPSocket() override; - -private: - TCPSocket(int fd, Object* parent = nullptr); - explicit TCPSocket(Object* parent = nullptr); -}; - -} diff --git a/Libraries/LibCore/Timer.cpp b/Libraries/LibCore/Timer.cpp deleted file mode 100644 index aa0a0cb17d..0000000000 --- a/Libraries/LibCore/Timer.cpp +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/Timer.h> - -namespace Core { - -Timer::Timer(Object* parent) - : Object(parent) -{ -} - -Timer::Timer(int interval, Function<void()>&& timeout_handler, Object* parent) - : Object(parent) - , on_timeout(move(timeout_handler)) -{ - start(interval); -} - -Timer::~Timer() -{ -} - -void Timer::start() -{ - start(m_interval); -} - -void Timer::start(int interval) -{ - if (m_active) - return; - m_interval = interval; - start_timer(interval); - m_active = true; -} - -void Timer::restart() -{ - restart(m_interval); -} - -void Timer::restart(int interval) -{ - if (m_active) - stop(); - start(interval); -} - -void Timer::stop() -{ - if (!m_active) - return; - stop_timer(); - m_active = false; -} - -void Timer::timer_event(TimerEvent&) -{ - if (m_single_shot) - stop(); - else { - if (m_interval_dirty) { - stop(); - start(m_interval); - } - } - - if (on_timeout) - on_timeout(); -} - -} diff --git a/Libraries/LibCore/Timer.h b/Libraries/LibCore/Timer.h deleted file mode 100644 index 04f41e39a0..0000000000 --- a/Libraries/LibCore/Timer.h +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/Function.h> -#include <LibCore/Object.h> - -namespace Core { - -class Timer final : public Object { - C_OBJECT(Timer); - -public: - static NonnullRefPtr<Timer> create_single_shot(int interval, Function<void()>&& timeout_handler, Object* parent = nullptr) - { - auto timer = adopt(*new Timer(interval, move(timeout_handler), parent)); - timer->set_single_shot(true); - timer->stop(); - return timer; - } - - virtual ~Timer() override; - - void start(); - void start(int interval); - void restart(); - void restart(int interval); - void stop(); - - bool is_active() const { return m_active; } - int interval() const { return m_interval; } - void set_interval(int interval) - { - if (m_interval == interval) - return; - m_interval = interval; - m_interval_dirty = true; - } - - bool is_single_shot() const { return m_single_shot; } - void set_single_shot(bool single_shot) { m_single_shot = single_shot; } - - Function<void()> on_timeout; - -private: - explicit Timer(Object* parent = nullptr); - Timer(int interval, Function<void()>&& timeout_handler, Object* parent = nullptr); - - virtual void timer_event(TimerEvent&) override; - - bool m_active { false }; - bool m_single_shot { false }; - bool m_interval_dirty { false }; - int m_interval { 0 }; -}; - -} diff --git a/Libraries/LibCore/UDPServer.cpp b/Libraries/LibCore/UDPServer.cpp deleted file mode 100644 index 6716865e6b..0000000000 --- a/Libraries/LibCore/UDPServer.cpp +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <AK/IPv4Address.h> -#include <AK/Types.h> -#include <LibCore/Notifier.h> -#include <LibCore/UDPServer.h> -#include <LibCore/UDPSocket.h> -#include <stdio.h> -#include <unistd.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif - -namespace Core { - -UDPServer::UDPServer(Object* parent) - : Object(parent) -{ -#ifdef SOCK_NONBLOCK - m_fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK | SOCK_CLOEXEC, 0); -#else - m_fd = socket(AF_INET, SOCK_DGRAM, 0); - int option = 1; - ioctl(m_fd, FIONBIO, &option); - fcntl(m_fd, F_SETFD, FD_CLOEXEC); -#endif - ASSERT(m_fd >= 0); -} - -UDPServer::~UDPServer() -{ - ::close(m_fd); -} - -bool UDPServer::bind(const IPv4Address& address, u16 port) -{ - if (m_bound) - return false; - - auto saddr = SocketAddress(address, port); - auto in = saddr.to_sockaddr_in(); - - if (::bind(m_fd, (const sockaddr*)&in, sizeof(in)) != 0) { - perror("UDPServer::bind"); - return false; - } - - m_bound = true; - - m_notifier = Notifier::construct(m_fd, Notifier::Event::Read, this); - m_notifier->on_ready_to_read = [this] { - if (on_ready_to_receive) - on_ready_to_receive(); - }; - return true; -} - -ByteBuffer UDPServer::receive(size_t size, sockaddr_in& in) -{ - auto buf = ByteBuffer::create_uninitialized(size); - socklen_t in_len = sizeof(in); - ssize_t rlen = ::recvfrom(m_fd, buf.data(), size, 0, (sockaddr*)&in, &in_len); - if (rlen < 0) { - dbgln("recvfrom: {}", strerror(errno)); - return {}; - } - - buf.trim(rlen); - return buf; -} - -Optional<IPv4Address> UDPServer::local_address() const -{ - if (m_fd == -1) - return {}; - - sockaddr_in address; - socklen_t len = sizeof(address); - if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) - return {}; - - return IPv4Address(address.sin_addr.s_addr); -} - -Optional<u16> UDPServer::local_port() const -{ - if (m_fd == -1) - return {}; - - sockaddr_in address; - socklen_t len = sizeof(address); - if (getsockname(m_fd, (sockaddr*)&address, &len) != 0) - return {}; - - return ntohs(address.sin_port); -} - -} diff --git a/Libraries/LibCore/UDPServer.h b/Libraries/LibCore/UDPServer.h deleted file mode 100644 index 29dfd29d60..0000000000 --- a/Libraries/LibCore/UDPServer.h +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <AK/ByteBuffer.h> -#include <AK/Forward.h> -#include <AK/Function.h> -#include <LibCore/Forward.h> -#include <LibCore/Object.h> -#include <LibCore/SocketAddress.h> - -namespace Core { - -class UDPServer : public Object { - C_OBJECT(UDPServer) -public: - virtual ~UDPServer() override; - - bool is_bound() const { return m_bound; } - - bool bind(const IPv4Address& address, u16 port); - ByteBuffer receive(size_t size, sockaddr_in& from); - ByteBuffer receive(size_t size) - { - struct sockaddr_in saddr; - return receive(size, saddr); - }; - - Optional<IPv4Address> local_address() const; - Optional<u16> local_port() const; - - Function<void()> on_ready_to_receive; - -private: - explicit UDPServer(Object* parent = nullptr); - - int m_fd { -1 }; - bool m_bound { false }; - RefPtr<Notifier> m_notifier; -}; - -} diff --git a/Libraries/LibCore/UDPSocket.cpp b/Libraries/LibCore/UDPSocket.cpp deleted file mode 100644 index c319ac3dc1..0000000000 --- a/Libraries/LibCore/UDPSocket.cpp +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include <LibCore/UDPSocket.h> -#include <errno.h> -#include <sys/socket.h> - -#ifndef SOCK_NONBLOCK -# include <sys/ioctl.h> -#endif - -namespace Core { - -UDPSocket::UDPSocket(Object* parent) - : Socket(Socket::Type::UDP, parent) -{ -#ifdef SOCK_NONBLOCK - int fd = socket(AF_INET, SOCK_DGRAM | SOCK_NONBLOCK, 0); -#else - int fd = socket(AF_INET, SOCK_DGRAM, 0); - int option = 1; - ioctl(fd, FIONBIO, &option); -#endif - - if (fd < 0) { - set_error(errno); - } else { - set_fd(fd); - set_mode(IODevice::ReadWrite); - set_error(0); - } -} - -UDPSocket::~UDPSocket() -{ -} - -} diff --git a/Libraries/LibCore/UDPSocket.h b/Libraries/LibCore/UDPSocket.h deleted file mode 100644 index 3bb65d9831..0000000000 --- a/Libraries/LibCore/UDPSocket.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Copyright (c) 2020, Andreas Kling <kling@serenityos.org> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER - * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#pragma once - -#include <LibCore/Socket.h> - -namespace Core { - -class UDPSocket final : public Socket { - C_OBJECT(UDPSocket) -public: - virtual ~UDPSocket() override; - -private: - explicit UDPSocket(Object* parent = nullptr); -}; - -} diff --git a/Libraries/LibCore/puff.cpp b/Libraries/LibCore/puff.cpp deleted file mode 100644 index c6c90d7142..0000000000 --- a/Libraries/LibCore/puff.cpp +++ /dev/null @@ -1,840 +0,0 @@ -/* - * puff.c - * Copyright (C) 2002-2013 Mark Adler - * For conditions of distribution and use, see copyright notice in puff.h - * version 2.3, 21 Jan 2013 - * - * puff.c is a simple inflate written to be an unambiguous way to specify the - * deflate format. It is not written for speed but rather simplicity. As a - * side benefit, this code might actually be useful when small code is more - * important than speed, such as bootstrap applications. For typical deflate - * data, zlib's inflate() is about four times as fast as puff(). zlib's - * inflate compiles to around 20K on my machine, whereas puff.c compiles to - * around 4K on my machine (a PowerPC using GNU cc). If the faster decode() - * function here is used, then puff() is only twice as slow as zlib's - * inflate(). - * - * All dynamically allocated memory comes from the stack. The stack required - * is less than 2K bytes. This code is compatible with 16-bit int's and - * assumes that long's are at least 32 bits. puff.c uses the short data type, - * assumed to be 16 bits, for arrays in order to conserve memory. The code - * works whether integers are stored big endian or little endian. - * - * In the comments below are "Format notes" that describe the inflate process - * and document some of the less obvious aspects of the format. This source - * code is meant to supplement RFC 1951, which formally describes the deflate - * format: - * - * http://www.zlib.org/rfc-deflate.html - */ - -/* - * Change history: - * - * 1.0 10 Feb 2002 - First version - * 1.1 17 Feb 2002 - Clarifications of some comments and notes - * - Update puff() dest and source pointers on negative - * errors to facilitate debugging deflators - * - Remove longest from struct huffman -- not needed - * - Simplify offs[] index in construct() - * - Add input size and checking, using longjmp() to - * maintain easy readability - * - Use short data type for large arrays - * - Use pointers instead of long to specify source and - * destination sizes to avoid arbitrary 4 GB limits - * 1.2 17 Mar 2002 - Add faster version of decode(), doubles speed (!), - * but leave simple version for readabilty - * - Make sure invalid distances detected if pointers - * are 16 bits - * - Fix fixed codes table error - * - Provide a scanning mode for determining size of - * uncompressed data - * 1.3 20 Mar 2002 - Go back to lengths for puff() parameters [Gailly] - * - Add a puff.h file for the interface - * - Add braces in puff() for else do [Gailly] - * - Use indexes instead of pointers for readability - * 1.4 31 Mar 2002 - Simplify construct() code set check - * - Fix some comments - * - Add FIXLCODES #define - * 1.5 6 Apr 2002 - Minor comment fixes - * 1.6 7 Aug 2002 - Minor format changes - * 1.7 3 Mar 2003 - Added test code for distribution - * - Added zlib-like license - * 1.8 9 Jan 2004 - Added some comments on no distance codes case - * 1.9 21 Feb 2008 - Fix bug on 16-bit integer architectures [Pohland] - * - Catch missing end-of-block symbol error - * 2.0 25 Jul 2008 - Add #define to permit distance too far back - * - Add option in TEST code for puff to write the data - * - Add option in TEST code to skip input bytes - * - Allow TEST code to read from piped stdin - * 2.1 4 Apr 2010 - Avoid variable initialization for happier compilers - * - Avoid unsigned comparisons for even happier compilers - * 2.2 25 Apr 2010 - Fix bug in variable initializations [Oberhumer] - * - Add const where appropriate [Oberhumer] - * - Split if's and ?'s for coverage testing - * - Break out test code to separate file - * - Move NIL to puff.h - * - Allow incomplete code only if single code length is 1 - * - Add full code coverage test to Makefile - * 2.3 21 Jan 2013 - Check for invalid code length codes in dynamic blocks - */ - -#include <setjmp.h> /* for setjmp(), longjmp(), and jmp_buf */ -#include "puff.h" /* prototype for puff() */ - -#define local static /* for local function definitions */ - -/* - * Maximums for allocations and loops. It is not useful to change these -- - * they are fixed by the deflate format. - */ -#define MAXBITS 15 /* maximum bits in a code */ -#define MAXLCODES 286 /* maximum number of literal/length codes */ -#define MAXDCODES 30 /* maximum number of distance codes */ -#define MAXCODES (MAXLCODES+MAXDCODES) /* maximum codes lengths to read */ -#define FIXLCODES 288 /* number of fixed literal/length codes */ - -/* input and output state */ -struct state { - /* output state */ - unsigned char *out; /* output buffer */ - unsigned long outlen; /* available space at out */ - unsigned long outcnt; /* bytes written to out so far */ - - /* input state */ - const unsigned char *in; /* input buffer */ - unsigned long inlen; /* available input at in */ - unsigned long incnt; /* bytes read so far */ - int bitbuf; /* bit buffer */ - int bitcnt; /* number of bits in bit buffer */ - - /* input limit error return state for bits() and decode() */ - jmp_buf env; -}; - -/* - * Return need bits from the input stream. This always leaves less than - * eight bits in the buffer. bits() works properly for need == 0. - * - * Format notes: - * - * - Bits are stored in bytes from the least significant bit to the most - * significant bit. Therefore bits are dropped from the bottom of the bit - * buffer, using shift right, and new bytes are appended to the top of the - * bit buffer, using shift left. - */ -local int bits(struct state *s, int need) -{ - long val; /* bit accumulator (can use up to 20 bits) */ - - /* load at least need bits into val */ - val = s->bitbuf; - while (s->bitcnt < need) { - if (s->incnt == s->inlen) - longjmp(s->env, 1); /* out of input */ - val |= (long)(s->in[s->incnt++]) << s->bitcnt; /* load eight bits */ - s->bitcnt += 8; - } - - /* drop need bits and update buffer, always zero to seven bits left */ - s->bitbuf = (int)(val >> need); - s->bitcnt -= need; - - /* return need bits, zeroing the bits above that */ - return (int)(val & ((1L << need) - 1)); -} - -/* - * Process a stored block. - * - * Format notes: - * - * - After the two-bit stored block type (00), the stored block length and - * stored bytes are byte-aligned for fast copying. Therefore any leftover - * bits in the byte that has the last bit of the type, as many as seven, are - * discarded. The value of the discarded bits are not defined and should not - * be checked against any expectation. - * - * - The second inverted copy of the stored block length does not have to be - * checked, but it's probably a good idea to do so anyway. - * - * - A stored block can have zero length. This is sometimes used to byte-align - * subsets of the compressed data for random access or partial recovery. - */ -local int stored(struct state *s) -{ - unsigned len; /* length of stored block */ - - /* discard leftover bits from current byte (assumes s->bitcnt < 8) */ - s->bitbuf = 0; - s->bitcnt = 0; - - /* get length and check against its one's complement */ - if (s->incnt + 4 > s->inlen) - return 2; /* not enough input */ - len = s->in[s->incnt++]; - len |= s->in[s->incnt++] << 8; - if (s->in[s->incnt++] != (~len & 0xff) || - s->in[s->incnt++] != ((~len >> 8) & 0xff)) - return -2; /* didn't match complement! */ - - /* copy len bytes from in to out */ - if (s->incnt + len > s->inlen) - return 2; /* not enough input */ - if (s->out != NIL) { - if (s->outcnt + len > s->outlen) - return 1; /* not enough output space */ - while (len--) - s->out[s->outcnt++] = s->in[s->incnt++]; - } - else { /* just scanning */ - s->outcnt += len; - s->incnt += len; - } - - /* done with a valid stored block */ - return 0; -} - -/* - * Huffman code decoding tables. count[1..MAXBITS] is the number of symbols of - * each length, which for a canonical code are stepped through in order. - * symbol[] are the symbol values in canonical order, where the number of - * entries is the sum of the counts in count[]. The decoding process can be - * seen in the function decode() below. - */ -struct huffman { - short *count; /* number of symbols of each length */ - short *symbol; /* canonically ordered symbols */ -}; - -/* - * Decode a code from the stream s using huffman table h. Return the symbol or - * a negative value if there is an error. If all of the lengths are zero, i.e. - * an empty code, or if the code is incomplete and an invalid code is received, - * then -10 is returned after reading MAXBITS bits. - * - * Format notes: - * - * - The codes as stored in the compressed data are bit-reversed relative to - * a simple integer ordering of codes of the same lengths. Hence below the - * bits are pulled from the compressed data one at a time and used to - * build the code value reversed from what is in the stream in order to - * permit simple integer comparisons for decoding. A table-based decoding - * scheme (as used in zlib) does not need to do this reversal. - * - * - The first code for the shortest length is all zeros. Subsequent codes of - * the same length are simply integer increments of the previous code. When - * moving up a length, a zero bit is appended to the code. For a complete - * code, the last code of the longest length will be all ones. - * - * - Incomplete codes are handled by this decoder, since they are permitted - * in the deflate format. See the format notes for fixed() and dynamic(). - */ -#ifdef SLOW -local int decode(struct state *s, const struct huffman *h) -{ - int len; /* current number of bits in code */ - int code; /* len bits being decoded */ - int first; /* first code of length len */ - int count; /* number of codes of length len */ - int index; /* index of first code of length len in symbol table */ - - code = first = index = 0; - for (len = 1; len <= MAXBITS; len++) { - code |= bits(s, 1); /* get next bit */ - count = h->count[len]; - if (code - count < first) /* if length len, return symbol */ - return h->symbol[index + (code - first)]; - index += count; /* else update for next length */ - first += count; - first <<= 1; - code <<= 1; - } - return -10; /* ran out of codes */ -} - -/* - * A faster version of decode() for real applications of this code. It's not - * as readable, but it makes puff() twice as fast. And it only makes the code - * a few percent larger. - */ -#else /* !SLOW */ -local int decode(struct state *s, const struct huffman *h) -{ - int len; /* current number of bits in code */ - int code; /* len bits being decoded */ - int first; /* first code of length len */ - int count; /* number of codes of length len */ - int index; /* index of first code of length len in symbol table */ - int bitbuf; /* bits from stream */ - int left; /* bits left in next or left to process */ - short *next; /* next number of codes */ - - bitbuf = s->bitbuf; - left = s->bitcnt; - code = first = index = 0; - len = 1; - next = h->count + 1; - while (1) { - while (left--) { - code |= bitbuf & 1; - bitbuf >>= 1; - count = *next++; - if (code - count < first) { /* if length len, return symbol */ - s->bitbuf = bitbuf; - s->bitcnt = (s->bitcnt - len) & 7; - return h->symbol[index + (code - first)]; - } - index += count; /* else update for next length */ - first += count; - first <<= 1; - code <<= 1; - len++; - } - left = (MAXBITS+1) - len; - if (left == 0) - break; - if (s->incnt == s->inlen) - longjmp(s->env, 1); /* out of input */ - bitbuf = s->in[s->incnt++]; - if (left > 8) - left = 8; - } - return -10; /* ran out of codes */ -} -#endif /* SLOW */ - -/* - * Given the list of code lengths length[0..n-1] representing a canonical - * Huffman code for n symbols, construct the tables required to decode those - * codes. Those tables are the number of codes of each length, and the symbols - * sorted by length, retaining their original order within each length. The - * return value is zero for a complete code set, negative for an over- - * subscribed code set, and positive for an incomplete code set. The tables - * can be used if the return value is zero or positive, but they cannot be used - * if the return value is negative. If the return value is zero, it is not - * possible for decode() using that table to return an error--any stream of - * enough bits will resolve to a symbol. If the return value is positive, then - * it is possible for decode() using that table to return an error for received - * codes past the end of the incomplete lengths. - * - * Not used by decode(), but used for error checking, h->count[0] is the number - * of the n symbols not in the code. So n - h->count[0] is the number of - * codes. This is useful for checking for incomplete codes that have more than - * one symbol, which is an error in a dynamic block. - * - * Assumption: for all i in 0..n-1, 0 <= length[i] <= MAXBITS - * This is assured by the construction of the length arrays in dynamic() and - * fixed() and is not verified by construct(). - * - * Format notes: - * - * - Permitted and expected examples of incomplete codes are one of the fixed - * codes and any code with a single symbol which in deflate is coded as one - * bit instead of zero bits. See the format notes for fixed() and dynamic(). - * - * - Within a given code length, the symbols are kept in ascending order for - * the code bits definition. - */ -local int construct(struct huffman *h, const short *length, int n) -{ - int symbol; /* current symbol when stepping through length[] */ - int len; /* current length when stepping through h->count[] */ - int left; /* number of possible codes left of current length */ - short offs[MAXBITS+1]; /* offsets in symbol table for each length */ - - /* count number of codes of each length */ - for (len = 0; len <= MAXBITS; len++) - h->count[len] = 0; - for (symbol = 0; symbol < n; symbol++) - (h->count[length[symbol]])++; /* assumes lengths are within bounds */ - if (h->count[0] == n) /* no codes! */ - return 0; /* complete, but decode() will fail */ - - /* check for an over-subscribed or incomplete set of lengths */ - left = 1; /* one possible code of zero length */ - for (len = 1; len <= MAXBITS; len++) { - left <<= 1; /* one more bit, double codes left */ - left -= h->count[len]; /* deduct count from possible codes */ - if (left < 0) - return left; /* over-subscribed--return negative */ - } /* left > 0 means incomplete */ - - /* generate offsets into symbol table for each length for sorting */ - offs[1] = 0; - for (len = 1; len < MAXBITS; len++) - offs[len + 1] = offs[len] + h->count[len]; - - /* - * put symbols in table sorted by length, by symbol order within each - * length - */ - for (symbol = 0; symbol < n; symbol++) - if (length[symbol] != 0) - h->symbol[offs[length[symbol]]++] = symbol; - - /* return zero for complete set, positive for incomplete set */ - return left; -} - -/* - * Decode literal/length and distance codes until an end-of-block code. - * - * Format notes: - * - * - Compressed data that is after the block type if fixed or after the code - * description if dynamic is a combination of literals and length/distance - * pairs terminated by and end-of-block code. Literals are simply Huffman - * coded bytes. A length/distance pair is a coded length followed by a - * coded distance to represent a string that occurs earlier in the - * uncompressed data that occurs again at the current location. - * - * - Literals, lengths, and the end-of-block code are combined into a single - * code of up to 286 symbols. They are 256 literals (0..255), 29 length - * symbols (257..285), and the end-of-block symbol (256). - * - * - There are 256 possible lengths (3..258), and so 29 symbols are not enough - * to represent all of those. Lengths 3..10 and 258 are in fact represented - * by just a length symbol. Lengths 11..257 are represented as a symbol and - * some number of extra bits that are added as an integer to the base length - * of the length symbol. The number of extra bits is determined by the base - * length symbol. These are in the static arrays below, lens[] for the base - * lengths and lext[] for the corresponding number of extra bits. - * - * - The reason that 258 gets its own symbol is that the longest length is used - * often in highly redundant files. Note that 258 can also be coded as the - * base value 227 plus the maximum extra value of 31. While a good deflate - * should never do this, it is not an error, and should be decoded properly. - * - * - If a length is decoded, including its extra bits if any, then it is - * followed a distance code. There are up to 30 distance symbols. Again - * there are many more possible distances (1..32768), so extra bits are added - * to a base value represented by the symbol. The distances 1..4 get their - * own symbol, but the rest require extra bits. The base distances and - * corresponding number of extra bits are below in the static arrays dist[] - * and dext[]. - * - * - Literal bytes are simply written to the output. A length/distance pair is - * an instruction to copy previously uncompressed bytes to the output. The - * copy is from distance bytes back in the output stream, copying for length - * bytes. - * - * - Distances pointing before the beginning of the output data are not - * permitted. - * - * - Overlapped copies, where the length is greater than the distance, are - * allowed and common. For example, a distance of one and a length of 258 - * simply copies the last byte 258 times. A distance of four and a length of - * twelve copies the last four bytes three times. A simple forward copy - * ignoring whether the length is greater than the distance or not implements - * this correctly. You should not use memcpy() since its behavior is not - * defined for overlapped arrays. You should not use memmove() or bcopy() - * since though their behavior -is- defined for overlapping arrays, it is - * defined to do the wrong thing in this case. - */ -local int codes(struct state *s, - const struct huffman *lencode, - const struct huffman *distcode) -{ - int symbol; /* decoded symbol */ - int len; /* length for copy */ - unsigned dist; /* distance for copy */ - static const short lens[29] = { /* Size base for length codes 257..285 */ - 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, - 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258}; - static const short lext[29] = { /* Extra bits for length codes 257..285 */ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, - 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0}; - static const short dists[30] = { /* Offset base for distance codes 0..29 */ - 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, - 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, - 8193, 12289, 16385, 24577}; - static const short dext[30] = { /* Extra bits for distance codes 0..29 */ - 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, - 12, 12, 13, 13}; - - /* decode literals and length/distance pairs */ - do { - symbol = decode(s, lencode); - if (symbol < 0) - return symbol; /* invalid symbol */ - if (symbol < 256) { /* literal: symbol is the byte */ - /* write out the literal */ - if (s->out != NIL) { - if (s->outcnt == s->outlen) - return 1; - s->out[s->outcnt] = symbol; - } - s->outcnt++; - } - else if (symbol > 256) { /* length */ - /* get and compute length */ - symbol -= 257; - if (symbol >= 29) - return -10; /* invalid fixed code */ - len = lens[symbol] + bits(s, lext[symbol]); - - /* get and check distance */ - symbol = decode(s, distcode); - if (symbol < 0) - return symbol; /* invalid symbol */ - dist = dists[symbol] + bits(s, dext[symbol]); -#ifndef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - if (dist > s->outcnt) - return -11; /* distance too far back */ -#endif - - /* copy length bytes from distance bytes back */ - if (s->out != NIL) { - if (s->outcnt + len > s->outlen) - return 1; - while (len--) { - s->out[s->outcnt] = -#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR - dist > s->outcnt ? - 0 : -#endif - s->out[s->outcnt - dist]; - s->outcnt++; - } - } - else - s->outcnt += len; - } - } while (symbol != 256); /* end of block symbol */ - - /* done with a valid fixed or dynamic block */ - return 0; -} - -/* - * Process a fixed codes block. - * - * Format notes: - * - * - This block type can be useful for compressing small amounts of data for - * which the size of the code descriptions in a dynamic block exceeds the - * benefit of custom codes for that block. For fixed codes, no bits are - * spent on code descriptions. Instead the code lengths for literal/length - * codes and distance codes are fixed. The specific lengths for each symbol - * can be seen in the "for" loops below. - * - * - The literal/length code is complete, but has two symbols that are invalid - * and should result in an error if received. This cannot be implemented - * simply as an incomplete code since those two symbols are in the "middle" - * of the code. They are eight bits long and the longest literal/length\ - * code is nine bits. Therefore the code must be constructed with those - * symbols, and the invalid symbols must be detected after decoding. - * - * - The fixed distance codes also have two invalid symbols that should result - * in an error if received. Since all of the distance codes are the same - * length, this can be implemented as an incomplete code. Then the invalid - * codes are detected while decoding. - */ -local int fixed(struct state *s) -{ - static int virgin = 1; - static short lencnt[MAXBITS+1], lensym[FIXLCODES]; - static short distcnt[MAXBITS+1], distsym[MAXDCODES]; - static struct huffman lencode, distcode; - - /* build fixed huffman tables if first call (may not be thread safe) */ - if (virgin) { - int symbol; - short lengths[FIXLCODES]; - - /* construct lencode and distcode */ - lencode.count = lencnt; - lencode.symbol = lensym; - distcode.count = distcnt; - distcode.symbol = distsym; - - /* literal/length table */ - for (symbol = 0; symbol < 144; symbol++) - lengths[symbol] = 8; - for (; symbol < 256; symbol++) - lengths[symbol] = 9; - for (; symbol < 280; symbol++) - lengths[symbol] = 7; - for (; symbol < FIXLCODES; symbol++) - lengths[symbol] = 8; - construct(&lencode, lengths, FIXLCODES); - - /* distance table */ - for (symbol = 0; symbol < MAXDCODES; symbol++) - lengths[symbol] = 5; - construct(&distcode, lengths, MAXDCODES); - - /* do this just once */ - virgin = 0; - } - - /* decode data until end-of-block code */ - return codes(s, &lencode, &distcode); -} - -/* - * Process a dynamic codes block. - * - * Format notes: - * - * - A dynamic block starts with a description of the literal/length and - * distance codes for that block. New dynamic blocks allow the compressor to - * rapidly adapt to changing data with new codes optimized for that data. - * - * - The codes used by the deflate format are "canonical", which means that - * the actual bits of the codes are generated in an unambiguous way simply - * from the number of bits in each code. Therefore the code descriptions - * are simply a list of code lengths for each symbol. - * - * - The code lengths are stored in order for the symbols, so lengths are - * provided for each of the literal/length symbols, and for each of the - * distance symbols. - * - * - If a symbol is not used in the block, this is represented by a zero as - * as the code length. This does not mean a zero-length code, but rather - * that no code should be created for this symbol. There is no way in the - * deflate format to represent a zero-length code. - * - * - The maximum number of bits in a code is 15, so the possible lengths for - * any code are 1..15. - * - * - The fact that a length of zero is not permitted for a code has an - * interesting consequence. Normally if only one symbol is used for a given - * code, then in fact that code could be represented with zero bits. However - * in deflate, that code has to be at least one bit. So for example, if - * only a single distance base symbol appears in a block, then it will be - * represented by a single code of length one, in particular one 0 bit. This - * is an incomplete code, since if a 1 bit is received, it has no meaning, - * and should result in an error. So incomplete distance codes of one symbol - * should be permitted, and the receipt of invalid codes should be handled. - * - * - It is also possible to have a single literal/length code, but that code - * must be the end-of-block code, since every dynamic block has one. This - * is not the most efficient way to create an empty block (an empty fixed - * block is fewer bits), but it is allowed by the format. So incomplete - * literal/length codes of one symbol should also be permitted. - * - * - If there are only literal codes and no lengths, then there are no distance - * codes. This is represented by one distance code with zero bits. - * - * - The list of up to 286 length/literal lengths and up to 30 distance lengths - * are themselves compressed using Huffman codes and run-length encoding. In - * the list of code lengths, a 0 symbol means no code, a 1..15 symbol means - * that length, and the symbols 16, 17, and 18 are run-length instructions. - * Each of 16, 17, and 18 are follwed by extra bits to define the length of - * the run. 16 copies the last length 3 to 6 times. 17 represents 3 to 10 - * zero lengths, and 18 represents 11 to 138 zero lengths. Unused symbols - * are common, hence the special coding for zero lengths. - * - * - The symbols for 0..18 are Huffman coded, and so that code must be - * described first. This is simply a sequence of up to 19 three-bit values - * representing no code (0) or the code length for that symbol (1..7). - * - * - A dynamic block starts with three fixed-size counts from which is computed - * the number of literal/length code lengths, the number of distance code - * lengths, and the number of code length code lengths (ok, you come up with - * a better name!) in the code descriptions. For the literal/length and - * distance codes, lengths after those provided are considered zero, i.e. no - * code. The code length code lengths are received in a permuted order (see - * the order[] array below) to make a short code length code length list more - * likely. As it turns out, very short and very long codes are less likely - * to be seen in a dynamic code description, hence what may appear initially - * to be a peculiar ordering. - * - * - Given the number of literal/length code lengths (nlen) and distance code - * lengths (ndist), then they are treated as one long list of nlen + ndist - * code lengths. Therefore run-length coding can and often does cross the - * boundary between the two sets of lengths. - * - * - So to summarize, the code description at the start of a dynamic block is - * three counts for the number of code lengths for the literal/length codes, - * the distance codes, and the code length codes. This is followed by the - * code length code lengths, three bits each. This is used to construct the - * code length code which is used to read the remainder of the lengths. Then - * the literal/length code lengths and distance lengths are read as a single - * set of lengths using the code length codes. Codes are constructed from - * the resulting two sets of lengths, and then finally you can start - * decoding actual compressed data in the block. - * - * - For reference, a "typical" size for the code description in a dynamic - * block is around 80 bytes. - */ -local int dynamic(struct state *s) -{ - int nlen, ndist, ncode; /* number of lengths in descriptor */ - int index; /* index of lengths[] */ - int err; /* construct() return value */ - short lengths[MAXCODES]; /* descriptor code lengths */ - short lencnt[MAXBITS+1], lensym[MAXLCODES]; /* lencode memory */ - short distcnt[MAXBITS+1], distsym[MAXDCODES]; /* distcode memory */ - struct huffman lencode, distcode; /* length and distance codes */ - static const short order[19] = /* permutation of code length codes */ - {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; - - /* construct lencode and distcode */ - lencode.count = lencnt; - lencode.symbol = lensym; - distcode.count = distcnt; - distcode.symbol = distsym; - - /* get number of lengths in each table, check lengths */ - nlen = bits(s, 5) + 257; - ndist = bits(s, 5) + 1; - ncode = bits(s, 4) + 4; - if (nlen > MAXLCODES || ndist > MAXDCODES) - return -3; /* bad counts */ - - /* read code length code lengths (really), missing lengths are zero */ - for (index = 0; index < ncode; index++) - lengths[order[index]] = bits(s, 3); - for (; index < 19; index++) - lengths[order[index]] = 0; - - /* build huffman table for code lengths codes (use lencode temporarily) */ - err = construct(&lencode, lengths, 19); - if (err != 0) /* require complete code set here */ - return -4; - - /* read length/literal and distance code length tables */ - index = 0; - while (index < nlen + ndist) { - int symbol; /* decoded value */ - int len; /* last length to repeat */ - - symbol = decode(s, &lencode); - if (symbol < 0) - return symbol; /* invalid symbol */ - if (symbol < 16) /* length in 0..15 */ - lengths[index++] = symbol; - else { /* repeat instruction */ - len = 0; /* assume repeating zeros */ - if (symbol == 16) { /* repeat last length 3..6 times */ - if (index == 0) - return -5; /* no last length! */ - len = lengths[index - 1]; /* last length */ - symbol = 3 + bits(s, 2); - } - else if (symbol == 17) /* repeat zero 3..10 times */ - symbol = 3 + bits(s, 3); - else /* == 18, repeat zero 11..138 times */ - symbol = 11 + bits(s, 7); - if (index + symbol > nlen + ndist) - return -6; /* too many lengths! */ - while (symbol--) /* repeat last or zero symbol times */ - lengths[index++] = len; - } - } - - /* check for end-of-block code -- there better be one! */ - if (lengths[256] == 0) - return -9; - - /* build huffman table for literal/length codes */ - err = construct(&lencode, lengths, nlen); - if (err && (err < 0 || nlen != lencode.count[0] + lencode.count[1])) - return -7; /* incomplete code ok only for single length 1 code */ - - /* build huffman table for distance codes */ - err = construct(&distcode, lengths + nlen, ndist); - if (err && (err < 0 || ndist != distcode.count[0] + distcode.count[1])) - return -8; /* incomplete code ok only for single length 1 code */ - - /* decode data until end-of-block code */ - return codes(s, &lencode, &distcode); -} - -/* - * Inflate source to dest. On return, destlen and sourcelen are updated to the - * size of the uncompressed data and the size of the deflate data respectively. - * On success, the return value of puff() is zero. If there is an error in the - * source data, i.e. it is not in the deflate format, then a negative value is - * returned. If there is not enough input available or there is not enough - * output space, then a positive error is returned. In that case, destlen and - * sourcelen are not updated to facilitate retrying from the beginning with the - * provision of more input data or more output space. In the case of invalid - * inflate data (a negative error), the dest and source pointers are updated to - * facilitate the debugging of deflators. - * - * puff() also has a mode to determine the size of the uncompressed output with - * no output written. For this dest must be (unsigned char *)0. In this case, - * the input value of *destlen is ignored, and on return *destlen is set to the - * size of the uncompressed output. - * - * The return codes are: - * - * 2: available inflate data did not terminate - * 1: output space exhausted before completing inflate - * 0: successful inflate - * -1: invalid block type (type == 3) - * -2: stored block length did not match one's complement - * -3: dynamic block code description: too many length or distance codes - * -4: dynamic block code description: code lengths codes incomplete - * -5: dynamic block code description: repeat lengths with no first length - * -6: dynamic block code description: repeat more than specified lengths - * -7: dynamic block code description: invalid literal/length code lengths - * -8: dynamic block code description: invalid distance code lengths - * -9: dynamic block code description: missing end-of-block code - * -10: invalid literal/length or distance code in fixed or dynamic block - * -11: distance is too far back in fixed or dynamic block - * - * Format notes: - * - * - Three bits are read for each block to determine the kind of block and - * whether or not it is the last block. Then the block is decoded and the - * process repeated if it was not the last block. - * - * - The leftover bits in the last byte of the deflate data after the last - * block (if it was a fixed or dynamic block) are undefined and have no - * expected values to check. - */ -int puff(unsigned char *dest, /* pointer to destination pointer */ - unsigned long *destlen, /* amount of output space */ - const unsigned char *source, /* pointer to source data pointer */ - unsigned long *sourcelen) /* amount of input available */ -{ - struct state s; /* input/output state */ - int last, type; /* block information */ - int err; /* return value */ - - /* initialize output state */ - s.out = dest; - s.outlen = *destlen; /* ignored if dest is NIL */ - s.outcnt = 0; - - /* initialize input state */ - s.in = source; - s.inlen = *sourcelen; - s.incnt = 0; - s.bitbuf = 0; - s.bitcnt = 0; - - /* return if bits() or decode() tries to read past available input */ - if (setjmp(s.env) != 0) /* if came back here via longjmp() */ - err = 2; /* then skip do-loop, return error */ - else { - /* process blocks until last block or error */ - do { - last = bits(&s, 1); /* one if last block */ - type = bits(&s, 2); /* block type 0..3 */ - err = type == 0 ? - stored(&s) : - (type == 1 ? - fixed(&s) : - (type == 2 ? - dynamic(&s) : - -1)); /* type == 3, invalid */ - if (err != 0) - break; /* return with error */ - } while (!last); - } - - /* update the lengths and return */ - if (err <= 0) { - *destlen = s.outcnt; - *sourcelen = s.incnt; - } - return err; -} diff --git a/Libraries/LibCore/puff.h b/Libraries/LibCore/puff.h deleted file mode 100644 index 5943910403..0000000000 --- a/Libraries/LibCore/puff.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once - -/* puff.h - Copyright (C) 2002-2013 Mark Adler, all rights reserved - version 2.3, 21 Jan 2013 - - This software is provided 'as-is', without any express or implied - warranty. In no event will the author be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgment in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - Mark Adler madler@alumni.caltech.edu - */ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * See puff.c for purpose and usage. - */ -#ifndef NIL -# define NIL ((unsigned char*)0) /* for no output option */ -#endif - -int puff(unsigned char* dest, /* pointer to destination pointer */ - unsigned long* destlen, /* amount of output space */ - const unsigned char* source, /* pointer to source data pointer */ - unsigned long* sourcelen); /* amount of input available */ - -#ifdef __cplusplus -} -#endif |