mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-21 23:20:20 +00:00
Compare commits
95 commits
055c45642c
...
1a3a14964d
Author | SHA1 | Date | |
---|---|---|---|
|
1a3a14964d | ||
|
001df24935 | ||
|
b60cb699a9 | ||
|
8d13115d9a | ||
|
cd14b215d1 | ||
|
35764db0b7 | ||
|
caf7983039 | ||
|
cdb54fe504 | ||
|
7f989765f5 | ||
|
41c172c663 | ||
|
ac5699c8fc | ||
|
ce26e5d757 | ||
|
3a2cc1aa20 | ||
|
0448d4d609 | ||
|
a1687854ab | ||
|
d1120e1809 | ||
|
248e4bb517 | ||
|
b4ba65c6e5 | ||
|
009f328308 | ||
|
d55caff227 | ||
|
570c5f8df2 | ||
|
036e922c79 | ||
|
4fb15d25f3 | ||
|
91fbb26c03 | ||
|
d6bcd3fb0b | ||
|
d527c5df5d | ||
|
13f349aea2 | ||
|
84f673515b | ||
|
4e48298414 | ||
|
bf5cf720b5 | ||
|
488034477a | ||
|
f57ff63432 | ||
|
c715711f88 | ||
|
5689621c2b | ||
|
4742775262 | ||
|
a80523be18 | ||
|
55c81482b0 | ||
|
dfaa3bf649 | ||
|
5fe0d3352d | ||
|
eca378a7a3 | ||
|
e4e05837e1 | ||
|
c8d2404230 | ||
|
d368fcadac | ||
|
f7517c5b8d | ||
|
b94307583b | ||
|
e236f1d2ae | ||
|
63a5717bc7 | ||
|
c5afe58540 | ||
|
3bcd91b109 | ||
|
7d1291b9f0 | ||
|
6911c45bab | ||
|
879ae94183 | ||
|
7e20f4726f | ||
|
7f72c28e78 | ||
|
d704b61066 | ||
|
b93d8ef875 | ||
|
8a07131229 | ||
|
063cd68bf4 | ||
|
f638f84185 | ||
|
4203b7823f | ||
|
cd446e5e9c | ||
|
ab0dc83d28 | ||
|
6fc06f45c2 | ||
|
e98e9b8e81 | ||
|
4b1deb6fe1 | ||
|
356507284e | ||
|
ec5ea0d686 | ||
|
b3c253e50f | ||
|
d0c0db5bb3 | ||
|
b99a3ec2df | ||
|
74b27d620d | ||
|
dabf3da7e5 | ||
|
11460b3daa | ||
|
43056a8684 | ||
|
a423493dd8 | ||
|
77d205571d | ||
|
f09ed59351 | ||
|
866609c682 | ||
|
3468a83e45 | ||
|
4a731b3858 | ||
|
ddd15e96b6 | ||
|
61d52c8a3f | ||
|
33e7d6121b | ||
|
d87144fde2 | ||
|
69f5f40617 | ||
|
a828a0e158 | ||
|
4b4a6991e3 | ||
|
fca6fd0b85 | ||
|
829391e714 | ||
|
726f2cfb11 | ||
|
32cf4d1e29 | ||
|
d5fb48a6f5 | ||
|
458167935c | ||
|
a95f761cb4 | ||
|
6033349574 |
647 changed files with 9381 additions and 31687 deletions
|
@ -23,6 +23,14 @@ extension Swift.String {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension AK.String {
|
||||||
|
public init(swiftString: consuming Swift.String) {
|
||||||
|
self.init() // Create empty string first, using default constructor
|
||||||
|
swiftString.withUTF8 { buffer in
|
||||||
|
self = AK.String.from_utf8_without_validation(AK.ReadonlyBytes(buffer.baseAddress!, buffer.count))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
extension AK.StringView: ExpressibleByStringLiteral {
|
extension AK.StringView: ExpressibleByStringLiteral {
|
||||||
public typealias StringLiteralType = Swift.StaticString
|
public typealias StringLiteralType = Swift.StaticString
|
||||||
|
|
||||||
|
|
|
@ -9,10 +9,8 @@
|
||||||
#include <AK/BitmapView.h>
|
#include <AK/BitmapView.h>
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/Noncopyable.h>
|
#include <AK/Noncopyable.h>
|
||||||
#include <AK/Optional.h>
|
|
||||||
#include <AK/Platform.h>
|
#include <AK/Platform.h>
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Try.h>
|
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/kmalloc.h>
|
#include <AK/kmalloc.h>
|
||||||
|
|
||||||
|
|
|
@ -50,6 +50,10 @@
|
||||||
# cmakedefine01 CSS_TRANSITIONS_DEBUG
|
# cmakedefine01 CSS_TRANSITIONS_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef DNS_DEBUG
|
||||||
|
# cmakedefine01 DNS_DEBUG
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef EDITOR_DEBUG
|
#ifndef EDITOR_DEBUG
|
||||||
# cmakedefine01 EDITOR_DEBUG
|
# cmakedefine01 EDITOR_DEBUG
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -29,6 +29,15 @@ public:
|
||||||
m_data[i] = data[i];
|
m_data[i] = data[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
constexpr IPv6Address(Array<u8, 16> const& data)
|
||||||
|
{
|
||||||
|
for (size_t i = 0; i < 16; i++)
|
||||||
|
m_data[i] = data[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
template<SameAs<char const*> T>
|
||||||
|
constexpr IPv6Address(T const&) = delete; // Disable implicit conversion of char const* -> ipv4 -> ipv6
|
||||||
|
|
||||||
constexpr IPv6Address(IPv4Address const& ipv4_address)
|
constexpr IPv6Address(IPv4Address const& ipv4_address)
|
||||||
{
|
{
|
||||||
// IPv4 mapped IPv6 address
|
// IPv4 mapped IPv6 address
|
||||||
|
|
|
@ -58,9 +58,14 @@ LexicalPath::LexicalPath(ByteString path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LexicalPath::is_absolute() const
|
bool LexicalPath::is_absolute_path(StringView path)
|
||||||
{
|
{
|
||||||
return m_string.starts_with('/');
|
return path.starts_with('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LexicalPath::is_root() const
|
||||||
|
{
|
||||||
|
return m_string == "/";
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ByteString> LexicalPath::parts() const
|
Vector<ByteString> LexicalPath::parts() const
|
||||||
|
|
|
@ -26,7 +26,10 @@ public:
|
||||||
|
|
||||||
explicit LexicalPath(ByteString);
|
explicit LexicalPath(ByteString);
|
||||||
|
|
||||||
bool is_absolute() const;
|
static bool is_absolute_path(StringView path);
|
||||||
|
bool is_absolute() const { return is_absolute_path(m_string); }
|
||||||
|
bool is_root() const;
|
||||||
|
|
||||||
ByteString const& string() const { return m_string; }
|
ByteString const& string() const { return m_string; }
|
||||||
|
|
||||||
StringView dirname() const { return m_dirname; }
|
StringView dirname() const { return m_dirname; }
|
||||||
|
|
|
@ -10,14 +10,9 @@
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
static bool is_absolute_path(StringView path)
|
|
||||||
{
|
|
||||||
return path.length() >= 2 && path[1] == ':';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool is_root(auto const& parts)
|
static bool is_root(auto const& parts)
|
||||||
{
|
{
|
||||||
return parts.size() == 1 && is_absolute_path(parts[0]);
|
return parts.size() == 1 && LexicalPath::is_absolute_path(parts[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
LexicalPath::LexicalPath(ByteString path)
|
LexicalPath::LexicalPath(ByteString path)
|
||||||
|
@ -45,9 +40,14 @@ LexicalPath::LexicalPath(ByteString path)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LexicalPath::is_absolute() const
|
bool LexicalPath::is_absolute_path(StringView path)
|
||||||
{
|
{
|
||||||
return is_absolute_path(m_string);
|
return path.length() >= 2 && path[1] == ':';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LexicalPath::is_root() const
|
||||||
|
{
|
||||||
|
return AK::is_root(m_parts);
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector<ByteString> LexicalPath::parts() const
|
Vector<ByteString> LexicalPath::parts() const
|
||||||
|
@ -86,7 +86,7 @@ ByteString LexicalPath::canonicalized_path(ByteString path)
|
||||||
continue;
|
continue;
|
||||||
if (part == ".." && !canonical_parts.is_empty()) {
|
if (part == ".." && !canonical_parts.is_empty()) {
|
||||||
// At the root, .. does nothing.
|
// At the root, .. does nothing.
|
||||||
if (is_root(canonical_parts))
|
if (AK::is_root(canonical_parts))
|
||||||
continue;
|
continue;
|
||||||
// A .. and a previous non-.. part cancel each other.
|
// A .. and a previous non-.. part cancel each other.
|
||||||
if (canonical_parts.last() != "..") {
|
if (canonical_parts.last() != "..") {
|
||||||
|
@ -100,7 +100,7 @@ ByteString LexicalPath::canonicalized_path(ByteString path)
|
||||||
StringBuilder builder;
|
StringBuilder builder;
|
||||||
builder.join('\\', canonical_parts);
|
builder.join('\\', canonical_parts);
|
||||||
// "X:" -> "X:\"
|
// "X:" -> "X:\"
|
||||||
if (is_root(canonical_parts))
|
if (AK::is_root(canonical_parts))
|
||||||
builder.append('\\');
|
builder.append('\\');
|
||||||
path = builder.to_byte_string();
|
path = builder.to_byte_string();
|
||||||
return path == "" ? "." : path;
|
return path == "" ? "." : path;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Noncopyable.h>
|
#include <AK/Noncopyable.h>
|
||||||
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
|
@ -18,4 +18,11 @@
|
||||||
# define SWIFT_CONFORMS_TO_PROTOCOL(protocol)
|
# define SWIFT_CONFORMS_TO_PROTOCOL(protocol)
|
||||||
# define SWIFT_COMPUTED_PROPERTY
|
# define SWIFT_COMPUTED_PROPERTY
|
||||||
# define SWIFT_MUTATING
|
# define SWIFT_MUTATING
|
||||||
|
# define SWIFT_UNCHECKED_SENDABLE
|
||||||
|
# define SWIFT_NONCOPYABLE
|
||||||
|
# define SWIFT_NONESCAPABLE
|
||||||
|
# define SWIFT_ESCAPABLE
|
||||||
|
# define SWIFT_ESCAPABLE_IF(...)
|
||||||
|
# define SWIFT_RETURNS_RETAINED
|
||||||
|
# define SWIFT_RETURNS_UNRETAINED
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -147,6 +147,7 @@ using __ptrdiff_t = __PTRDIFF_TYPE__;
|
||||||
# if defined(AK_OS_WINDOWS)
|
# if defined(AK_OS_WINDOWS)
|
||||||
using ssize_t = AK::Detail::MakeSigned<size_t>;
|
using ssize_t = AK::Detail::MakeSigned<size_t>;
|
||||||
using mode_t = unsigned short;
|
using mode_t = unsigned short;
|
||||||
|
using pid_t = int;
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -35,5 +35,5 @@ you are welcome to ask on [Discord](../README.md#get-in-touch-and-participate).
|
||||||
* [LibWeb: From Loading to Painting](LibWebFromLoadingToPainting.md)
|
* [LibWeb: From Loading to Painting](LibWebFromLoadingToPainting.md)
|
||||||
* [LibWeb: Browsing Contexts and Navigables](BrowsingContextsAndNavigables.md)
|
* [LibWeb: Browsing Contexts and Navigables](BrowsingContextsAndNavigables.md)
|
||||||
* [How to Add an IDL File](AddNewIDLFile.md)
|
* [How to Add an IDL File](AddNewIDLFile.md)
|
||||||
* [LibWeb Code Style & Patterns](Browser/Patterns.md)
|
* [LibWeb Code Style & Patterns](LibWebPatterns.md)
|
||||||
* [CSS Generated Files](CSSGeneratedFiles.md)
|
* [CSS Generated Files](CSSGeneratedFiles.md)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
# Testing Ladybird
|
# Testing Ladybird
|
||||||
|
|
||||||
Tests are locates in `Tests/`, with a directory for each library.
|
Tests are located in `Tests/`, with a directory for each library.
|
||||||
|
|
||||||
Every feature or bug fix added to LibWeb should have a corresponding test in `Tests/LibWeb`.
|
Every feature or bug fix added to LibWeb should have a corresponding test in `Tests/LibWeb`.
|
||||||
The test should be either a Text, Layout, Ref, or Screenshot test depending on the feature.
|
The test should be either a Text, Layout, Ref, or Screenshot test depending on the feature.
|
||||||
|
|
|
@ -9,8 +9,6 @@
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/BinarySearch.h>
|
#include <AK/BinarySearch.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <LibCompress/Deflate.h>
|
#include <LibCompress/Deflate.h>
|
||||||
#include <LibCompress/Huffman.h>
|
#include <LibCompress/Huffman.h>
|
||||||
|
|
||||||
|
|
|
@ -11,9 +11,6 @@
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <LibCore/DateTime.h>
|
#include <LibCore/DateTime.h>
|
||||||
#include <LibCore/File.h>
|
|
||||||
#include <LibCore/MappedFile.h>
|
|
||||||
#include <LibCore/System.h>
|
|
||||||
|
|
||||||
namespace Compress {
|
namespace Compress {
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ AnonymousBufferImpl::~AnonymousBufferImpl()
|
||||||
|
|
||||||
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
|
ErrorOr<NonnullRefPtr<AnonymousBufferImpl>> AnonymousBufferImpl::create(size_t size)
|
||||||
{
|
{
|
||||||
HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, HIWORD(size), LOWORD(size), NULL);
|
HANDLE map_handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, size >> 31 >> 1, size & 0xFFFFFFFF, NULL);
|
||||||
if (!map_handle)
|
if (!map_handle)
|
||||||
return Error::from_windows_error(GetLastError());
|
return Error::from_windows_error(GetLastError());
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,10 @@ serenity_lib(LibCoreMinimal coreminimal)
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
find_path(DIRENT_INCLUDE_DIR dirent.h REQUIRED)
|
find_path(DIRENT_INCLUDE_DIR dirent.h REQUIRED)
|
||||||
target_include_directories(LibCoreMinimal PRIVATE ${DIRENT_INCLUDE_DIR})
|
target_include_directories(LibCoreMinimal PRIVATE ${DIRENT_INCLUDE_DIR})
|
||||||
|
|
||||||
|
find_package(mman REQUIRED)
|
||||||
|
target_include_directories(LibCoreMinimal PRIVATE ${MMAN_INCLUDE_DIR})
|
||||||
|
target_link_libraries(LibCoreMinimal PRIVATE ${MMAN_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (LAGOM_TOOLS_ONLY)
|
if (LAGOM_TOOLS_ONLY)
|
||||||
|
@ -110,3 +114,7 @@ endif()
|
||||||
if (ANDROID)
|
if (ANDROID)
|
||||||
target_link_libraries(LibCore PRIVATE log)
|
target_link_libraries(LibCore PRIVATE log)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
target_include_directories(LibCore PRIVATE ${MMAN_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
|
@ -12,8 +12,6 @@
|
||||||
#include <LibCore/Directory.h>
|
#include <LibCore/Directory.h>
|
||||||
#include <LibCore/StandardPaths.h>
|
#include <LibCore/StandardPaths.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <pwd.h>
|
|
||||||
#include <sys/types.h>
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
|
|
@ -4,10 +4,8 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "Directory.h"
|
#include <LibCore/Directory.h>
|
||||||
#include "DirIterator.h"
|
#include <LibCore/System.h>
|
||||||
#include "System.h"
|
|
||||||
#include <dirent.h>
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -31,6 +29,7 @@ Directory::~Directory()
|
||||||
MUST(System::close(m_directory_fd));
|
MUST(System::close(m_directory_fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef AK_OS_WINDOWS
|
||||||
ErrorOr<void> Directory::chown(uid_t uid, gid_t gid)
|
ErrorOr<void> Directory::chown(uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
if (m_directory_fd == -1)
|
if (m_directory_fd == -1)
|
||||||
|
@ -38,6 +37,7 @@ ErrorOr<void> Directory::chown(uid_t uid, gid_t gid)
|
||||||
TRY(Core::System::fchown(m_directory_fd, uid, gid));
|
TRY(Core::System::fchown(m_directory_fd, uid, gid));
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ErrorOr<bool> Directory::is_valid_directory(int fd)
|
ErrorOr<bool> Directory::is_valid_directory(int fd)
|
||||||
{
|
{
|
||||||
|
@ -69,7 +69,7 @@ ErrorOr<Directory> Directory::create(LexicalPath path, CreateDirectories create_
|
||||||
|
|
||||||
ErrorOr<void> Directory::ensure_directory(LexicalPath const& path, mode_t creation_mode)
|
ErrorOr<void> Directory::ensure_directory(LexicalPath const& path, mode_t creation_mode)
|
||||||
{
|
{
|
||||||
if (path.basename() == "/" || path.basename() == ".")
|
if (path.is_root() || path.string() == ".")
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
TRY(ensure_directory(path.parent(), creation_mode));
|
TRY(ensure_directory(path.parent(), creation_mode));
|
||||||
|
|
|
@ -10,14 +10,11 @@
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/Format.h>
|
#include <AK/Format.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/IterationDecision.h>
|
|
||||||
#include <AK/LexicalPath.h>
|
#include <AK/LexicalPath.h>
|
||||||
#include <AK/Noncopyable.h>
|
#include <AK/Noncopyable.h>
|
||||||
#include <AK/Optional.h>
|
|
||||||
#include <LibCore/DirIterator.h>
|
#include <LibCore/DirIterator.h>
|
||||||
#include <LibCore/DirectoryEntry.h>
|
#include <LibCore/DirectoryEntry.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
#include <dirent.h>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -51,7 +48,9 @@ public:
|
||||||
static ErrorOr<void> for_each_entry(StringView path, DirIterator::Flags, ForEachEntryCallback);
|
static ErrorOr<void> for_each_entry(StringView path, DirIterator::Flags, ForEachEntryCallback);
|
||||||
ErrorOr<void> for_each_entry(DirIterator::Flags, ForEachEntryCallback);
|
ErrorOr<void> for_each_entry(DirIterator::Flags, ForEachEntryCallback);
|
||||||
|
|
||||||
|
#ifndef AK_OS_WINDOWS
|
||||||
ErrorOr<void> chown(uid_t, gid_t);
|
ErrorOr<void> chown(uid_t, gid_t);
|
||||||
|
#endif
|
||||||
|
|
||||||
static ErrorOr<bool> is_valid_directory(int fd);
|
static ErrorOr<bool> is_valid_directory(int fd);
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
#include <LibCore/MappedFile.h>
|
#include <LibCore/MappedFile.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
|
@ -29,10 +27,8 @@ ErrorOr<NonnullOwnPtr<MappedFile>> MappedFile::map_from_file(NonnullOwnPtr<Core:
|
||||||
|
|
||||||
ErrorOr<NonnullOwnPtr<MappedFile>> MappedFile::map_from_fd_and_close(int fd, [[maybe_unused]] StringView path, Mode mode)
|
ErrorOr<NonnullOwnPtr<MappedFile>> MappedFile::map_from_fd_and_close(int fd, [[maybe_unused]] StringView path, Mode mode)
|
||||||
{
|
{
|
||||||
TRY(Core::System::fcntl(fd, F_SETFD, FD_CLOEXEC));
|
|
||||||
|
|
||||||
ScopeGuard fd_close_guard = [fd] {
|
ScopeGuard fd_close_guard = [fd] {
|
||||||
::close(fd);
|
(void)System::close(fd);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto stat = TRY(Core::System::fstat(fd));
|
auto stat = TRY(Core::System::fstat(fd));
|
||||||
|
|
|
@ -61,6 +61,24 @@ struct ArgvList {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Process::Process(Process&& other)
|
||||||
|
: m_pid(exchange(other.m_pid, 0))
|
||||||
|
, m_should_disown(exchange(other.m_should_disown, false))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Process& Process::operator=(Process&& other)
|
||||||
|
{
|
||||||
|
m_pid = exchange(other.m_pid, 0);
|
||||||
|
m_should_disown = exchange(other.m_should_disown, false);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process::~Process()
|
||||||
|
{
|
||||||
|
(void)disown();
|
||||||
|
}
|
||||||
|
|
||||||
Process Process::current()
|
Process Process::current()
|
||||||
{
|
{
|
||||||
auto p = Process { getpid() };
|
auto p = Process { getpid() };
|
||||||
|
@ -121,7 +139,7 @@ ErrorOr<Process> Process::spawn(ProcessSpawnOptions const& options)
|
||||||
return Process { pid };
|
return Process { pid };
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory, KeepAsChild keep_as_child)
|
ErrorOr<Process> Process::spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory, KeepAsChild keep_as_child)
|
||||||
{
|
{
|
||||||
auto process = TRY(spawn({
|
auto process = TRY(spawn({
|
||||||
.executable = path,
|
.executable = path,
|
||||||
|
@ -131,14 +149,11 @@ ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<ByteString> argument
|
||||||
|
|
||||||
if (keep_as_child == KeepAsChild::No)
|
if (keep_as_child == KeepAsChild::No)
|
||||||
TRY(process.disown());
|
TRY(process.disown());
|
||||||
else {
|
|
||||||
// FIXME: This won't be needed if return value is changed to Process.
|
return process;
|
||||||
process.m_should_disown = false;
|
|
||||||
}
|
|
||||||
return process.pid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory, KeepAsChild keep_as_child)
|
ErrorOr<Process> Process::spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory, KeepAsChild keep_as_child)
|
||||||
{
|
{
|
||||||
Vector<ByteString> backing_strings;
|
Vector<ByteString> backing_strings;
|
||||||
backing_strings.ensure_capacity(arguments.size());
|
backing_strings.ensure_capacity(arguments.size());
|
||||||
|
@ -153,29 +168,8 @@ ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<StringView> argument
|
||||||
|
|
||||||
if (keep_as_child == KeepAsChild::No)
|
if (keep_as_child == KeepAsChild::No)
|
||||||
TRY(process.disown());
|
TRY(process.disown());
|
||||||
else
|
|
||||||
process.m_should_disown = false;
|
|
||||||
return process.pid();
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<pid_t> Process::spawn(StringView path, ReadonlySpan<char const*> arguments, ByteString working_directory, KeepAsChild keep_as_child)
|
return process;
|
||||||
{
|
|
||||||
Vector<ByteString> backing_strings;
|
|
||||||
backing_strings.ensure_capacity(arguments.size());
|
|
||||||
for (auto const& argument : arguments)
|
|
||||||
backing_strings.append(argument);
|
|
||||||
|
|
||||||
auto process = TRY(spawn({
|
|
||||||
.executable = path,
|
|
||||||
.arguments = backing_strings,
|
|
||||||
.working_directory = working_directory.is_empty() ? Optional<ByteString> {} : Optional<ByteString> { working_directory },
|
|
||||||
}));
|
|
||||||
|
|
||||||
if (keep_as_child == KeepAsChild::No)
|
|
||||||
TRY(process.disown());
|
|
||||||
else
|
|
||||||
process.m_should_disown = false;
|
|
||||||
return process.pid();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<String> Process::get_name()
|
ErrorOr<String> Process::get_name()
|
||||||
|
@ -321,6 +315,11 @@ void Process::wait_for_debugger_and_break()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pid_t Process::pid() const
|
||||||
|
{
|
||||||
|
return m_pid;
|
||||||
|
}
|
||||||
|
|
||||||
ErrorOr<void> Process::disown()
|
ErrorOr<void> Process::disown()
|
||||||
{
|
{
|
||||||
if (m_pid != 0 && m_should_disown) {
|
if (m_pid != 0 && m_should_disown) {
|
||||||
|
@ -336,19 +335,19 @@ ErrorOr<void> Process::disown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<bool> Process::wait_for_termination()
|
ErrorOr<int> Process::wait_for_termination()
|
||||||
{
|
{
|
||||||
VERIFY(m_pid > 0);
|
VERIFY(m_pid > 0);
|
||||||
|
|
||||||
bool exited_with_code_0 = true;
|
int exit_code = -1;
|
||||||
int status;
|
int status;
|
||||||
if (waitpid(m_pid, &status, 0) == -1)
|
if (waitpid(m_pid, &status, 0) == -1)
|
||||||
return Error::from_syscall("waitpid"sv, errno);
|
return Error::from_syscall("waitpid"sv, errno);
|
||||||
|
|
||||||
if (WIFEXITED(status)) {
|
if (WIFEXITED(status)) {
|
||||||
exited_with_code_0 &= WEXITSTATUS(status) == 0;
|
exit_code = WEXITSTATUS(status);
|
||||||
} else if (WIFSIGNALED(status)) {
|
} else if (WIFSIGNALED(status)) {
|
||||||
exited_with_code_0 = false;
|
exit_code = 128 + WTERMSIG(status);
|
||||||
} else if (WIFSTOPPED(status)) {
|
} else if (WIFSTOPPED(status)) {
|
||||||
// This is only possible if the child process is being traced by us.
|
// This is only possible if the child process is being traced by us.
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
|
@ -357,7 +356,7 @@ ErrorOr<bool> Process::wait_for_termination()
|
||||||
}
|
}
|
||||||
|
|
||||||
m_should_disown = false;
|
m_should_disown = false;
|
||||||
return exited_with_code_0;
|
return exit_code;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,33 +53,15 @@ public:
|
||||||
No
|
No
|
||||||
};
|
};
|
||||||
|
|
||||||
Process(Process&& other)
|
Process(Process&& other);
|
||||||
: m_pid(exchange(other.m_pid, 0))
|
Process& operator=(Process&& other);
|
||||||
, m_should_disown(exchange(other.m_should_disown, false))
|
~Process();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
Process& operator=(Process&& other)
|
|
||||||
{
|
|
||||||
m_pid = exchange(other.m_pid, 0);
|
|
||||||
m_should_disown = exchange(other.m_should_disown, false);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Process()
|
|
||||||
{
|
|
||||||
(void)disown();
|
|
||||||
}
|
|
||||||
|
|
||||||
static ErrorOr<Process> spawn(ProcessSpawnOptions const& options);
|
static ErrorOr<Process> spawn(ProcessSpawnOptions const& options);
|
||||||
static Process current();
|
static Process current();
|
||||||
|
|
||||||
// FIXME: Make the following 2 functions return Process instance or delete them.
|
static ErrorOr<Process> spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
||||||
static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
static ErrorOr<Process> spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
||||||
static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
|
||||||
|
|
||||||
// FIXME: Remove this. char const* should not exist on this level of abstraction.
|
|
||||||
static ErrorOr<pid_t> spawn(StringView path, ReadonlySpan<char const*> arguments = {}, ByteString working_directory = {}, KeepAsChild keep_as_child = KeepAsChild::No);
|
|
||||||
|
|
||||||
static ErrorOr<String> get_name();
|
static ErrorOr<String> get_name();
|
||||||
enum class SetThreadName {
|
enum class SetThreadName {
|
||||||
|
@ -91,15 +73,17 @@ public:
|
||||||
static void wait_for_debugger_and_break();
|
static void wait_for_debugger_and_break();
|
||||||
static ErrorOr<bool> is_being_debugged();
|
static ErrorOr<bool> is_being_debugged();
|
||||||
|
|
||||||
pid_t pid() const { return m_pid; }
|
pid_t pid() const;
|
||||||
|
|
||||||
|
#ifndef AK_OS_WINDOWS
|
||||||
ErrorOr<void> disown();
|
ErrorOr<void> disown();
|
||||||
|
#endif
|
||||||
|
|
||||||
// FIXME: Make it return an exit code.
|
ErrorOr<int> wait_for_termination();
|
||||||
ErrorOr<bool> wait_for_termination();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Process(pid_t pid)
|
#ifndef AK_OS_WINDOWS
|
||||||
|
Process(pid_t pid = -1)
|
||||||
: m_pid(pid)
|
: m_pid(pid)
|
||||||
, m_should_disown(true)
|
, m_should_disown(true)
|
||||||
{
|
{
|
||||||
|
@ -107,6 +91,14 @@ private:
|
||||||
|
|
||||||
pid_t m_pid;
|
pid_t m_pid;
|
||||||
bool m_should_disown;
|
bool m_should_disown;
|
||||||
|
#else
|
||||||
|
Process(void* handle = 0)
|
||||||
|
: m_handle(handle)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void* m_handle;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
162
Libraries/LibCore/ProcessWindows.cpp
Normal file
162
Libraries/LibCore/ProcessWindows.cpp
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021, Andreas Kling <andreas@ladybird.org>
|
||||||
|
* Copyright (c) 2022-2023, MacDue <macdue@dueutil.tech>
|
||||||
|
* Copyright (c) 2023-2024, Sam Atkins <atkinssj@serenityos.org>
|
||||||
|
* Copyright (c) 2024, Tim Flynn <trflynn89@serenityos.org>
|
||||||
|
* Copyright (c) 2024, stasoid <stasoid@yahoo.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/Utf16View.h>
|
||||||
|
#include <LibCore/Process.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
|
||||||
|
Process::Process(Process&& other)
|
||||||
|
: m_handle(exchange(other.m_handle, nullptr))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Process& Process::operator=(Process&& other)
|
||||||
|
{
|
||||||
|
m_handle = exchange(other.m_handle, nullptr);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
Process::~Process()
|
||||||
|
{
|
||||||
|
if (m_handle)
|
||||||
|
CloseHandle(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
Process Process::current()
|
||||||
|
{
|
||||||
|
return GetCurrentProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Process> Process::spawn(ProcessSpawnOptions const& options)
|
||||||
|
{
|
||||||
|
// file actions are not supported
|
||||||
|
VERIFY(options.file_actions.is_empty());
|
||||||
|
|
||||||
|
char const* program_path = 0;
|
||||||
|
StringBuilder builder;
|
||||||
|
if (options.search_for_executable_in_path)
|
||||||
|
builder.appendff("\"{}\" ", options.executable);
|
||||||
|
else
|
||||||
|
program_path = options.executable.characters();
|
||||||
|
|
||||||
|
builder.join(' ', options.arguments);
|
||||||
|
builder.append('\0');
|
||||||
|
ByteBuffer command_line = TRY(builder.to_byte_buffer());
|
||||||
|
|
||||||
|
auto curdir = options.working_directory.has_value() ? options.working_directory->characters() : 0;
|
||||||
|
|
||||||
|
STARTUPINFO startup_info = {};
|
||||||
|
PROCESS_INFORMATION process_info = {};
|
||||||
|
|
||||||
|
BOOL result = CreateProcess(
|
||||||
|
program_path,
|
||||||
|
(char*)command_line.data(),
|
||||||
|
NULL, // process security attributes
|
||||||
|
NULL, // primary thread security attributes
|
||||||
|
TRUE, // handles are inherited
|
||||||
|
0, // creation flags
|
||||||
|
NULL, // use parent's environment
|
||||||
|
curdir,
|
||||||
|
&startup_info,
|
||||||
|
&process_info);
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
return Error::from_windows_error(GetLastError());
|
||||||
|
|
||||||
|
CloseHandle(process_info.hThread);
|
||||||
|
|
||||||
|
return Process(process_info.hProcess);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Process> Process::spawn(StringView path, ReadonlySpan<ByteString> arguments, ByteString working_directory, KeepAsChild)
|
||||||
|
{
|
||||||
|
return spawn({
|
||||||
|
.executable = path,
|
||||||
|
.arguments = Vector<ByteString> { arguments },
|
||||||
|
.working_directory = working_directory.is_empty() ? Optional<ByteString> {} : working_directory,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<Process> Process::spawn(StringView path, ReadonlySpan<StringView> arguments, ByteString working_directory, KeepAsChild)
|
||||||
|
{
|
||||||
|
Vector<ByteString> backing_strings;
|
||||||
|
backing_strings.ensure_capacity(arguments.size());
|
||||||
|
for (auto argument : arguments)
|
||||||
|
backing_strings.append(argument);
|
||||||
|
|
||||||
|
return spawn({
|
||||||
|
.executable = path,
|
||||||
|
.arguments = backing_strings,
|
||||||
|
.working_directory = working_directory.is_empty() ? Optional<ByteString> {} : working_directory,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the full path of the executable file of the current process
|
||||||
|
ErrorOr<String> Process::get_name()
|
||||||
|
{
|
||||||
|
wchar_t path[MAX_PATH] = {};
|
||||||
|
|
||||||
|
DWORD length = GetModuleFileNameW(NULL, path, MAX_PATH);
|
||||||
|
if (!length)
|
||||||
|
return Error::from_windows_error(GetLastError());
|
||||||
|
|
||||||
|
return String::from_utf16(Utf16View { { (u16*)path, length } });
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> Process::set_name(StringView, SetThreadName)
|
||||||
|
{
|
||||||
|
// Process::set_name() probably cannot be implemented on Windows.
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<bool> Process::is_being_debugged()
|
||||||
|
{
|
||||||
|
return IsDebuggerPresent();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Forces the process to sleep until a debugger is attached, then breaks.
|
||||||
|
void Process::wait_for_debugger_and_break()
|
||||||
|
{
|
||||||
|
bool print_message = true;
|
||||||
|
for (;;) {
|
||||||
|
if (IsDebuggerPresent()) {
|
||||||
|
DebugBreak();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (print_message) {
|
||||||
|
dbgln("Process {} with pid {} is sleeping, waiting for debugger.", Process::get_name(), GetCurrentProcessId());
|
||||||
|
print_message = false;
|
||||||
|
}
|
||||||
|
Sleep(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t Process::pid() const
|
||||||
|
{
|
||||||
|
return GetProcessId(m_handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<int> Process::wait_for_termination()
|
||||||
|
{
|
||||||
|
auto result = WaitForSingleObject(m_handle, INFINITE);
|
||||||
|
if (result == WAIT_FAILED)
|
||||||
|
return Error::from_windows_error(GetLastError());
|
||||||
|
|
||||||
|
DWORD exit_code = 0;
|
||||||
|
if (!GetExitCodeProcess(m_handle, &exit_code))
|
||||||
|
return Error::from_windows_error(GetLastError());
|
||||||
|
|
||||||
|
return exit_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -159,6 +159,7 @@ class TCPSocket final : public Socket {
|
||||||
public:
|
public:
|
||||||
static ErrorOr<NonnullOwnPtr<TCPSocket>> connect(ByteString const& host, u16 port);
|
static ErrorOr<NonnullOwnPtr<TCPSocket>> connect(ByteString const& host, u16 port);
|
||||||
static ErrorOr<NonnullOwnPtr<TCPSocket>> connect(SocketAddress const& address);
|
static ErrorOr<NonnullOwnPtr<TCPSocket>> connect(SocketAddress const& address);
|
||||||
|
static ErrorOr<NonnullOwnPtr<TCPSocket>> connect(SocketAddress const& address, ByteString const&) { return connect(address); }
|
||||||
static ErrorOr<NonnullOwnPtr<TCPSocket>> adopt_fd(int fd);
|
static ErrorOr<NonnullOwnPtr<TCPSocket>> adopt_fd(int fd);
|
||||||
|
|
||||||
TCPSocket(TCPSocket&& other)
|
TCPSocket(TCPSocket&& other)
|
||||||
|
@ -220,6 +221,7 @@ class UDPSocket final : public Socket {
|
||||||
public:
|
public:
|
||||||
static ErrorOr<NonnullOwnPtr<UDPSocket>> connect(ByteString const& host, u16 port, Optional<AK::Duration> timeout = {});
|
static ErrorOr<NonnullOwnPtr<UDPSocket>> connect(ByteString const& host, u16 port, Optional<AK::Duration> timeout = {});
|
||||||
static ErrorOr<NonnullOwnPtr<UDPSocket>> connect(SocketAddress const& address, Optional<AK::Duration> timeout = {});
|
static ErrorOr<NonnullOwnPtr<UDPSocket>> connect(SocketAddress const& address, Optional<AK::Duration> timeout = {});
|
||||||
|
static ErrorOr<NonnullOwnPtr<UDPSocket>> connect(SocketAddress const& address, ByteString const&, Optional<AK::Duration> timeout = {}) { return connect(address, timeout); }
|
||||||
|
|
||||||
UDPSocket(UDPSocket&& other)
|
UDPSocket(UDPSocket&& other)
|
||||||
: Socket(static_cast<Socket&&>(other))
|
: Socket(static_cast<Socket&&>(other))
|
||||||
|
|
|
@ -12,17 +12,31 @@
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/ScopeGuard.h>
|
#include <AK/ScopeGuard.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <WinSock2.h>
|
#include <Windows.h>
|
||||||
|
#include <direct.h>
|
||||||
#include <io.h>
|
#include <io.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
namespace Core::System {
|
namespace Core::System {
|
||||||
|
|
||||||
ErrorOr<int> open(StringView path, int options, mode_t mode)
|
ErrorOr<int> open(StringView path, int options, mode_t mode)
|
||||||
{
|
{
|
||||||
ByteString string_path = path;
|
ByteString string_path = path;
|
||||||
int rc = _open(string_path.characters(), options, mode);
|
auto sz_path = string_path.characters();
|
||||||
if (rc < 0)
|
int rc = _open(sz_path, options, mode);
|
||||||
return Error::from_syscall("open"sv, -errno);
|
if (rc < 0) {
|
||||||
|
int error = errno;
|
||||||
|
struct stat st = {};
|
||||||
|
if (::stat(sz_path, &st) == 0 && (st.st_mode & S_IFDIR)) {
|
||||||
|
HANDLE dir_handle = CreateFile(sz_path, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
|
||||||
|
if (dir_handle == INVALID_HANDLE_VALUE)
|
||||||
|
return Error::from_windows_error(GetLastError());
|
||||||
|
int dir_fd = _open_osfhandle((intptr_t)dir_handle, 0);
|
||||||
|
if (dir_fd != -1)
|
||||||
|
return dir_fd;
|
||||||
|
}
|
||||||
|
return Error::from_syscall("open"sv, -error);
|
||||||
|
}
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,4 +102,86 @@ ErrorOr<void> ioctl(int, unsigned, ...)
|
||||||
VERIFY_NOT_REACHED();
|
VERIFY_NOT_REACHED();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ErrorOr<ByteString> getcwd()
|
||||||
|
{
|
||||||
|
auto* cwd = _getcwd(nullptr, 0);
|
||||||
|
if (!cwd)
|
||||||
|
return Error::from_syscall("getcwd"sv, -errno);
|
||||||
|
|
||||||
|
ByteString string_cwd(cwd);
|
||||||
|
free(cwd);
|
||||||
|
return string_cwd;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<struct stat> stat(StringView path)
|
||||||
|
{
|
||||||
|
if (path.is_null())
|
||||||
|
return Error::from_syscall("stat"sv, -EFAULT);
|
||||||
|
|
||||||
|
struct stat st = {};
|
||||||
|
ByteString path_string = path;
|
||||||
|
if (::stat(path_string.characters(), &st) < 0)
|
||||||
|
return Error::from_syscall("stat"sv, -errno);
|
||||||
|
return st;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> rmdir(StringView path)
|
||||||
|
{
|
||||||
|
if (path.is_null())
|
||||||
|
return Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
ByteString path_string = path;
|
||||||
|
if (_rmdir(path_string.characters()) < 0)
|
||||||
|
return Error::from_syscall("rmdir"sv, -errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> unlink(StringView path)
|
||||||
|
{
|
||||||
|
if (path.is_null())
|
||||||
|
return Error::from_errno(EFAULT);
|
||||||
|
|
||||||
|
ByteString path_string = path;
|
||||||
|
if (_unlink(path_string.characters()) < 0)
|
||||||
|
return Error::from_syscall("unlink"sv, -errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> mkdir(StringView path, mode_t)
|
||||||
|
{
|
||||||
|
ByteString str = path;
|
||||||
|
if (_mkdir(str.characters()) < 0)
|
||||||
|
return Error::from_syscall("mkdir"sv, -errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<int> openat(int, StringView, int, mode_t)
|
||||||
|
{
|
||||||
|
dbgln("Core::System::openat() is not implemented");
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<struct stat> fstatat(int, StringView, int)
|
||||||
|
{
|
||||||
|
dbgln("Core::System::fstatat() is not implemented");
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void*> mmap(void* address, size_t size, int protection, int flags, int fd, off_t offset, size_t alignment, StringView)
|
||||||
|
{
|
||||||
|
// custom alignment is not supported
|
||||||
|
VERIFY(!alignment);
|
||||||
|
void* ptr = ::mmap(address, size, protection, flags, fd, offset);
|
||||||
|
if (ptr == MAP_FAILED)
|
||||||
|
return Error::from_syscall("mmap"sv, -errno);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorOr<void> munmap(void* address, size_t size)
|
||||||
|
{
|
||||||
|
if (::munmap(address, size) < 0)
|
||||||
|
return Error::from_syscall("munmap"sv, -errno);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <AK/Time.h>
|
#include <AK/Time.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
|
||||||
|
|
||||||
namespace Crypto::ASN1 {
|
namespace Crypto::ASN1 {
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/BitmapView.h>
|
#include <AK/BitmapView.h>
|
||||||
#include <AK/Result.h>
|
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibCrypto/ASN1/ASN1.h>
|
#include <LibCrypto/ASN1/ASN1.h>
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/ByteBuffer.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <LibCrypto/ASN1/ASN1.h>
|
|
||||||
#include <LibCrypto/ASN1/DER.h>
|
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Endian.h>
|
#include <AK/Endian.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibCrypto/Hash/HashFunction.h>
|
|
||||||
|
|
||||||
namespace Crypto::Authentication {
|
namespace Crypto::Authentication {
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "UnsignedBigIntegerAlgorithms.h"
|
#include "UnsignedBigIntegerAlgorithms.h"
|
||||||
#include <AK/BigIntBase.h>
|
|
||||||
#include <AK/BuiltinWrappers.h>
|
|
||||||
#include <AK/NumericLimits.h>
|
#include <AK/NumericLimits.h>
|
||||||
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#include "UnsignedBigIntegerAlgorithms.h"
|
#include "UnsignedBigIntegerAlgorithms.h"
|
||||||
#include <AK/BigIntBase.h>
|
#include <AK/BigIntBase.h>
|
||||||
#include <AK/BuiltinWrappers.h>
|
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
|
|
||||||
#include <AK/Concepts.h>
|
#include <AK/Concepts.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/String.h>
|
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
|
|
||||||
namespace Crypto {
|
namespace Crypto {
|
||||||
|
|
|
@ -601,6 +601,11 @@ bool UnsignedBigInteger::operator<(UnsignedBigInteger const& other) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool UnsignedBigInteger::operator<=(UnsignedBigInteger const& other) const
|
||||||
|
{
|
||||||
|
return *this < other || *this == other;
|
||||||
|
}
|
||||||
|
|
||||||
bool UnsignedBigInteger::operator>(UnsignedBigInteger const& other) const
|
bool UnsignedBigInteger::operator>(UnsignedBigInteger const& other) const
|
||||||
{
|
{
|
||||||
return *this != other && !(*this < other);
|
return *this != other && !(*this < other);
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/BigIntBase.h>
|
#include <AK/BigIntBase.h>
|
||||||
#include <AK/ByteBuffer.h>
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Concepts.h>
|
#include <AK/Concepts.h>
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
|
@ -128,6 +127,7 @@ public:
|
||||||
[[nodiscard]] bool operator==(UnsignedBigInteger const& other) const;
|
[[nodiscard]] bool operator==(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] bool operator!=(UnsignedBigInteger const& other) const;
|
[[nodiscard]] bool operator!=(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] bool operator<(UnsignedBigInteger const& other) const;
|
[[nodiscard]] bool operator<(UnsignedBigInteger const& other) const;
|
||||||
|
[[nodiscard]] bool operator<=(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] bool operator>(UnsignedBigInteger const& other) const;
|
[[nodiscard]] bool operator>(UnsignedBigInteger const& other) const;
|
||||||
[[nodiscard]] bool operator>=(UnsignedBigInteger const& other) const;
|
[[nodiscard]] bool operator>=(UnsignedBigInteger const& other) const;
|
||||||
|
|
||||||
|
@ -171,8 +171,26 @@ struct AK::Formatter<Crypto::UnsignedBigInteger> : Formatter<StringView> {
|
||||||
ErrorOr<void> format(FormatBuilder&, Crypto::UnsignedBigInteger const&);
|
ErrorOr<void> format(FormatBuilder&, Crypto::UnsignedBigInteger const&);
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Crypto::UnsignedBigInteger
|
inline Crypto::UnsignedBigInteger operator""_bigint(char const* string, size_t length)
|
||||||
operator""_bigint(char const* string, size_t length)
|
|
||||||
{
|
{
|
||||||
return MUST(Crypto::UnsignedBigInteger::from_base(10, { string, length }));
|
return MUST(Crypto::UnsignedBigInteger::from_base(10, { string, length }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline Crypto::UnsignedBigInteger operator""_bigint(unsigned long long value)
|
||||||
|
{
|
||||||
|
auto result = Crypto::UnsignedBigInteger { static_cast<u64>(value) };
|
||||||
|
VERIFY(!result.is_invalid());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline Crypto::UnsignedBigInteger operator""_bigint(long double value)
|
||||||
|
{
|
||||||
|
VERIFY(value >= 0);
|
||||||
|
VERIFY(value < static_cast<long double>(NumericLimits<double>::max()));
|
||||||
|
|
||||||
|
auto result = Crypto::UnsignedBigInteger { static_cast<double>(value) };
|
||||||
|
VERIFY(!result.is_invalid());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Array.h>
|
#include <AK/Array.h>
|
||||||
#include <AK/NumericLimits.h>
|
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibCrypto/Checksum/CRC32.h>
|
#include <LibCrypto/Checksum/CRC32.h>
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibCrypto/Cipher/Cipher.h>
|
#include <LibCrypto/Cipher/Cipher.h>
|
||||||
#include <LibCrypto/Cipher/Mode/CBC.h>
|
#include <LibCrypto/Cipher/Mode/CBC.h>
|
||||||
#include <LibCrypto/Cipher/Mode/CTR.h>
|
#include <LibCrypto/Cipher/Mode/CTR.h>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteBuffer.h>
|
#include <AK/Span.h>
|
||||||
|
|
||||||
namespace Crypto::Cipher {
|
namespace Crypto::Cipher {
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Optional.h>
|
|
||||||
#include <AK/Span.h>
|
#include <AK/Span.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Random.h>
|
|
||||||
|
|
||||||
namespace Crypto::Curves {
|
namespace Crypto::Curves {
|
||||||
|
|
||||||
class Curve25519 {
|
class Curve25519 {
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteBuffer.h>
|
#include <AK/ByteBuffer.h>
|
||||||
#include <LibCrypto/Curves/EllipticCurve.h>
|
|
||||||
|
|
||||||
namespace Crypto::Curves {
|
namespace Crypto::Curves {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteReader.h>
|
#include <AK/ByteReader.h>
|
||||||
#include <AK/Endian.h>
|
|
||||||
#include <AK/Random.h>
|
#include <AK/Random.h>
|
||||||
#include <LibCrypto/Curves/Curve25519.h>
|
#include <LibCrypto/Curves/Curve25519.h>
|
||||||
#include <LibCrypto/Curves/X25519.h>
|
#include <LibCrypto/Curves/X25519.h>
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
|
#include <AK/Random.h>
|
||||||
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
|
#include <LibCrypto/BigInt/Algorithms/UnsignedBigIntegerAlgorithms.h>
|
||||||
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
#include <LibCrypto/NumberTheory/ModularFunctions.h>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Random.h>
|
|
||||||
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
#include <LibCrypto/BigInt/UnsignedBigInteger.h>
|
||||||
|
|
||||||
namespace Crypto::NumberTheory {
|
namespace Crypto::NumberTheory {
|
||||||
|
|
6
Libraries/LibDNS/CMakeLists.txt
Normal file
6
Libraries/LibDNS/CMakeLists.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
set(SOURCES
|
||||||
|
Message.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
serenity_lib(LibDNS dns)
|
||||||
|
target_link_libraries(LibDNS PRIVATE LibCore)
|
1177
Libraries/LibDNS/Message.cpp
Normal file
1177
Libraries/LibDNS/Message.cpp
Normal file
File diff suppressed because it is too large
Load diff
702
Libraries/LibDNS/Message.h
Normal file
702
Libraries/LibDNS/Message.h
Normal file
|
@ -0,0 +1,702 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Base64.h>
|
||||||
|
#include <AK/IPv4Address.h>
|
||||||
|
#include <AK/IPv6Address.h>
|
||||||
|
#include <AK/RedBlackTree.h>
|
||||||
|
#include <AK/Time.h>
|
||||||
|
|
||||||
|
namespace DNS {
|
||||||
|
namespace Messages {
|
||||||
|
|
||||||
|
struct DomainName;
|
||||||
|
struct ParseContext {
|
||||||
|
CountingStream& stream;
|
||||||
|
NonnullOwnPtr<RedBlackTree<u16, DomainName>> pointers;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum class OpCode : u8;
|
||||||
|
|
||||||
|
struct Options {
|
||||||
|
// 1 1 1 1 1 1
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// | ID |
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// |QR| Opcode |AA|TC|RD|RA| Z |AD|CD| RCODE |
|
||||||
|
constexpr inline static u16 QRMask = 0b1000000000000000;
|
||||||
|
constexpr inline static u16 OpCodeMask = 0b0111100000000000;
|
||||||
|
constexpr inline static u16 AuthoritativeAnswerMask = 0b0000010000000000;
|
||||||
|
constexpr inline static u16 TruncatedMask = 0b0000001000000000;
|
||||||
|
constexpr inline static u16 RecursionDesiredMask = 0b0000000100000000;
|
||||||
|
constexpr inline static u16 RecursionAvailableMask = 0b0000000010000000;
|
||||||
|
constexpr inline static u16 AuthenticatedDataMask = 0b0000000000100000;
|
||||||
|
constexpr inline static u16 CheckingDisabledMask = 0b0000000000010000;
|
||||||
|
constexpr inline static u16 ResponseCodeMask = 0b0000000000001111;
|
||||||
|
|
||||||
|
enum class ResponseCode : u16 {
|
||||||
|
NoError = 0,
|
||||||
|
FormatError = 1,
|
||||||
|
ServerFailure = 2,
|
||||||
|
NameError = 3,
|
||||||
|
NotImplemented = 4,
|
||||||
|
Refused = 5,
|
||||||
|
};
|
||||||
|
|
||||||
|
void set_is_question(bool value) { raw = (raw & ~QRMask) | (value ? QRMask : 0); }
|
||||||
|
void set_is_authoritative_answer(bool value) { raw = (raw & ~AuthoritativeAnswerMask) | (value ? AuthoritativeAnswerMask : 0); }
|
||||||
|
void set_is_truncated(bool value) { raw = (raw & ~TruncatedMask) | (value ? TruncatedMask : 0); }
|
||||||
|
void set_recursion_desired(bool value) { raw = (raw & ~RecursionDesiredMask) | (value ? RecursionDesiredMask : 0); }
|
||||||
|
void set_recursion_available(bool value) { raw = (raw & ~RecursionAvailableMask) | (value ? RecursionAvailableMask : 0); }
|
||||||
|
void set_response_code(ResponseCode code) { raw = (raw & ~ResponseCodeMask) | static_cast<u16>(code); }
|
||||||
|
void set_checking_disabled(bool value) { raw = (raw & ~CheckingDisabledMask) | (value ? CheckingDisabledMask : 0); }
|
||||||
|
void set_authenticated_data(bool value) { raw = (raw & ~AuthenticatedDataMask) | (value ? AuthenticatedDataMask : 0); }
|
||||||
|
void set_op_code(OpCode code) { raw = (raw & ~OpCodeMask) | (static_cast<u16>(code) << 11); }
|
||||||
|
|
||||||
|
bool is_question() const { return (raw & QRMask) == 0; }
|
||||||
|
bool is_authoritative_answer() const { return (raw & AuthoritativeAnswerMask) != 0; }
|
||||||
|
bool is_truncated() const { return (raw & TruncatedMask) != 0; }
|
||||||
|
bool recursion_desired() const { return (raw & RecursionDesiredMask) != 0; }
|
||||||
|
bool recursion_available() const { return (raw & RecursionAvailableMask) != 0; }
|
||||||
|
bool checking_disabled() const { return (raw & CheckingDisabledMask) != 0; }
|
||||||
|
bool authenticated_data() const { return (raw & AuthenticatedDataMask) != 0; }
|
||||||
|
ResponseCode response_code() const { return static_cast<ResponseCode>(raw & ResponseCodeMask); }
|
||||||
|
OpCode op_code() const { return static_cast<OpCode>((raw & OpCodeMask) >> 11); }
|
||||||
|
|
||||||
|
String to_string() const;
|
||||||
|
|
||||||
|
NetworkOrdered<u16> raw { 0 };
|
||||||
|
};
|
||||||
|
StringView to_string(Options::ResponseCode);
|
||||||
|
|
||||||
|
struct Header {
|
||||||
|
NetworkOrdered<u16> id;
|
||||||
|
Options options;
|
||||||
|
NetworkOrdered<u16> question_count;
|
||||||
|
NetworkOrdered<u16> answer_count;
|
||||||
|
NetworkOrdered<u16> authority_count;
|
||||||
|
NetworkOrdered<u16> additional_count;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DomainName {
|
||||||
|
Vector<ByteString> labels;
|
||||||
|
|
||||||
|
static DomainName from_string(StringView);
|
||||||
|
static ErrorOr<DomainName> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const;
|
||||||
|
String to_string() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-4.
|
||||||
|
enum class ResourceType : u16 {
|
||||||
|
Reserved = 0, // [RFC6895]
|
||||||
|
A = 1, // a host address [RFC1035]
|
||||||
|
NS = 2, // an authoritative name server [RFC1035]
|
||||||
|
MD = 3, // a mail destination (OBSOLETE - use MX) [RFC1035]
|
||||||
|
MF = 4, // a mail forwarder (OBSOLETE - use MX) [RFC1035]
|
||||||
|
CNAME = 5, // the canonical name for an alias [RFC1035]
|
||||||
|
SOA = 6, // marks the start of a zone of authority [RFC1035]
|
||||||
|
MB = 7, // a mailbox domain name (EXPERIMENTAL) [RFC1035]
|
||||||
|
MG = 8, // a mail group member (EXPERIMENTAL) [RFC1035]
|
||||||
|
MR = 9, // a mail rename domain name (EXPERIMENTAL) [RFC1035]
|
||||||
|
NULL_ = 10, // a null RR (EXPERIMENTAL) [RFC1035]
|
||||||
|
WKS = 11, // a well known service description [RFC1035]
|
||||||
|
PTR = 12, // a domain name pointer [RFC1035]
|
||||||
|
HINFO = 13, // host information [RFC1035]
|
||||||
|
MINFO = 14, // mailbox or mail list information [RFC1035]
|
||||||
|
MX = 15, // mail exchange [RFC1035]
|
||||||
|
TXT = 16, // text strings [RFC1035]
|
||||||
|
RP = 17, // for Responsible Person [RFC1183]
|
||||||
|
AFSDB = 18, // for AFS Data Base location [RFC1183][RFC5864]
|
||||||
|
X25 = 19, // for X.25 PSDN address [RFC1183]
|
||||||
|
ISDN = 20, // for ISDN address [RFC1183]
|
||||||
|
RT = 21, // for Route Through [RFC1183]
|
||||||
|
NSAP = 22, // for NSAP address, NSAP style A record (DEPRECATED) [RFC1706][Moving TPC.INT and NSAP.INT infrastructure domains to historic]
|
||||||
|
NSAP_PTR = 23, // for domain name pointer, NSAP style (DEPRECATED) [RFC1706][Moving TPC.INT and NSAP.INT infrastructure domains to historic]
|
||||||
|
SIG = 24, // for security signature [RFC2536][RFC2931][RFC3110][RFC4034]
|
||||||
|
KEY = 25, // for security key [RFC2536][RFC2539][RFC3110][RFC4034]
|
||||||
|
PX = 26, // X.400 mail mapping information [RFC2163]
|
||||||
|
GPOS = 27, // Geographical Position [RFC1712]
|
||||||
|
AAAA = 28, // IP6 Address [RFC3596]
|
||||||
|
LOC = 29, // Location Information [RFC1876]
|
||||||
|
NXT = 30, // Next Domain (OBSOLETE) [RFC2535][RFC3755]
|
||||||
|
EID = 31, // Endpoint Identifier [Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt]
|
||||||
|
NIMLOC = 32, // Nimrod Locator [1][Michael_Patton][http://ana-3.lcs.mit.edu/~jnc/nimrod/dns.txt]
|
||||||
|
SRV = 33, // Server Selection [1][RFC2782]
|
||||||
|
ATMA = 34, // ATM Address "[ ATM Forum Technical Committee, "ATM Name System, V2.0", Doc ID: AF-DANS-0152.000, July 2000. Available from and held in escrow by IANA.]"
|
||||||
|
NAPTR = 35, // Naming Authority Pointer [RFC3403]
|
||||||
|
KX = 36, // Key Exchanger [RFC2230]
|
||||||
|
CERT = 37, // CERT [RFC4398]
|
||||||
|
A6 = 38, // A6 (OBSOLETE - use AAAA) [RFC2874][RFC3226][RFC6563]
|
||||||
|
DNAME = 39, // DNAME [RFC6672]
|
||||||
|
SINK = 40, // SINK [Donald_E_Eastlake][draft-eastlake-kitchen-sink]
|
||||||
|
OPT = 41, // OPT [RFC3225][RFC6891]
|
||||||
|
APL = 42, // APL [RFC3123]
|
||||||
|
DS = 43, // Delegation Signer [RFC4034]
|
||||||
|
SSHFP = 44, // SSH Key Fingerprint [RFC4255]
|
||||||
|
IPSECKEY = 45, // IPSECKEY [RFC4025]
|
||||||
|
RRSIG = 46, // RRSIG [RFC4034]
|
||||||
|
NSEC = 47, // NSEC [RFC4034][RFC9077]
|
||||||
|
DNSKEY = 48, // DNSKEY [RFC4034]
|
||||||
|
DHCID = 49, // DHCID [RFC4701]
|
||||||
|
NSEC3 = 50, // NSEC3 [RFC5155][RFC9077]
|
||||||
|
NSEC3PARAM = 51, // NSEC3PARAM [RFC5155]
|
||||||
|
TLSA = 52, // TLSA [RFC6698]
|
||||||
|
SMIMEA = 53, // S/MIME cert association [RFC8162]
|
||||||
|
HIP = 55, // Host Identity Protocol [RFC8005]
|
||||||
|
NINFO = 56, // NINFO [Jim_Reid]
|
||||||
|
RKEY = 57, // RKEY [Jim_Reid]
|
||||||
|
TALINK = 58, // Trust Anchor LINK [Wouter_Wijngaards]
|
||||||
|
CDS = 59, // Child DS [RFC7344]
|
||||||
|
CDNSKEY = 60, // DNSKEY(s) the Child wants reflected in DS [RFC7344]
|
||||||
|
OPENPGPKEY = 61, // OpenPGP Key [RFC7929]
|
||||||
|
CSYNC = 62, // Child-To-Parent Synchronization [RFC7477]
|
||||||
|
ZONEMD = 63, // Message Digest Over Zone Data [RFC8976]
|
||||||
|
SVCB = 64, // General-purpose service binding [RFC9460]
|
||||||
|
HTTPS = 65, // SVCB-compatible type for use with HTTP [RFC9460]
|
||||||
|
SPF = 99, // [RFC7208]
|
||||||
|
UINFO = 100, // [IANA-Reserved]
|
||||||
|
UID = 101, // [IANA-Reserved]
|
||||||
|
GID = 102, // [IANA-Reserved]
|
||||||
|
UNSPEC = 103, // [IANA-Reserved]
|
||||||
|
NID = 104, // [RFC6742]
|
||||||
|
L32 = 105, // [RFC6742]
|
||||||
|
L64 = 106, // [RFC6742]
|
||||||
|
LP = 107, // [RFC6742]
|
||||||
|
EUI48 = 108, // an EUI-48 address [RFC7043]
|
||||||
|
EUI64 = 109, // an EUI-64 address [RFC7043]
|
||||||
|
NXNAME = 128, // NXDOMAIN indicator for Compact Denial of Existence [draft-ietf-dnsop-compact-denial-of-existence-04]
|
||||||
|
TKEY = 249, // Transaction Key [RFC2930]
|
||||||
|
TSIG = 250, // Transaction Signature [RFC8945]
|
||||||
|
IXFR = 251, // incremental transfer [RFC1995]
|
||||||
|
AXFR = 252, // transfer of an entire zone [RFC1035][RFC5936]
|
||||||
|
MAILB = 253, // mailbox-related RRs (MB, MG or MR) [RFC1035]
|
||||||
|
MAILA = 254, // mail agent RRs (OBSOLETE - see MX) [RFC1035]
|
||||||
|
ANY = 255, // A request for some or all records the server has available [RFC1035][RFC6895][RFC8482]
|
||||||
|
URI = 256, // URI [RFC7553]
|
||||||
|
CAA = 257, // Certification Authority Restriction [RFC8659]
|
||||||
|
AVC = 258, // Application Visibility and Control [Wolfgang_Riedel]
|
||||||
|
DOA = 259, // Digital Object Architecture [draft-durand-doa-over-dns]
|
||||||
|
AMTRELAY = 260, // Automatic Multicast Tunneling Relay [RFC8777]
|
||||||
|
RESINFO = 261, // Resolver Information as Key/Value Pairs [RFC9606]
|
||||||
|
WALLET = 262, // Public wallet address [Paul_Hoffman]
|
||||||
|
CLA = 263, // BP Convergence Layer Adapter [draft-johnson-dns-ipn-cla-07]
|
||||||
|
IPN = 264, // BP Node Number [draft-johnson-dns-ipn-cla-07]
|
||||||
|
TA = 32768, // DNSSEC Trust Authorities "[Sam_Weiler][Deploying DNSSEC Without a Signed Root. Technical Report 1999-19, Information Networking Institute, Carnegie Mellon University, April 2004.]"
|
||||||
|
DLV = 32769, // DNSSEC Lookaside Validation (OBSOLETE) [RFC8749][RFC4431]
|
||||||
|
};
|
||||||
|
StringView to_string(ResourceType);
|
||||||
|
Optional<ResourceType> resource_type_from_string(StringView);
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-2.
|
||||||
|
enum class Class : u16 {
|
||||||
|
IN = 1, // the Internet [RFC1035]
|
||||||
|
CH = 3, // the CHAOS class [Moon1981]
|
||||||
|
HS = 4, // Hesiod [Dyer1987]
|
||||||
|
};
|
||||||
|
StringView to_string(Class);
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-parameters/dns-parameters.xhtml#dns-parameters-3.
|
||||||
|
enum class OpCode : u8 {
|
||||||
|
Query = 0, // a standard query (QUERY)
|
||||||
|
IQuery = 1, // an inverse query (IQUERY)
|
||||||
|
Status = 2, // a server status request (STATUS)
|
||||||
|
Notify = 4, // NOTIFY
|
||||||
|
Update = 5, // dynamic update (RFC 2136)
|
||||||
|
DSO = 6, // DNS Stateful Operations (DSO) [RFC8490]
|
||||||
|
Reserved = 7, // [RFC6895]
|
||||||
|
ReservedMask = 15 // [RFC6895]
|
||||||
|
};
|
||||||
|
StringView to_string(OpCode);
|
||||||
|
|
||||||
|
namespace TLSA {
|
||||||
|
|
||||||
|
// Listings from IANA https://www.iana.org/assignments/dane-parameters/dane-parameters.xhtml.
|
||||||
|
enum class CertUsage : u8 {
|
||||||
|
CAConstraint = 0,
|
||||||
|
ServiceCertificateConstraint = 1,
|
||||||
|
TrustAnchorAssertion = 2,
|
||||||
|
DomainIssuedCertificate = 3,
|
||||||
|
Private = 255
|
||||||
|
};
|
||||||
|
enum class Selector : u8 {
|
||||||
|
FullCertificate = 0,
|
||||||
|
SubjectPublicKeyInfo = 1,
|
||||||
|
Private = 255
|
||||||
|
};
|
||||||
|
enum class MatchingType : u8 {
|
||||||
|
Full = 0,
|
||||||
|
SHA256 = 1,
|
||||||
|
SHA512 = 2,
|
||||||
|
Private = 255
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace DNSSEC {
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
|
||||||
|
enum class Algorithm : u8 {
|
||||||
|
RSAMD5 = 1, // RSA/MD5 [RFC4034][RFC3110]
|
||||||
|
DSA = 3, // DSA/SHA-1 [RFC3755][RFC2536]
|
||||||
|
RSASHA1 = 5, // RSA/SHA-1 [RFC3110]
|
||||||
|
RSASHA1NSEC3SHA1 = 7, // [RFC5155]
|
||||||
|
RSASHA256 = 8, // RSA/SHA-256 [RFC5702]
|
||||||
|
RSASHA512 = 10, // RSA/SHA-512 [RFC5702]
|
||||||
|
ECDSAP256SHA256 = 13, // ECDSA Curve P-256 with SHA-256 [RFC6605]
|
||||||
|
ECDSAP384SHA384 = 14, // ECDSA Curve P-384 with SHA-384 [RFC6605]
|
||||||
|
ED25519 = 15, // Ed25519 [RFC8080]
|
||||||
|
Unknown = 255 // Reserved for Private Use
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline StringView to_string(Algorithm algorithm)
|
||||||
|
{
|
||||||
|
switch (algorithm) {
|
||||||
|
case Algorithm::RSAMD5:
|
||||||
|
return "RSAMD5"sv;
|
||||||
|
case Algorithm::DSA:
|
||||||
|
return "DSA"sv;
|
||||||
|
case Algorithm::RSASHA1:
|
||||||
|
return "RSASHA1"sv;
|
||||||
|
case Algorithm::RSASHA1NSEC3SHA1:
|
||||||
|
return "RSASHA1NSEC3SHA1"sv;
|
||||||
|
case Algorithm::RSASHA256:
|
||||||
|
return "RSASHA256"sv;
|
||||||
|
case Algorithm::RSASHA512:
|
||||||
|
return "RSASHA512"sv;
|
||||||
|
case Algorithm::ECDSAP256SHA256:
|
||||||
|
return "ECDSAP256SHA256"sv;
|
||||||
|
case Algorithm::ECDSAP384SHA384:
|
||||||
|
return "ECDSAP384SHA384"sv;
|
||||||
|
case Algorithm::ED25519:
|
||||||
|
return "ED25519"sv;
|
||||||
|
case Algorithm::Unknown:
|
||||||
|
return "Unknown"sv;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
|
||||||
|
enum class DigestType : u8 {
|
||||||
|
SHA1 = 1, // SHA-1 [RFC3658]
|
||||||
|
SHA256 = 2, // SHA-256 [RFC4509]
|
||||||
|
GOST3411 = 3, // GOST R 34.11-94 [RFC5933]
|
||||||
|
SHA384 = 4, // SHA-384 [RFC6605]
|
||||||
|
SHA512 = 5, // SHA-512 [RFC6605]
|
||||||
|
SHA224 = 6, // SHA-224 [RFC6605]
|
||||||
|
Unknown = 255 // Reserved for Private Use
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline StringView to_string(DigestType digest_type)
|
||||||
|
{
|
||||||
|
switch (digest_type) {
|
||||||
|
case DigestType::SHA1:
|
||||||
|
return "SHA1"sv;
|
||||||
|
case DigestType::SHA256:
|
||||||
|
return "SHA256"sv;
|
||||||
|
case DigestType::GOST3411:
|
||||||
|
return "GOST3411"sv;
|
||||||
|
case DigestType::SHA384:
|
||||||
|
return "SHA384"sv;
|
||||||
|
case DigestType::SHA512:
|
||||||
|
return "SHA512"sv;
|
||||||
|
case DigestType::SHA224:
|
||||||
|
return "SHA224"sv;
|
||||||
|
case DigestType::Unknown:
|
||||||
|
return "Unknown"sv;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing from IANA https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml.
|
||||||
|
enum class NSEC3HashAlgorithm : u8 {
|
||||||
|
SHA1 = 1, // [RFC5155]
|
||||||
|
SHA256 = 2, // [RFC6605]
|
||||||
|
GOST3411 = 3, // [RFC5933]
|
||||||
|
SHA384 = 4, // [RFC6605]
|
||||||
|
SHA512 = 5, // [RFC6605]
|
||||||
|
SHA224 = 6, // [RFC6605]
|
||||||
|
Unknown = 255 // Reserved for Private Use
|
||||||
|
};
|
||||||
|
|
||||||
|
static inline StringView to_string(NSEC3HashAlgorithm hash_algorithm)
|
||||||
|
{
|
||||||
|
switch (hash_algorithm) {
|
||||||
|
case NSEC3HashAlgorithm::SHA1:
|
||||||
|
return "SHA1"sv;
|
||||||
|
case NSEC3HashAlgorithm::SHA256:
|
||||||
|
return "SHA256"sv;
|
||||||
|
case NSEC3HashAlgorithm::GOST3411:
|
||||||
|
return "GOST3411"sv;
|
||||||
|
case NSEC3HashAlgorithm::SHA384:
|
||||||
|
return "SHA384"sv;
|
||||||
|
case NSEC3HashAlgorithm::SHA512:
|
||||||
|
return "SHA512"sv;
|
||||||
|
case NSEC3HashAlgorithm::SHA224:
|
||||||
|
return "SHA224"sv;
|
||||||
|
case NSEC3HashAlgorithm::Unknown:
|
||||||
|
return "Unknown"sv;
|
||||||
|
}
|
||||||
|
VERIFY_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Question {
|
||||||
|
DomainName name;
|
||||||
|
ResourceType type;
|
||||||
|
Class class_;
|
||||||
|
|
||||||
|
static ErrorOr<Question> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Records {
|
||||||
|
|
||||||
|
struct A {
|
||||||
|
IPv4Address address;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::A;
|
||||||
|
static ErrorOr<A> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return address.to_string(); }
|
||||||
|
};
|
||||||
|
struct AAAA {
|
||||||
|
IPv6Address address;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::AAAA;
|
||||||
|
static ErrorOr<AAAA> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return address.to_string(); }
|
||||||
|
};
|
||||||
|
struct TXT {
|
||||||
|
ByteString content;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::TXT;
|
||||||
|
static ErrorOr<TXT> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return String::formatted("Text: '{}'", StringView { content }); }
|
||||||
|
};
|
||||||
|
struct CNAME {
|
||||||
|
DomainName names;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::CNAME;
|
||||||
|
static ErrorOr<CNAME> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return names.to_string(); }
|
||||||
|
};
|
||||||
|
struct NS {
|
||||||
|
DomainName name;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::NS;
|
||||||
|
static ErrorOr<NS> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return name.to_string(); }
|
||||||
|
};
|
||||||
|
struct SOA {
|
||||||
|
DomainName mname;
|
||||||
|
DomainName rname;
|
||||||
|
u32 serial;
|
||||||
|
u32 refresh;
|
||||||
|
u32 retry;
|
||||||
|
u32 expire;
|
||||||
|
u32 minimum;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::SOA;
|
||||||
|
static ErrorOr<SOA> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const
|
||||||
|
{
|
||||||
|
return String::formatted("SOA MName: '{}', RName: '{}', Serial: {}, Refresh: {}, Retry: {}, Expire: {}, Minimum: {}", mname.to_string(), rname.to_string(), serial, refresh, retry, expire, minimum);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct MX {
|
||||||
|
u16 preference;
|
||||||
|
DomainName exchange;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::MX;
|
||||||
|
static ErrorOr<MX> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return String::formatted("MX Preference: {}, Exchange: '{}'", preference, exchange.to_string()); }
|
||||||
|
};
|
||||||
|
struct PTR {
|
||||||
|
DomainName name;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::PTR;
|
||||||
|
static ErrorOr<PTR> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return name.to_string(); }
|
||||||
|
};
|
||||||
|
struct SRV {
|
||||||
|
u16 priority;
|
||||||
|
u16 weight;
|
||||||
|
u16 port;
|
||||||
|
DomainName target;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::SRV;
|
||||||
|
static ErrorOr<SRV> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return String::formatted("SRV Priority: {}, Weight: {}, Port: {}, Target: '{}'", priority, weight, port, target.to_string()); }
|
||||||
|
};
|
||||||
|
struct DNSKEY {
|
||||||
|
u16 flags;
|
||||||
|
u8 protocol;
|
||||||
|
DNSSEC::Algorithm algorithm;
|
||||||
|
ByteBuffer public_key;
|
||||||
|
|
||||||
|
constexpr static inline u16 FlagSecureEntryPoint = 0b1000000000000000;
|
||||||
|
constexpr static inline u16 FlagZoneKey = 0b0100000000000000;
|
||||||
|
constexpr static inline u16 FlagRevoked = 0b0010000000000000;
|
||||||
|
|
||||||
|
constexpr bool is_secure_entry_point() const { return flags & FlagSecureEntryPoint; }
|
||||||
|
constexpr bool is_zone_key() const { return flags & FlagZoneKey; }
|
||||||
|
constexpr bool is_revoked() const { return flags & FlagRevoked; }
|
||||||
|
constexpr bool is_key_signing_key() const { return is_secure_entry_point() && is_zone_key() && !is_revoked(); }
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::DNSKEY;
|
||||||
|
static ErrorOr<DNSKEY> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const
|
||||||
|
{
|
||||||
|
return String::formatted("DNSKEY Flags: {}{}{}{}({}), Protocol: {}, Algorithm: {}, Public Key: {}",
|
||||||
|
is_secure_entry_point() ? "sep "sv : ""sv,
|
||||||
|
is_zone_key() ? "zone "sv : ""sv,
|
||||||
|
is_revoked() ? "revoked "sv : ""sv,
|
||||||
|
is_key_signing_key() ? "ksk "sv : ""sv,
|
||||||
|
flags,
|
||||||
|
protocol,
|
||||||
|
DNSSEC::to_string(algorithm),
|
||||||
|
TRY(encode_base64(public_key)));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
struct CDNSKEY : public DNSKEY {
|
||||||
|
template<typename... Ts>
|
||||||
|
CDNSKEY(Ts&&... args)
|
||||||
|
: DNSKEY(forward<Ts>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::CDNSKEY;
|
||||||
|
static ErrorOr<CDNSKEY> from_raw(ParseContext& raw) { return DNSKEY::from_raw(raw); }
|
||||||
|
};
|
||||||
|
struct DS {
|
||||||
|
u16 key_tag;
|
||||||
|
DNSSEC::Algorithm algorithm;
|
||||||
|
DNSSEC::DigestType digest_type;
|
||||||
|
ByteBuffer digest;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::DS;
|
||||||
|
static ErrorOr<DS> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return "DS"_string; }
|
||||||
|
};
|
||||||
|
struct CDS : public DS {
|
||||||
|
template<typename... Ts>
|
||||||
|
CDS(Ts&&... args)
|
||||||
|
: DS(forward<Ts>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
static constexpr ResourceType type = ResourceType::CDS;
|
||||||
|
static ErrorOr<CDS> from_raw(ParseContext& raw) { return DS::from_raw(raw); }
|
||||||
|
};
|
||||||
|
struct SIG {
|
||||||
|
ResourceType type_covered;
|
||||||
|
DNSSEC::Algorithm algorithm;
|
||||||
|
u8 label_count;
|
||||||
|
u32 original_ttl;
|
||||||
|
UnixDateTime expiration;
|
||||||
|
UnixDateTime inception;
|
||||||
|
u16 key_tag;
|
||||||
|
DomainName signers_name;
|
||||||
|
ByteBuffer signature;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::SIG;
|
||||||
|
static ErrorOr<SIG> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const;
|
||||||
|
};
|
||||||
|
struct RRSIG : public SIG {
|
||||||
|
template<typename... Ts>
|
||||||
|
RRSIG(Ts&&... args)
|
||||||
|
: SIG(forward<Ts>(args)...)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::RRSIG;
|
||||||
|
static ErrorOr<RRSIG> from_raw(ParseContext& raw) { return SIG::from_raw(raw); }
|
||||||
|
};
|
||||||
|
struct NSEC {
|
||||||
|
DomainName next_domain_name;
|
||||||
|
Vector<ResourceType> types;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::NSEC;
|
||||||
|
static ErrorOr<NSEC> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return "NSEC"_string; }
|
||||||
|
};
|
||||||
|
struct NSEC3 {
|
||||||
|
DNSSEC::NSEC3HashAlgorithm hash_algorithm;
|
||||||
|
u8 flags;
|
||||||
|
u16 iterations;
|
||||||
|
ByteBuffer salt;
|
||||||
|
DomainName next_hashed_owner_name;
|
||||||
|
Vector<ResourceType> types;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::NSEC3;
|
||||||
|
static ErrorOr<NSEC3> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return "NSEC3"_string; }
|
||||||
|
};
|
||||||
|
struct NSEC3PARAM {
|
||||||
|
DNSSEC::NSEC3HashAlgorithm hash_algorithm;
|
||||||
|
u8 flags;
|
||||||
|
u16 iterations;
|
||||||
|
ByteBuffer salt;
|
||||||
|
|
||||||
|
constexpr static inline u8 FlagOptOut = 0b10000000;
|
||||||
|
|
||||||
|
constexpr bool is_opt_out() const { return flags & FlagOptOut; }
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::NSEC3PARAM;
|
||||||
|
static ErrorOr<NSEC3PARAM> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return "NSEC3PARAM"_string; }
|
||||||
|
};
|
||||||
|
struct TLSA {
|
||||||
|
Messages::TLSA::CertUsage cert_usage;
|
||||||
|
Messages::TLSA::Selector selector;
|
||||||
|
Messages::TLSA::MatchingType matching_type;
|
||||||
|
ByteBuffer certificate_association_data;
|
||||||
|
|
||||||
|
static ErrorOr<TLSA> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return "TLSA"_string; }
|
||||||
|
};
|
||||||
|
struct HINFO {
|
||||||
|
ByteString cpu;
|
||||||
|
ByteString os;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::HINFO;
|
||||||
|
static ErrorOr<HINFO> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const { return Error::from_string_literal("Not implemented"); }
|
||||||
|
ErrorOr<String> to_string() const { return String::formatted("HINFO CPU: '{}', OS: '{}'", StringView { cpu }, StringView { os }); }
|
||||||
|
};
|
||||||
|
struct OPT {
|
||||||
|
struct Option {
|
||||||
|
u16 code;
|
||||||
|
ByteBuffer data;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 1 1 1 1 1 1
|
||||||
|
// 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// | UDP Payload Size |
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// | Extended RCode | VER | ZZ |
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// |DO| Z |
|
||||||
|
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
|
||||||
|
// | OPT-LEN / OPT-DATA...
|
||||||
|
|
||||||
|
NetworkOrdered<u16> udp_payload_size { 0 };
|
||||||
|
NetworkOrdered<u32> extended_rcode_and_flags { 0 };
|
||||||
|
Vector<Option> options;
|
||||||
|
static constexpr u32 MaskExtendedRCode = 0b11111111000000000000000000000000;
|
||||||
|
static constexpr u32 MaskVersion = 0b00000000111100000000000000000000;
|
||||||
|
static constexpr u32 MaskDO = 0b00000000000000001000000000000000;
|
||||||
|
|
||||||
|
static constexpr ResourceType type = ResourceType::OPT;
|
||||||
|
|
||||||
|
constexpr u8 extended_rcode() const { return (extended_rcode_and_flags & MaskExtendedRCode) >> 24; }
|
||||||
|
constexpr u8 version() const { return (extended_rcode_and_flags & MaskVersion) >> 20; }
|
||||||
|
constexpr bool dnssec_ok() const { return extended_rcode_and_flags & MaskDO; }
|
||||||
|
|
||||||
|
void set_extended_rcode(u8 value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskExtendedRCode) | (value << 24); }
|
||||||
|
void set_version(u8 value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskVersion) | (value << 20); }
|
||||||
|
void set_dnssec_ok(bool value) { extended_rcode_and_flags = (extended_rcode_and_flags & ~MaskDO) | (value ? MaskDO : 0); }
|
||||||
|
|
||||||
|
static ErrorOr<OPT> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const;
|
||||||
|
ErrorOr<String> to_string() const
|
||||||
|
{
|
||||||
|
StringBuilder builder;
|
||||||
|
builder.appendff("OPT UDP Payload Size: {}, Extended RCode: {}, Version: {}, DNSSEC OK: {}", udp_payload_size, extended_rcode(), version(), dnssec_ok());
|
||||||
|
for (auto& option : options)
|
||||||
|
builder.appendff(", opt[{} = '{:hex-dump}']", option.code, option.data.bytes());
|
||||||
|
|
||||||
|
return builder.to_string();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
using Record = Variant<
|
||||||
|
Records::A,
|
||||||
|
Records::AAAA,
|
||||||
|
Records::TXT,
|
||||||
|
Records::CNAME,
|
||||||
|
Records::NS,
|
||||||
|
Records::SOA,
|
||||||
|
Records::MX,
|
||||||
|
Records::PTR,
|
||||||
|
Records::SRV,
|
||||||
|
Records::DNSKEY,
|
||||||
|
Records::CDNSKEY,
|
||||||
|
Records::DS,
|
||||||
|
Records::CDS,
|
||||||
|
Records::RRSIG,
|
||||||
|
Records::NSEC,
|
||||||
|
Records::NSEC3,
|
||||||
|
Records::NSEC3PARAM,
|
||||||
|
Records::TLSA,
|
||||||
|
Records::HINFO,
|
||||||
|
Records::OPT,
|
||||||
|
// TODO: Add more records.
|
||||||
|
ByteBuffer>; // Fallback for unknown records.
|
||||||
|
|
||||||
|
struct ResourceRecord {
|
||||||
|
DomainName name;
|
||||||
|
ResourceType type;
|
||||||
|
Class class_;
|
||||||
|
u32 ttl;
|
||||||
|
Record record;
|
||||||
|
Optional<ByteBuffer> raw;
|
||||||
|
|
||||||
|
static ErrorOr<ResourceRecord> from_raw(ParseContext&);
|
||||||
|
ErrorOr<void> to_raw(ByteBuffer&) const;
|
||||||
|
ErrorOr<String> to_string() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ZoneAuthority {
|
||||||
|
DomainName name;
|
||||||
|
ByteString admin_mailbox;
|
||||||
|
u32 serial;
|
||||||
|
u32 refresh;
|
||||||
|
u32 retry;
|
||||||
|
u32 expire;
|
||||||
|
u32 minimum_ttl;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Message {
|
||||||
|
Header header;
|
||||||
|
Vector<Question> questions;
|
||||||
|
Vector<ResourceRecord> answers;
|
||||||
|
Vector<ResourceRecord> authorities;
|
||||||
|
Vector<ResourceRecord> additional_records;
|
||||||
|
|
||||||
|
static ErrorOr<Message> from_raw(ParseContext&);
|
||||||
|
static ErrorOr<Message> from_raw(Stream&);
|
||||||
|
ErrorOr<size_t> to_raw(ByteBuffer&) const;
|
||||||
|
|
||||||
|
ErrorOr<String> format_for_log() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
489
Libraries/LibDNS/Resolver.h
Normal file
489
Libraries/LibDNS/Resolver.h
Normal file
|
@ -0,0 +1,489 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Ali Mohammad Pur <mpfard@serenityos.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/AtomicRefCounted.h>
|
||||||
|
#include <AK/HashTable.h>
|
||||||
|
#include <AK/MaybeOwned.h>
|
||||||
|
#include <AK/MemoryStream.h>
|
||||||
|
#include <AK/Random.h>
|
||||||
|
#include <AK/StringView.h>
|
||||||
|
#include <AK/TemporaryChange.h>
|
||||||
|
#include <LibCore/DateTime.h>
|
||||||
|
#include <LibCore/Promise.h>
|
||||||
|
#include <LibCore/SocketAddress.h>
|
||||||
|
#include <LibDNS/Message.h>
|
||||||
|
#include <LibThreading/MutexProtected.h>
|
||||||
|
#include <LibThreading/RWLockProtected.h>
|
||||||
|
|
||||||
|
namespace DNS {
|
||||||
|
class Resolver;
|
||||||
|
|
||||||
|
class LookupResult : public AtomicRefCounted<LookupResult>
|
||||||
|
, public Weakable<LookupResult> {
|
||||||
|
public:
|
||||||
|
explicit LookupResult(Messages::DomainName name)
|
||||||
|
: m_name(move(name))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Variant<IPv4Address, IPv6Address>> cached_addresses() const
|
||||||
|
{
|
||||||
|
Vector<Variant<IPv4Address, IPv6Address>> result;
|
||||||
|
for (auto& re : m_cached_records) {
|
||||||
|
re.record.record.visit(
|
||||||
|
[&](Messages::Records::A const& a) { result.append(a.address); },
|
||||||
|
[&](Messages::Records::AAAA const& aaaa) { result.append(aaaa.address); },
|
||||||
|
[](auto&) {});
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void check_expiration()
|
||||||
|
{
|
||||||
|
if (!m_valid)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto now = Core::DateTime::now();
|
||||||
|
for (size_t i = 0; i < m_cached_records.size();) {
|
||||||
|
auto& record = m_cached_records[i];
|
||||||
|
if (record.expiration.has_value() && record.expiration.value() < now) {
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS: Removing expired record for {}", m_name.to_string());
|
||||||
|
m_cached_records.remove(i);
|
||||||
|
} else {
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS: Keeping record for {} (expires in {})", m_name.to_string(), record.expiration.has_value() ? record.expiration.value().to_string() : "never"_string);
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_cached_records.is_empty())
|
||||||
|
m_valid = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_record(Messages::ResourceRecord record)
|
||||||
|
{
|
||||||
|
m_valid = true;
|
||||||
|
auto expiration = record.ttl > 0 ? Optional<Core::DateTime>(Core::DateTime::from_timestamp(Core::DateTime::now().timestamp() + record.ttl)) : OptionalNone();
|
||||||
|
m_cached_records.append({ move(record), move(expiration) });
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector<Messages::ResourceRecord> records() const
|
||||||
|
{
|
||||||
|
Vector<Messages::ResourceRecord> result;
|
||||||
|
for (auto& re : m_cached_records)
|
||||||
|
result.append(re.record);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_record_of_type(Messages::ResourceType type, bool later = false) const
|
||||||
|
{
|
||||||
|
if (later && m_desired_types.contains(type))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
for (auto const& re : m_cached_records) {
|
||||||
|
if (re.record.type == type)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void will_add_record_of_type(Messages::ResourceType type) { m_desired_types.set(type); }
|
||||||
|
|
||||||
|
void set_id(u16 id) { m_id = id; }
|
||||||
|
u16 id() { return m_id; }
|
||||||
|
|
||||||
|
bool is_valid() const { return m_valid; }
|
||||||
|
Messages::DomainName const& name() const { return m_name; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_valid { false };
|
||||||
|
Messages::DomainName m_name;
|
||||||
|
struct RecordWithExpiration {
|
||||||
|
Messages::ResourceRecord record;
|
||||||
|
Optional<Core::DateTime> expiration;
|
||||||
|
};
|
||||||
|
Vector<RecordWithExpiration> m_cached_records;
|
||||||
|
HashTable<Messages::ResourceType> m_desired_types;
|
||||||
|
u16 m_id { 0 };
|
||||||
|
};
|
||||||
|
|
||||||
|
class Resolver {
|
||||||
|
public:
|
||||||
|
enum class ConnectionMode {
|
||||||
|
TCP,
|
||||||
|
UDP,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SocketResult {
|
||||||
|
MaybeOwned<Core::Socket> socket;
|
||||||
|
ConnectionMode mode;
|
||||||
|
};
|
||||||
|
|
||||||
|
Resolver(Function<ErrorOr<SocketResult>()> create_socket)
|
||||||
|
: m_pending_lookups(make<RedBlackTree<u16, PendingLookup>>())
|
||||||
|
, m_create_socket(move(create_socket))
|
||||||
|
{
|
||||||
|
m_cache.with_write_locked([&](auto& cache) {
|
||||||
|
auto add_v4v6_entry = [&cache](StringView name_string, IPv4Address v4, IPv6Address v6) {
|
||||||
|
auto name = Messages::DomainName::from_string(name_string);
|
||||||
|
auto ptr = make_ref_counted<LookupResult>(name);
|
||||||
|
ptr->will_add_record_of_type(Messages::ResourceType::A);
|
||||||
|
ptr->will_add_record_of_type(Messages::ResourceType::AAAA);
|
||||||
|
cache.set(name_string, ptr);
|
||||||
|
|
||||||
|
ptr->add_record({ .name = {}, .type = Messages::ResourceType::A, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::A { v4 }, .raw = {} });
|
||||||
|
ptr->add_record({ .name = {}, .type = Messages::ResourceType::AAAA, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::AAAA { v6 }, .raw = {} });
|
||||||
|
};
|
||||||
|
|
||||||
|
add_v4v6_entry("localhost"sv, { 127, 0, 0, 1 }, IPv6Address::loopback());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<Core::Promise<Empty>> when_socket_ready()
|
||||||
|
{
|
||||||
|
auto promise = Core::Promise<Empty>::construct();
|
||||||
|
m_socket_ready_promises.append(promise);
|
||||||
|
if (has_connection(false)) {
|
||||||
|
promise->resolve({});
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!has_connection())
|
||||||
|
promise->reject(Error::from_string_literal("Failed to create socket"));
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
void reset_connection()
|
||||||
|
{
|
||||||
|
m_socket.with_write_locked([&](auto& socket) { socket = {}; });
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<LookupResult const> expect_cached(StringView name, Messages::Class class_ = Messages::Class::IN)
|
||||||
|
{
|
||||||
|
return expect_cached(name, class_, Array { Messages::ResourceType::A, Messages::ResourceType::AAAA });
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<LookupResult const> expect_cached(StringView name, Messages::Class class_, Span<Messages::ResourceType const> desired_types)
|
||||||
|
{
|
||||||
|
auto result = lookup_in_cache(name, class_, desired_types);
|
||||||
|
VERIFY(!result.is_null());
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS::expect({}) -> OK", name);
|
||||||
|
return *result;
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<LookupResult const> lookup_in_cache(StringView name, Messages::Class class_ = Messages::Class::IN)
|
||||||
|
{
|
||||||
|
return lookup_in_cache(name, class_, Array { Messages::ResourceType::A, Messages::ResourceType::AAAA });
|
||||||
|
}
|
||||||
|
|
||||||
|
RefPtr<LookupResult const> lookup_in_cache(StringView name, Messages::Class, Span<Messages::ResourceType const> desired_types)
|
||||||
|
{
|
||||||
|
return m_cache.with_read_locked([&](auto& cache) -> RefPtr<LookupResult const> {
|
||||||
|
auto it = cache.find(name);
|
||||||
|
if (it == cache.end())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
auto& result = *it->value;
|
||||||
|
for (auto const& type : desired_types) {
|
||||||
|
if (!result.has_record_of_type(type))
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<Core::Promise<NonnullRefPtr<LookupResult const>>> lookup(ByteString name, Messages::Class class_ = Messages::Class::IN)
|
||||||
|
{
|
||||||
|
return lookup(move(name), class_, Array { Messages::ResourceType::A, Messages::ResourceType::AAAA });
|
||||||
|
}
|
||||||
|
|
||||||
|
NonnullRefPtr<Core::Promise<NonnullRefPtr<LookupResult const>>> lookup(ByteString name, Messages::Class class_, Span<Messages::ResourceType const> desired_types)
|
||||||
|
{
|
||||||
|
flush_cache();
|
||||||
|
|
||||||
|
auto promise = Core::Promise<NonnullRefPtr<LookupResult const>>::construct();
|
||||||
|
|
||||||
|
if (auto maybe_ipv4 = IPv4Address::from_string(name); maybe_ipv4.has_value()) {
|
||||||
|
if (desired_types.contains_slow(Messages::ResourceType::A)) {
|
||||||
|
auto result = make_ref_counted<LookupResult>(Messages::DomainName {});
|
||||||
|
result->add_record({ .name = {}, .type = Messages::ResourceType::A, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::A { maybe_ipv4.release_value() }, .raw = {} });
|
||||||
|
promise->resolve(move(result));
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto maybe_ipv6 = IPv6Address::from_string(name); maybe_ipv6.has_value()) {
|
||||||
|
if (desired_types.contains_slow(Messages::ResourceType::AAAA)) {
|
||||||
|
auto result = make_ref_counted<LookupResult>(Messages::DomainName {});
|
||||||
|
result->add_record({ .name = {}, .type = Messages::ResourceType::AAAA, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::AAAA { maybe_ipv6.release_value() }, .raw = {} });
|
||||||
|
promise->resolve(move(result));
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (auto result = lookup_in_cache(name, class_, desired_types)) {
|
||||||
|
promise->resolve(result.release_nonnull());
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto domain_name = Messages::DomainName::from_string(name);
|
||||||
|
|
||||||
|
if (!has_connection()) {
|
||||||
|
// Use system resolver
|
||||||
|
// FIXME: Use an underlying resolver instead.
|
||||||
|
dbgln_if(DNS_DEBUG, "Not ready to resolve, using system resolver and skipping cache for {}", name);
|
||||||
|
auto record_or_error = Core::Socket::resolve_host(name, Core::Socket::SocketType::Stream);
|
||||||
|
if (record_or_error.is_error()) {
|
||||||
|
promise->reject(record_or_error.release_error());
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
auto result = make_ref_counted<LookupResult>(domain_name);
|
||||||
|
auto record = record_or_error.release_value();
|
||||||
|
record.visit(
|
||||||
|
[&](IPv4Address const& address) {
|
||||||
|
result->add_record({ .name = {}, .type = Messages::ResourceType::A, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::A { address }, .raw = {} });
|
||||||
|
},
|
||||||
|
[&](IPv6Address const& address) {
|
||||||
|
result->add_record({ .name = {}, .type = Messages::ResourceType::AAAA, .class_ = Messages::Class::IN, .ttl = 0, .record = Messages::Records::AAAA { address }, .raw = {} });
|
||||||
|
});
|
||||||
|
promise->resolve(result);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto already_in_cache = false;
|
||||||
|
auto result = m_cache.with_write_locked([&](auto& cache) -> NonnullRefPtr<LookupResult> {
|
||||||
|
auto existing = [&] -> RefPtr<LookupResult> {
|
||||||
|
if (cache.contains(name)) {
|
||||||
|
auto ptr = *cache.get(name);
|
||||||
|
|
||||||
|
already_in_cache = true;
|
||||||
|
for (auto const& type : desired_types) {
|
||||||
|
if (!ptr->has_record_of_type(type, true)) {
|
||||||
|
already_in_cache = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}();
|
||||||
|
|
||||||
|
if (existing)
|
||||||
|
return *existing;
|
||||||
|
|
||||||
|
auto ptr = make_ref_counted<LookupResult>(domain_name);
|
||||||
|
for (auto const& type : desired_types)
|
||||||
|
ptr->will_add_record_of_type(type);
|
||||||
|
cache.set(name, ptr);
|
||||||
|
return ptr;
|
||||||
|
});
|
||||||
|
|
||||||
|
Optional<u16> cached_result_id;
|
||||||
|
if (already_in_cache) {
|
||||||
|
auto id = result->id();
|
||||||
|
cached_result_id = id;
|
||||||
|
auto existing_promise = m_pending_lookups.with_write_locked([&](auto& lookups) -> RefPtr<Core::Promise<NonnullRefPtr<LookupResult const>>> {
|
||||||
|
if (auto* lookup = lookups->find(id))
|
||||||
|
return lookup->promise;
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
if (existing_promise)
|
||||||
|
return existing_promise.release_nonnull();
|
||||||
|
|
||||||
|
promise->resolve(*result);
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
Messages::Message query;
|
||||||
|
m_pending_lookups.with_read_locked([&](auto& lookups) {
|
||||||
|
do
|
||||||
|
fill_with_random({ &query.header.id, sizeof(query.header.id) });
|
||||||
|
while (lookups->find(query.header.id) != nullptr);
|
||||||
|
});
|
||||||
|
query.header.question_count = max(1u, desired_types.size());
|
||||||
|
query.header.options.set_response_code(Messages::Options::ResponseCode::NoError);
|
||||||
|
query.header.options.set_recursion_desired(true);
|
||||||
|
query.header.options.set_op_code(Messages::OpCode::Query);
|
||||||
|
for (auto const& type : desired_types) {
|
||||||
|
query.questions.append(Messages::Question {
|
||||||
|
.name = domain_name,
|
||||||
|
.type = type,
|
||||||
|
.class_ = class_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (query.questions.is_empty()) {
|
||||||
|
query.questions.append(Messages::Question {
|
||||||
|
.name = Messages::DomainName::from_string(name),
|
||||||
|
.type = Messages::ResourceType::A,
|
||||||
|
.class_ = class_,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
auto cached_entry = m_pending_lookups.with_write_locked([&](auto& pending_lookups) -> RefPtr<Core::Promise<NonnullRefPtr<LookupResult const>>> {
|
||||||
|
// One more try to make sure we're not overwriting an existing lookup
|
||||||
|
if (cached_result_id.has_value()) {
|
||||||
|
if (auto* lookup = pending_lookups->find(*cached_result_id))
|
||||||
|
return lookup->promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
pending_lookups->insert(query.header.id, { query.header.id, name, result->make_weak_ptr(), promise });
|
||||||
|
return nullptr;
|
||||||
|
});
|
||||||
|
if (cached_entry) {
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS::lookup({}) -> Already in cache", name);
|
||||||
|
return cached_entry.release_nonnull();
|
||||||
|
}
|
||||||
|
|
||||||
|
ByteBuffer query_bytes;
|
||||||
|
MUST(query.to_raw(query_bytes));
|
||||||
|
|
||||||
|
if (m_mode == ConnectionMode::TCP) {
|
||||||
|
auto original_query_bytes = query_bytes;
|
||||||
|
query_bytes = MUST(ByteBuffer::create_uninitialized(query_bytes.size() + sizeof(u16)));
|
||||||
|
NetworkOrdered<u16> size = original_query_bytes.size();
|
||||||
|
query_bytes.overwrite(0, &size, sizeof(size));
|
||||||
|
query_bytes.overwrite(sizeof(size), original_query_bytes.data(), original_query_bytes.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
auto write_result = m_socket.with_write_locked([&](auto& socket) {
|
||||||
|
return (*socket)->write_until_depleted(query_bytes.bytes());
|
||||||
|
});
|
||||||
|
if (write_result.is_error()) {
|
||||||
|
promise->reject(write_result.release_error());
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
return promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct PendingLookup {
|
||||||
|
u16 id { 0 };
|
||||||
|
ByteString name;
|
||||||
|
WeakPtr<LookupResult> result;
|
||||||
|
NonnullRefPtr<Core::Promise<NonnullRefPtr<LookupResult const>>> promise;
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorOr<Messages::Message> parse_one_message()
|
||||||
|
{
|
||||||
|
if (m_mode == ConnectionMode::UDP)
|
||||||
|
return m_socket.with_write_locked([&](auto& socket) { return Messages::Message::from_raw(**socket); });
|
||||||
|
|
||||||
|
return m_socket.with_write_locked([&](auto& socket) -> ErrorOr<Messages::Message> {
|
||||||
|
if (!TRY((*socket)->can_read_without_blocking()))
|
||||||
|
return Error::from_errno(EAGAIN);
|
||||||
|
|
||||||
|
auto size = TRY((*socket)->template read_value<NetworkOrdered<u16>>());
|
||||||
|
auto buffer = TRY(ByteBuffer::create_uninitialized(size));
|
||||||
|
TRY((*socket)->read_until_filled(buffer));
|
||||||
|
FixedMemoryStream stream { static_cast<ReadonlyBytes>(buffer) };
|
||||||
|
return Messages::Message::from_raw(stream);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void process_incoming_messages()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
if (auto result = m_socket.with_read_locked([](auto& socket) { return (*socket)->can_read_without_blocking(); }); result.is_error() || !result.value())
|
||||||
|
break;
|
||||||
|
auto message_or_err = parse_one_message();
|
||||||
|
if (message_or_err.is_error()) {
|
||||||
|
if (!message_or_err.error().is_errno() || message_or_err.error().code() != EAGAIN)
|
||||||
|
dbgln("DNS: Failed to receive message: {}", message_or_err.error());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto message = message_or_err.release_value();
|
||||||
|
auto result = m_pending_lookups.with_write_locked([&](auto& lookups) -> ErrorOr<void> {
|
||||||
|
auto* lookup = lookups->find(message.header.id);
|
||||||
|
if (!lookup)
|
||||||
|
return Error::from_string_literal("No pending lookup found for this message");
|
||||||
|
|
||||||
|
if (lookup->result.is_null())
|
||||||
|
return {}; // Message is a response to a lookup that's been purged from the cache, ignore it
|
||||||
|
|
||||||
|
auto result = lookup->result.strong_ref();
|
||||||
|
for (auto& record : message.answers)
|
||||||
|
result->add_record(move(record));
|
||||||
|
|
||||||
|
lookup->promise->resolve(*result);
|
||||||
|
lookups->remove(message.header.id);
|
||||||
|
return {};
|
||||||
|
});
|
||||||
|
if (result.is_error()) {
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS: Received a message with no pending lookup: {}", result.error());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool has_connection(bool attempt_restart = true)
|
||||||
|
{
|
||||||
|
auto result = m_socket.with_read_locked(
|
||||||
|
[&](auto& socket) { return socket.has_value() && (*socket)->is_open(); });
|
||||||
|
|
||||||
|
if (attempt_restart && !result && !m_attempting_restart) {
|
||||||
|
TemporaryChange change(m_attempting_restart, true);
|
||||||
|
auto create_result = m_create_socket();
|
||||||
|
if (create_result.is_error()) {
|
||||||
|
dbgln_if(DNS_DEBUG, "DNS: Failed to create socket: {}", create_result.error());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto [socket, mode] = MUST(move(create_result));
|
||||||
|
set_socket(move(socket), mode);
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_socket(MaybeOwned<Core::Socket> socket, ConnectionMode mode = ConnectionMode::UDP)
|
||||||
|
{
|
||||||
|
m_mode = mode;
|
||||||
|
m_socket.with_write_locked([&](auto& s) {
|
||||||
|
s = move(socket);
|
||||||
|
(*s)->on_ready_to_read = [this] {
|
||||||
|
process_incoming_messages();
|
||||||
|
};
|
||||||
|
(*s)->set_notifications_enabled(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (auto& promise : m_socket_ready_promises)
|
||||||
|
promise->resolve({});
|
||||||
|
|
||||||
|
m_socket_ready_promises.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void flush_cache()
|
||||||
|
{
|
||||||
|
m_cache.with_write_locked([&](auto& cache) {
|
||||||
|
HashTable<ByteString> to_remove;
|
||||||
|
for (auto& entry : cache) {
|
||||||
|
entry.value->check_expiration();
|
||||||
|
if (!entry.value->is_valid())
|
||||||
|
to_remove.set(entry.key);
|
||||||
|
}
|
||||||
|
for (auto const& key : to_remove)
|
||||||
|
cache.remove(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Threading::RWLockProtected<HashMap<ByteString, NonnullRefPtr<LookupResult>>> m_cache;
|
||||||
|
Threading::RWLockProtected<NonnullOwnPtr<RedBlackTree<u16, PendingLookup>>> m_pending_lookups;
|
||||||
|
Threading::RWLockProtected<Optional<MaybeOwned<Core::Socket>>> m_socket;
|
||||||
|
Function<ErrorOr<SocketResult>()> m_create_socket;
|
||||||
|
bool m_attempting_restart { false };
|
||||||
|
ConnectionMode m_mode { ConnectionMode::UDP };
|
||||||
|
Vector<NonnullRefPtr<Core::Promise<Empty>>> m_socket_ready_promises;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1,7 +1,12 @@
|
||||||
set(SOURCES
|
set (SOURCES FileSystem.cpp)
|
||||||
FileSystem.cpp
|
if (NOT WIN32)
|
||||||
TempFile.cpp
|
list(APPEND SOURCES TempFile.cpp)
|
||||||
)
|
endif()
|
||||||
|
|
||||||
serenity_lib(LibFileSystem filesystem)
|
serenity_lib(LibFileSystem filesystem)
|
||||||
target_link_libraries(LibFileSystem PRIVATE LibCoreMinimal)
|
target_link_libraries(LibFileSystem PRIVATE LibCoreMinimal)
|
||||||
|
|
||||||
|
if (WIN32)
|
||||||
|
find_path(DIRENT_INCLUDE_DIR dirent.h REQUIRED)
|
||||||
|
target_include_directories(LibFileSystem PRIVATE ${DIRENT_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
#include <LibCore/DirIterator.h>
|
#include <LibCore/DirIterator.h>
|
||||||
#include <LibCore/System.h>
|
#include <LibCore/System.h>
|
||||||
#include <LibFileSystem/FileSystem.h>
|
#include <LibFileSystem/FileSystem.h>
|
||||||
#include <limits.h>
|
|
||||||
|
|
||||||
#if !defined(AK_OS_IOS) && defined(AK_OS_BSD_GENERIC)
|
#if !defined(AK_OS_IOS) && defined(AK_OS_BSD_GENERIC)
|
||||||
# include <sys/disk.h>
|
# include <sys/disk.h>
|
||||||
#elif defined(AK_OS_LINUX)
|
#elif defined(AK_OS_LINUX)
|
||||||
# include <linux/fs.h>
|
# include <linux/fs.h>
|
||||||
|
#elif defined(AK_OS_WINDOWS)
|
||||||
|
# include <dirent.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it
|
// On Linux distros that use glibc `basename` is defined as a macro that expands to `__xpg_basename`, so we undefine it
|
||||||
|
@ -32,16 +33,19 @@ ErrorOr<ByteString> current_working_directory()
|
||||||
|
|
||||||
ErrorOr<ByteString> absolute_path(StringView path)
|
ErrorOr<ByteString> absolute_path(StringView path)
|
||||||
{
|
{
|
||||||
|
#ifndef AK_OS_WINDOWS
|
||||||
if (exists(path))
|
if (exists(path))
|
||||||
return real_path(path);
|
return real_path(path);
|
||||||
|
#endif
|
||||||
|
|
||||||
if (path.starts_with("/"sv))
|
if (LexicalPath::is_absolute_path(path))
|
||||||
return LexicalPath::canonicalized_path(path);
|
return LexicalPath::canonicalized_path(path);
|
||||||
|
|
||||||
auto working_directory = TRY(current_working_directory());
|
auto working_directory = TRY(current_working_directory());
|
||||||
return LexicalPath::absolute_path(working_directory, path);
|
return LexicalPath::absolute_path(working_directory, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef AK_OS_WINDOWS
|
||||||
ErrorOr<ByteString> real_path(StringView path)
|
ErrorOr<ByteString> real_path(StringView path)
|
||||||
{
|
{
|
||||||
if (path.is_null())
|
if (path.is_null())
|
||||||
|
@ -56,6 +60,13 @@ ErrorOr<ByteString> real_path(StringView path)
|
||||||
|
|
||||||
return ByteString { real_path, strlen(real_path) };
|
return ByteString { real_path, strlen(real_path) };
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
// NOTE: real_path on Windows does not resolve symlinks
|
||||||
|
ErrorOr<ByteString> real_path(StringView path)
|
||||||
|
{
|
||||||
|
return absolute_path(path);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool exists(StringView path)
|
bool exists(StringView path)
|
||||||
{
|
{
|
||||||
|
@ -67,60 +78,6 @@ bool exists(int fd)
|
||||||
return !Core::System::fstat(fd).is_error();
|
return !Core::System::fstat(fd).is_error();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_device(StringView path)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::stat(path);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_device(int fd)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::fstat(fd);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISBLK(st.st_mode) || S_ISCHR(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_block_device(StringView path)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::stat(path);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISBLK(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_block_device(int fd)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::fstat(fd);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISBLK(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_char_device(StringView path)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::stat(path);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISCHR(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_char_device(int fd)
|
|
||||||
{
|
|
||||||
auto st_or_error = Core::System::fstat(fd);
|
|
||||||
if (st_or_error.is_error())
|
|
||||||
return false;
|
|
||||||
auto st = st_or_error.release_value();
|
|
||||||
return S_ISCHR(st.st_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_regular_file(StringView path)
|
bool is_regular_file(StringView path)
|
||||||
{
|
{
|
||||||
auto st_or_error = Core::System::stat(path);
|
auto st_or_error = Core::System::stat(path);
|
||||||
|
@ -157,6 +114,16 @@ bool is_directory(int fd)
|
||||||
return S_ISDIR(st.st_mode);
|
return S_ISDIR(st.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef AK_OS_WINDOWS
|
||||||
|
bool is_link(StringView path)
|
||||||
|
{
|
||||||
|
ByteString string_path = path;
|
||||||
|
auto attr = GetFileAttributes(string_path.characters());
|
||||||
|
if (attr == INVALID_FILE_ATTRIBUTES)
|
||||||
|
return false;
|
||||||
|
return attr & FILE_ATTRIBUTE_REPARSE_POINT;
|
||||||
|
}
|
||||||
|
#else
|
||||||
bool is_link(StringView path)
|
bool is_link(StringView path)
|
||||||
{
|
{
|
||||||
auto st_or_error = Core::System::lstat(path);
|
auto st_or_error = Core::System::lstat(path);
|
||||||
|
@ -232,13 +199,13 @@ ErrorOr<void> copy_file(StringView destination_path, StringView source_path, str
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
||||||
struct timespec times[2] = {
|
struct timespec times[2] = {
|
||||||
#if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
|
# if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
|
||||||
source_stat.st_atimespec,
|
source_stat.st_atimespec,
|
||||||
source_stat.st_mtimespec,
|
source_stat.st_mtimespec,
|
||||||
#else
|
# else
|
||||||
source_stat.st_atim,
|
source_stat.st_atim,
|
||||||
source_stat.st_mtim,
|
source_stat.st_mtim,
|
||||||
#endif
|
# endif
|
||||||
};
|
};
|
||||||
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
|
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
|
||||||
}
|
}
|
||||||
|
@ -280,13 +247,13 @@ ErrorOr<void> copy_directory(StringView destination_path, StringView source_path
|
||||||
|
|
||||||
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
if (has_flag(preserve_mode, PreserveMode::Timestamps)) {
|
||||||
struct timespec times[2] = {
|
struct timespec times[2] = {
|
||||||
#if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
|
# if defined(AK_OS_MACOS) || defined(AK_OS_IOS)
|
||||||
source_stat.st_atimespec,
|
source_stat.st_atimespec,
|
||||||
source_stat.st_mtimespec,
|
source_stat.st_mtimespec,
|
||||||
#else
|
# else
|
||||||
source_stat.st_atim,
|
source_stat.st_atim,
|
||||||
source_stat.st_mtim,
|
source_stat.st_mtim,
|
||||||
#endif
|
# endif
|
||||||
};
|
};
|
||||||
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
|
TRY(Core::System::utimensat(AT_FDCWD, destination_path, times, 0));
|
||||||
}
|
}
|
||||||
|
@ -338,6 +305,34 @@ ErrorOr<void> move_file(StringView destination_path, StringView source_path, Pre
|
||||||
return Core::System::unlink(source_path);
|
return Core::System::unlink(source_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool can_delete_or_move(StringView path)
|
||||||
|
{
|
||||||
|
VERIFY(!path.is_empty());
|
||||||
|
auto directory = LexicalPath::dirname(path);
|
||||||
|
auto directory_has_write_access = !Core::System::access(directory, W_OK).is_error();
|
||||||
|
if (!directory_has_write_access)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto stat_or_empty = [](StringView path) {
|
||||||
|
auto stat_or_error = Core::System::stat(path);
|
||||||
|
if (stat_or_error.is_error()) {
|
||||||
|
struct stat stat { };
|
||||||
|
return stat;
|
||||||
|
}
|
||||||
|
return stat_or_error.release_value();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto directory_stat = stat_or_empty(directory);
|
||||||
|
bool is_directory_sticky = (directory_stat.st_mode & S_ISVTX) != 0;
|
||||||
|
if (!is_directory_sticky)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Directory is sticky, only the file owner, directory owner, and root can modify (rename, remove) it.
|
||||||
|
auto user_id = geteuid();
|
||||||
|
return user_id == 0 || directory_stat.st_uid == user_id || stat_or_empty(path).st_uid == user_id;
|
||||||
|
}
|
||||||
|
#endif // !AK_OS_WINDOWS
|
||||||
|
|
||||||
ErrorOr<void> remove(StringView path, RecursionMode mode)
|
ErrorOr<void> remove(StringView path, RecursionMode mode)
|
||||||
{
|
{
|
||||||
if (is_directory(path) && mode == RecursionMode::Allowed) {
|
if (is_directory(path) && mode == RecursionMode::Allowed) {
|
||||||
|
@ -368,88 +363,4 @@ ErrorOr<off_t> size_from_fstat(int fd)
|
||||||
return st.st_size;
|
return st.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorOr<off_t> block_device_size_from_ioctl(StringView path)
|
|
||||||
{
|
|
||||||
if (!path.characters_without_null_termination())
|
|
||||||
return Error::from_syscall("ioctl"sv, -EFAULT);
|
|
||||||
|
|
||||||
ByteString path_string = path;
|
|
||||||
int fd = open(path_string.characters(), O_RDONLY);
|
|
||||||
|
|
||||||
if (fd < 0)
|
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
off_t size = TRY(block_device_size_from_ioctl(fd));
|
|
||||||
|
|
||||||
if (close(fd) != 0)
|
|
||||||
return Error::from_errno(errno);
|
|
||||||
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<off_t> block_device_size_from_ioctl(int fd)
|
|
||||||
{
|
|
||||||
#if defined(AK_OS_MACOS)
|
|
||||||
u64 block_count = 0;
|
|
||||||
u32 block_size = 0;
|
|
||||||
TRY(Core::System::ioctl(fd, DKIOCGETBLOCKCOUNT, &block_count));
|
|
||||||
TRY(Core::System::ioctl(fd, DKIOCGETBLOCKSIZE, &block_size));
|
|
||||||
return static_cast<off_t>(block_count * block_size);
|
|
||||||
#elif defined(AK_OS_FREEBSD) || defined(AK_OS_NETBSD)
|
|
||||||
off_t size = 0;
|
|
||||||
TRY(Core::System::ioctl(fd, DIOCGMEDIASIZE, &size));
|
|
||||||
return size;
|
|
||||||
#elif defined(AK_OS_LINUX)
|
|
||||||
u64 size = 0;
|
|
||||||
TRY(Core::System::ioctl(fd, BLKGETSIZE64, &size));
|
|
||||||
return static_cast<off_t>(size);
|
|
||||||
#else
|
|
||||||
// FIXME: Add support for more platforms.
|
|
||||||
(void)fd;
|
|
||||||
return Error::from_string_literal("Platform does not support getting block device size");
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
bool can_delete_or_move(StringView path)
|
|
||||||
{
|
|
||||||
VERIFY(!path.is_empty());
|
|
||||||
auto directory = LexicalPath::dirname(path);
|
|
||||||
auto directory_has_write_access = !Core::System::access(directory, W_OK).is_error();
|
|
||||||
if (!directory_has_write_access)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto stat_or_empty = [](StringView path) {
|
|
||||||
auto stat_or_error = Core::System::stat(path);
|
|
||||||
if (stat_or_error.is_error()) {
|
|
||||||
struct stat stat { };
|
|
||||||
return stat;
|
|
||||||
}
|
|
||||||
return stat_or_error.release_value();
|
|
||||||
};
|
|
||||||
|
|
||||||
auto directory_stat = stat_or_empty(directory);
|
|
||||||
bool is_directory_sticky = (directory_stat.st_mode & S_ISVTX) != 0;
|
|
||||||
if (!is_directory_sticky)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
// Directory is sticky, only the file owner, directory owner, and root can modify (rename, remove) it.
|
|
||||||
auto user_id = geteuid();
|
|
||||||
return user_id == 0 || directory_stat.st_uid == user_id || stat_or_empty(path).st_uid == user_id;
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<ByteString> read_link(StringView link_path)
|
|
||||||
{
|
|
||||||
return Core::System::readlink(link_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
ErrorOr<void> link_file(StringView destination_path, StringView source_path)
|
|
||||||
{
|
|
||||||
return TRY(Core::System::symlink(source_path, TRY(get_duplicate_file_name(destination_path))));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool looks_like_shared_library(StringView path)
|
|
||||||
{
|
|
||||||
return path.ends_with(".so"sv) || path.contains(".so."sv);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/StringView.h>
|
#include <AK/StringView.h>
|
||||||
#include <LibCore/File.h>
|
#include <LibCore/File.h>
|
||||||
#include <sys/stat.h>
|
|
||||||
|
|
||||||
namespace FileSystem {
|
namespace FileSystem {
|
||||||
|
|
||||||
|
@ -31,15 +30,6 @@ bool is_regular_file(int fd);
|
||||||
bool is_directory(StringView path);
|
bool is_directory(StringView path);
|
||||||
bool is_directory(int fd);
|
bool is_directory(int fd);
|
||||||
|
|
||||||
bool is_device(StringView path);
|
|
||||||
bool is_device(int fd);
|
|
||||||
|
|
||||||
bool is_block_device(StringView path);
|
|
||||||
bool is_block_device(int fd);
|
|
||||||
|
|
||||||
bool is_char_device(StringView path);
|
|
||||||
bool is_char_device(int fd);
|
|
||||||
|
|
||||||
bool is_link(StringView path);
|
bool is_link(StringView path);
|
||||||
bool is_link(int fd);
|
bool is_link(int fd);
|
||||||
|
|
||||||
|
@ -73,13 +63,6 @@ ErrorOr<void> move_file(StringView destination_path, StringView source_path, Pre
|
||||||
ErrorOr<void> remove(StringView path, RecursionMode);
|
ErrorOr<void> remove(StringView path, RecursionMode);
|
||||||
ErrorOr<off_t> size_from_stat(StringView path);
|
ErrorOr<off_t> size_from_stat(StringView path);
|
||||||
ErrorOr<off_t> size_from_fstat(int fd);
|
ErrorOr<off_t> size_from_fstat(int fd);
|
||||||
ErrorOr<off_t> block_device_size_from_ioctl(StringView path);
|
|
||||||
ErrorOr<off_t> block_device_size_from_ioctl(int fd);
|
|
||||||
bool can_delete_or_move(StringView path);
|
bool can_delete_or_move(StringView path);
|
||||||
|
|
||||||
ErrorOr<ByteString> read_link(StringView link_path);
|
|
||||||
ErrorOr<void> link_file(StringView destination_path, StringView source_path);
|
|
||||||
|
|
||||||
bool looks_like_shared_library(StringView path);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ set(SOURCES
|
||||||
Cell.cpp
|
Cell.cpp
|
||||||
CellAllocator.cpp
|
CellAllocator.cpp
|
||||||
ConservativeVector.cpp
|
ConservativeVector.cpp
|
||||||
|
ForeignCell.cpp
|
||||||
Root.cpp
|
Root.cpp
|
||||||
Heap.cpp
|
Heap.cpp
|
||||||
HeapBlock.cpp
|
HeapBlock.cpp
|
||||||
|
@ -12,3 +13,12 @@ set(SOURCES
|
||||||
|
|
||||||
serenity_lib(LibGC gc)
|
serenity_lib(LibGC gc)
|
||||||
target_link_libraries(LibGC PRIVATE LibCore)
|
target_link_libraries(LibGC PRIVATE LibCore)
|
||||||
|
|
||||||
|
if (ENABLE_SWIFT)
|
||||||
|
generate_clang_module_map(LibGC)
|
||||||
|
target_sources(LibGC PRIVATE
|
||||||
|
Heap+Swift.swift
|
||||||
|
)
|
||||||
|
target_link_libraries(LibGC PRIVATE AK)
|
||||||
|
add_swift_target_properties(LibGC LAGOM_LIBRARIES AK)
|
||||||
|
endif()
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Swift.h>
|
||||||
#include <LibGC/Heap.h>
|
#include <LibGC/Heap.h>
|
||||||
|
|
||||||
namespace GC {
|
namespace GC {
|
||||||
|
@ -25,6 +26,6 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Heap& m_heap;
|
Heap& m_heap;
|
||||||
};
|
} SWIFT_NONCOPYABLE;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
61
Libraries/LibGC/ForeignCell.cpp
Normal file
61
Libraries/LibGC/ForeignCell.cpp
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <LibGC/DeferGC.h>
|
||||||
|
#include <LibGC/ForeignCell.h>
|
||||||
|
#include <LibGC/Heap.h>
|
||||||
|
|
||||||
|
namespace GC {
|
||||||
|
|
||||||
|
void* ForeignCell::foreign_data()
|
||||||
|
{
|
||||||
|
// !!!
|
||||||
|
auto offset = round_up_to_power_of_two(sizeof(ForeignCell), m_vtable.alignment);
|
||||||
|
return static_cast<void*>(reinterpret_cast<u8*>(this) + offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignCell::ForeignCell(ForeignCell::Vtable vtable)
|
||||||
|
: m_vtable(move(vtable))
|
||||||
|
{
|
||||||
|
if (m_vtable.initialize)
|
||||||
|
m_vtable.initialize(foreign_data(), m_vtable.class_metadata_pointer, *this);
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignCell::~ForeignCell()
|
||||||
|
{
|
||||||
|
if (m_vtable.destroy)
|
||||||
|
m_vtable.destroy(foreign_data(), m_vtable.class_metadata_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ref<ForeignCell> ForeignCell::create(Heap& heap, size_t size, ForeignCell::Vtable vtable)
|
||||||
|
{
|
||||||
|
// NOTE: GC must be deferred so that a collection during allocation doesn't get tripped
|
||||||
|
// up looking for the Cell pointer on the stack or in a register when it might only exist in the heap.
|
||||||
|
// We can't guarantee that the ForeignCell will be stashed in a proper ForeignRef/ForeignPtr or similar
|
||||||
|
// foreign type until after all the dust has settled on both sides of the FFI boundary.
|
||||||
|
VERIFY(heap.is_gc_deferred());
|
||||||
|
VERIFY(is_power_of_two(vtable.alignment));
|
||||||
|
auto& allocator = heap.allocator_for_size(sizeof(ForeignCell) + round_up_to_power_of_two(size, vtable.alignment));
|
||||||
|
auto* memory = allocator.allocate_cell(heap);
|
||||||
|
auto* foreign_cell = new (memory) ForeignCell(move(vtable));
|
||||||
|
return *foreign_cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForeignCell::finalize()
|
||||||
|
{
|
||||||
|
Base::finalize();
|
||||||
|
if (m_vtable.finalize)
|
||||||
|
m_vtable.finalize(foreign_data(), m_vtable.class_metadata_pointer);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ForeignCell::visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
Base::visit_edges(visitor);
|
||||||
|
if (m_vtable.visit_edges)
|
||||||
|
m_vtable.visit_edges(foreign_data(), m_vtable.class_metadata_pointer, visitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
180
Libraries/LibGC/ForeignCell.h
Normal file
180
Libraries/LibGC/ForeignCell.h
Normal file
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/String.h>
|
||||||
|
#include <AK/Swift.h>
|
||||||
|
#include <AK/TypeCasts.h>
|
||||||
|
#include <LibGC/Cell.h>
|
||||||
|
#include <LibGC/DeferGC.h>
|
||||||
|
|
||||||
|
namespace GC {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ForeignRef;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ForeignPtr;
|
||||||
|
|
||||||
|
#define FOREIGN_CELL(class_, base_class) \
|
||||||
|
using Base = base_class; \
|
||||||
|
friend class GC::Heap;
|
||||||
|
|
||||||
|
class ForeignCell : public Cell {
|
||||||
|
FOREIGN_CELL(ForeignCell, Cell);
|
||||||
|
|
||||||
|
public:
|
||||||
|
struct Vtable {
|
||||||
|
// Holds a pointer to the foreign vtable information such as
|
||||||
|
// a jclass in Java, or a Swift type metadata pointer
|
||||||
|
void* class_metadata_pointer = nullptr;
|
||||||
|
|
||||||
|
// FIXME: FlyString? The class name must be owned by the ForeignCell so it can vend StringViews
|
||||||
|
// We should properly cache the name and class info pointer to avoid string churn
|
||||||
|
String class_name;
|
||||||
|
|
||||||
|
size_t alignment { 1 };
|
||||||
|
|
||||||
|
void (*initialize)(void* thiz, void* clazz, Ref<Cell>);
|
||||||
|
void (*destroy)(void* thiz, void* clazz);
|
||||||
|
void (*finalize)(void* thiz, void* clazz);
|
||||||
|
void (*visit_edges)(void* thiz, void* clazz, Cell::Visitor&);
|
||||||
|
};
|
||||||
|
static Ref<ForeignCell> create(Heap&, size_t size, Vtable);
|
||||||
|
|
||||||
|
void* foreign_data() SWIFT_RETURNS_INDEPENDENT_VALUE; // technically lying to swift, but it's fiiiiine
|
||||||
|
|
||||||
|
// ^Cell
|
||||||
|
virtual void finalize() override;
|
||||||
|
virtual void visit_edges(Cell::Visitor& visitor) override;
|
||||||
|
virtual StringView class_name() const override { return m_vtable.class_name; }
|
||||||
|
|
||||||
|
~ForeignCell();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ForeignCell(Vtable vtable);
|
||||||
|
|
||||||
|
Vtable m_vtable;
|
||||||
|
} SWIFT_IMMORTAL_REFERENCE;
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ForeignRef {
|
||||||
|
friend struct ForeignPtr<T>;
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static ForeignRef allocate(Heap& heap, Args... args)
|
||||||
|
{
|
||||||
|
DeferGC const defer_gc(heap);
|
||||||
|
auto* cell = T::create(&heap, forward<Args>(args)...);
|
||||||
|
if constexpr (IsSame<decltype(cell), Cell*>) {
|
||||||
|
return ForeignRef(*verify_cast<ForeignCell>(cell));
|
||||||
|
} else {
|
||||||
|
static_assert(IsSame<decltype(cell), void*>);
|
||||||
|
auto* cast_cell = static_cast<Cell*>(cell);
|
||||||
|
return ForeignRef(*verify_cast<ForeignCell>(cast_cell));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignRef() = delete;
|
||||||
|
|
||||||
|
// This constructor should only be called directly after allocating a foreign cell by calling an FFI create method
|
||||||
|
ForeignRef(ForeignCell& cell)
|
||||||
|
: m_cell(cell)
|
||||||
|
{
|
||||||
|
// FIXME: This is super dangerous. How can we assert that the cell is actually a T?
|
||||||
|
m_data = static_cast<T*>(m_cell->foreign_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
~ForeignRef() = default;
|
||||||
|
ForeignRef(ForeignRef const& other) = default;
|
||||||
|
ForeignRef& operator=(ForeignRef const& other) = default;
|
||||||
|
|
||||||
|
RETURNS_NONNULL T* operator->() const { return m_data; }
|
||||||
|
[[nodiscard]] T& operator*() const { return *m_data; }
|
||||||
|
|
||||||
|
RETURNS_NONNULL T* ptr() const { return m_data; }
|
||||||
|
RETURNS_NONNULL operator T*() const { return m_data; }
|
||||||
|
|
||||||
|
operator T&() const { return *m_data; }
|
||||||
|
|
||||||
|
Ref<ForeignCell> cell() const { return m_cell; }
|
||||||
|
|
||||||
|
void visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
visitor.visit(m_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ref<ForeignCell> m_cell;
|
||||||
|
T* m_data { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct ForeignPtr {
|
||||||
|
constexpr ForeignPtr() = default;
|
||||||
|
|
||||||
|
// This constructor should only be called directly after allocating a foreign cell by calling an FFI create method
|
||||||
|
ForeignPtr(ForeignCell& cell)
|
||||||
|
: m_cell(&cell)
|
||||||
|
{
|
||||||
|
// FIXME: This is super dangerous. How can we assert that the cell is actually a T?
|
||||||
|
m_data = static_cast<T*>(m_cell->foreign_data());
|
||||||
|
}
|
||||||
|
|
||||||
|
// This constructor should only be called directly after allocating a foreign cell by calling an FFI create method
|
||||||
|
ForeignPtr(ForeignCell* cell)
|
||||||
|
: m_cell(cell)
|
||||||
|
{
|
||||||
|
// FIXME: This is super dangerous. How can we assert that the cell is actually a T?
|
||||||
|
m_data = m_cell ? static_cast<T*>(m_cell->foreign_data()) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignPtr(ForeignRef<T> const& other)
|
||||||
|
: m_cell(other.m_cell)
|
||||||
|
, m_data(other.m_data)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignPtr(nullptr_t)
|
||||||
|
: m_cell(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ForeignPtr(ForeignPtr const& other) = default;
|
||||||
|
ForeignPtr& operator=(ForeignPtr const& other) = default;
|
||||||
|
|
||||||
|
T* operator->() const
|
||||||
|
{
|
||||||
|
ASSERT(m_cell && m_data);
|
||||||
|
return m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] T& operator*() const
|
||||||
|
{
|
||||||
|
ASSERT(m_cell && m_data);
|
||||||
|
return *m_data;
|
||||||
|
}
|
||||||
|
|
||||||
|
operator T*() const { return m_data; }
|
||||||
|
T* ptr() const { return m_data; }
|
||||||
|
|
||||||
|
explicit operator bool() const { return !!m_cell; }
|
||||||
|
bool operator!() const { return !m_cell; }
|
||||||
|
|
||||||
|
Ptr<ForeignCell> cell() const { return m_cell; }
|
||||||
|
|
||||||
|
void visit_edges(Cell::Visitor& visitor)
|
||||||
|
{
|
||||||
|
visitor.visit(m_cell);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Ptr<ForeignCell> m_cell;
|
||||||
|
T* m_data { nullptr };
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -6,11 +6,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Types.h>
|
||||||
|
|
||||||
namespace GC {
|
namespace GC {
|
||||||
|
|
||||||
class Cell;
|
class Cell;
|
||||||
class CellAllocator;
|
class CellAllocator;
|
||||||
class DeferGC;
|
class DeferGC;
|
||||||
|
class ForeignCell;
|
||||||
class RootImpl;
|
class RootImpl;
|
||||||
class Heap;
|
class Heap;
|
||||||
class HeapBlock;
|
class HeapBlock;
|
||||||
|
|
105
Libraries/LibGC/Heap+Swift.swift
Normal file
105
Libraries/LibGC/Heap+Swift.swift
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2024, Andrew Kaster <andrew@ladybird.org>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
|
*/
|
||||||
|
|
||||||
|
import AK
|
||||||
|
@_exported import GCCxx
|
||||||
|
|
||||||
|
extension GC.Heap {
|
||||||
|
public func withDeferredGC<R, E>(_ body: () throws(E) -> R) throws(E) -> R {
|
||||||
|
let deferredRAII = GC.DeferGC(self)
|
||||||
|
_ = deferredRAII
|
||||||
|
return try body()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Cell and Cell::Visitor are not imported properly, so we have to treat them as OpaquePointer
|
||||||
|
public protocol HeapAllocatable {
|
||||||
|
static func allocate(on heap: GC.Heap) -> UnsafeMutablePointer<Self>
|
||||||
|
|
||||||
|
init(cell: OpaquePointer)
|
||||||
|
|
||||||
|
func finalize()
|
||||||
|
func visitEdges(_ visitor: OpaquePointer)
|
||||||
|
|
||||||
|
var cell: OpaquePointer { get }
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: Figure out why other modules can't conform to HeapAllocatable
|
||||||
|
public struct HeapString: HeapAllocatable {
|
||||||
|
public var string: Swift.String
|
||||||
|
|
||||||
|
public init(cell: OpaquePointer) {
|
||||||
|
self.cell = cell
|
||||||
|
self.string = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME: HeapAllocatable cannot be exposed to C++ yet, so we're off to void* paradise
|
||||||
|
public static func create(on heap: GC.Heap, string: Swift.String) -> OpaquePointer {
|
||||||
|
// NOTE: GC must be deferred so that a collection during allocation doesn't get tripped
|
||||||
|
// up looking for the Cell pointer on the stack or in a register when it might only exist in the heap
|
||||||
|
precondition(heap.is_gc_deferred())
|
||||||
|
let heapString = allocate(on: heap)
|
||||||
|
heapString.pointee.string = string
|
||||||
|
return heapString.pointee.cell
|
||||||
|
}
|
||||||
|
|
||||||
|
public var cell: OpaquePointer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Here be dragons
|
||||||
|
|
||||||
|
func asTypeMetadataPointer(_ type: Any.Type) -> UnsafeMutableRawPointer {
|
||||||
|
unsafeBitCast(type, to: UnsafeMutableRawPointer.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
func asHeapAllocatableType(_ typeMetadata: UnsafeMutableRawPointer) -> any HeapAllocatable.Type {
|
||||||
|
let typeObject = unsafeBitCast(typeMetadata, to: Any.Type.self)
|
||||||
|
guard let type = typeObject as? any HeapAllocatable.Type else {
|
||||||
|
fatalError("Passed foreign class but it wasn't a Swift type!")
|
||||||
|
}
|
||||||
|
return type
|
||||||
|
}
|
||||||
|
|
||||||
|
extension HeapAllocatable {
|
||||||
|
fileprivate static func initializeFromFFI(at this: UnsafeMutableRawPointer, cell: OpaquePointer) {
|
||||||
|
this.assumingMemoryBound(to: Self.self).initialize(to: Self.self.init(cell: cell))
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static func destroyFromFFI(at this: UnsafeMutableRawPointer) {
|
||||||
|
this.assumingMemoryBound(to: Self.self).deinitialize(count: 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static func finalizeFromFFI(at this: UnsafeMutableRawPointer) {
|
||||||
|
this.assumingMemoryBound(to: Self.self).pointee.finalize()
|
||||||
|
}
|
||||||
|
|
||||||
|
fileprivate static func visitEdgesFromFFI(at this: UnsafeMutableRawPointer, visitor: OpaquePointer) {
|
||||||
|
this.assumingMemoryBound(to: Self.self).pointee.visitEdges(visitor)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static func allocate(on heap: GC.Heap) -> UnsafeMutablePointer<Self> {
|
||||||
|
let vtable = GC.ForeignCell.Vtable(
|
||||||
|
class_metadata_pointer: asTypeMetadataPointer(Self.self),
|
||||||
|
class_name: AK.String(swiftString: Swift.String(describing: Self.self)),
|
||||||
|
alignment: MemoryLayout<Self>.alignment,
|
||||||
|
initialize: { this, typeMetadata, cell in
|
||||||
|
asHeapAllocatableType(typeMetadata!).initializeFromFFI(at: this!, cell: cell.ptr())
|
||||||
|
},
|
||||||
|
destroy: { this, typeMetadata in
|
||||||
|
asHeapAllocatableType(typeMetadata!).destroyFromFFI(at: this!)
|
||||||
|
},
|
||||||
|
finalize: { this, typeMetadata in
|
||||||
|
asHeapAllocatableType(typeMetadata!).finalizeFromFFI(at: this!)
|
||||||
|
},
|
||||||
|
visit_edges: nil
|
||||||
|
)
|
||||||
|
let cell = GC.ForeignCell.create(heap, MemoryLayout<Self>.stride, vtable)
|
||||||
|
return cell.pointee.foreign_data().assumingMemoryBound(to: Self.self)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func finalize() {}
|
||||||
|
public func visitEdges(_ visitor: OpaquePointer) {}
|
||||||
|
}
|
|
@ -13,6 +13,7 @@
|
||||||
#include <AK/Noncopyable.h>
|
#include <AK/Noncopyable.h>
|
||||||
#include <AK/NonnullOwnPtr.h>
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/StackInfo.h>
|
#include <AK/StackInfo.h>
|
||||||
|
#include <AK/Swift.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibCore/Forward.h>
|
#include <LibCore/Forward.h>
|
||||||
|
@ -73,10 +74,13 @@ public:
|
||||||
|
|
||||||
void uproot_cell(Cell* cell);
|
void uproot_cell(Cell* cell);
|
||||||
|
|
||||||
|
bool is_gc_deferred() const { return m_gc_deferrals > 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class MarkingVisitor;
|
friend class MarkingVisitor;
|
||||||
friend class GraphConstructorVisitor;
|
friend class GraphConstructorVisitor;
|
||||||
friend class DeferGC;
|
friend class DeferGC;
|
||||||
|
friend class ForeignCell;
|
||||||
|
|
||||||
void defer_gc();
|
void defer_gc();
|
||||||
void undefer_gc();
|
void undefer_gc();
|
||||||
|
@ -147,7 +151,7 @@ private:
|
||||||
bool m_collecting_garbage { false };
|
bool m_collecting_garbage { false };
|
||||||
StackInfo m_stack_info;
|
StackInfo m_stack_info;
|
||||||
AK::Function<void(HashMap<Cell*, GC::HeapRoot>&)> m_gather_embedder_roots;
|
AK::Function<void(HashMap<Cell*, GC::HeapRoot>&)> m_gather_embedder_roots;
|
||||||
};
|
} SWIFT_IMMORTAL_REFERENCE;
|
||||||
|
|
||||||
inline void Heap::did_create_root(Badge<RootImpl>, RootImpl& impl)
|
inline void Heap::did_create_root(Badge<RootImpl>, RootImpl& impl)
|
||||||
{
|
{
|
||||||
|
|
|
@ -10,11 +10,7 @@
|
||||||
# pragma GCC optimize("O3")
|
# pragma GCC optimize("O3")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <AK/Function.h>
|
|
||||||
#include <AK/NumericLimits.h>
|
|
||||||
#include <LibGfx/AntiAliasingPainter.h>
|
#include <LibGfx/AntiAliasingPainter.h>
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
|
||||||
#include <LibGfx/Line.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,7 @@
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
#include <LibGfx/DeprecatedPath.h>
|
#include <LibGfx/DeprecatedPath.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
#include <LibGfx/LineStyle.h>
|
|
||||||
#include <LibGfx/PaintStyle.h>
|
#include <LibGfx/PaintStyle.h>
|
||||||
#include <LibGfx/Quad.h>
|
|
||||||
#include <LibGfx/WindingRule.h>
|
#include <LibGfx/WindingRule.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Checked.h>
|
#include <AK/Checked.h>
|
||||||
#include <AK/Forward.h>
|
|
||||||
#include <LibCore/AnonymousBuffer.h>
|
#include <LibCore/AnonymousBuffer.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/BitmapSequence.h>
|
#include <LibGfx/BitmapSequence.h>
|
||||||
|
|
|
@ -13,7 +13,6 @@
|
||||||
#include <AK/Swift.h>
|
#include <AK/Swift.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
#include <LibGfx/SystemTheme.h>
|
|
||||||
#include <LibIPC/Decoder.h>
|
#include <LibIPC/Decoder.h>
|
||||||
#include <LibIPC/Encoder.h>
|
#include <LibIPC/Encoder.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <AK/Format.h>
|
#include <AK/Format.h>
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Math.h>
|
#include <AK/Math.h>
|
||||||
#include <AK/SIMD.h>
|
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <LibIPC/Forward.h>
|
#include <LibIPC/Forward.h>
|
||||||
|
|
||||||
|
@ -401,7 +400,8 @@ public:
|
||||||
|
|
||||||
constexpr Color with_opacity(float opacity) const
|
constexpr Color with_opacity(float opacity) const
|
||||||
{
|
{
|
||||||
return with_alpha(alpha() * opacity);
|
VERIFY(opacity >= 0 && opacity <= 1);
|
||||||
|
return with_alpha(static_cast<u8>(round(alpha() * opacity)));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr Color darkened(float amount = 0.5f) const
|
constexpr Color darkened(float amount = 0.5f) const
|
||||||
|
@ -550,9 +550,9 @@ public:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 out_r = (u8)(r * 255);
|
auto out_r = static_cast<u8>(round(r * 255));
|
||||||
u8 out_g = (u8)(g * 255);
|
auto out_g = static_cast<u8>(round(g * 255));
|
||||||
u8 out_b = (u8)(b * 255);
|
auto out_b = static_cast<u8>(round(b * 255));
|
||||||
return Color(out_r, out_g, out_b);
|
return Color(out_r, out_g, out_b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Format.h>
|
|
||||||
#include <AK/Math.h>
|
#include <AK/Math.h>
|
||||||
#include <LibGfx/DeltaE.h>
|
#include <LibGfx/DeltaE.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
|
@ -12,18 +12,13 @@
|
||||||
|
|
||||||
#include "DeprecatedPainter.h"
|
#include "DeprecatedPainter.h"
|
||||||
#include "Bitmap.h"
|
#include "Bitmap.h"
|
||||||
#include "Font/Font.h"
|
|
||||||
#include <AK/Assertions.h>
|
#include <AK/Assertions.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/Math.h>
|
#include <AK/Math.h>
|
||||||
#include <AK/Memory.h>
|
#include <AK/Memory.h>
|
||||||
#include <AK/Stack.h>
|
|
||||||
#include <AK/StdLibExtras.h>
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Utf8View.h>
|
|
||||||
#include <LibGfx/DeprecatedPath.h>
|
#include <LibGfx/DeprecatedPath.h>
|
||||||
#include <LibGfx/Palette.h>
|
#include <LibGfx/ScalingMode.h>
|
||||||
#include <LibGfx/Quad.h>
|
|
||||||
#include <LibGfx/TextLayout.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#if defined(AK_COMPILER_GCC)
|
#if defined(AK_COMPILER_GCC)
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Memory.h>
|
|
||||||
#include <AK/NonnullRefPtr.h>
|
#include <AK/NonnullRefPtr.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
|
@ -16,8 +15,6 @@
|
||||||
#include <LibGfx/PaintStyle.h>
|
#include <LibGfx/PaintStyle.h>
|
||||||
#include <LibGfx/Point.h>
|
#include <LibGfx/Point.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/ScalingMode.h>
|
|
||||||
#include <LibGfx/Size.h>
|
|
||||||
#include <LibGfx/WindingRule.h>
|
#include <LibGfx/WindingRule.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -6,12 +6,9 @@
|
||||||
|
|
||||||
#include <AK/Math.h>
|
#include <AK/Math.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <AK/TypeCasts.h>
|
|
||||||
#include <LibGfx/BoundingBox.h>
|
#include <LibGfx/BoundingBox.h>
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
#include <LibGfx/DeprecatedPainter.h>
|
||||||
#include <LibGfx/DeprecatedPath.h>
|
#include <LibGfx/DeprecatedPath.h>
|
||||||
#include <LibGfx/Font/ScaledFont.h>
|
|
||||||
#include <LibGfx/TextLayout.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
|
||||||
#include <AK/Optional.h>
|
#include <AK/Optional.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
|
|
@ -4,9 +4,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Array.h>
|
#include <AK/Memory.h>
|
||||||
#include <AK/Debug.h>
|
|
||||||
#include <AK/IntegralMath.h>
|
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibGfx/AntiAliasingPainter.h>
|
#include <LibGfx/AntiAliasingPainter.h>
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
#include <LibGfx/DeprecatedPainter.h>
|
||||||
|
|
|
@ -7,15 +7,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Bitmap.h>
|
|
||||||
#include <AK/ByteReader.h>
|
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibCore/MappedFile.h>
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
#include <LibGfx/Size.h>
|
|
||||||
|
|
||||||
struct hb_font_t;
|
struct hb_font_t;
|
||||||
|
|
||||||
|
@ -85,7 +80,7 @@ public:
|
||||||
virtual float width(StringView) const = 0;
|
virtual float width(StringView) const = 0;
|
||||||
virtual float width(Utf8View const&) const = 0;
|
virtual float width(Utf8View const&) const = 0;
|
||||||
|
|
||||||
virtual FlyString family() const = 0;
|
virtual FlyString const& family() const = 0;
|
||||||
|
|
||||||
virtual NonnullRefPtr<Font> with_size(float point_size) const = 0;
|
virtual NonnullRefPtr<Font> with_size(float point_size) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
|
||||||
#include <AK/Noncopyable.h>
|
|
||||||
#include <AK/RefCounted.h>
|
|
||||||
#include <LibCore/Resource.h>
|
#include <LibCore/Resource.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <LibGfx/Font/Typeface.h>
|
#include <LibGfx/Font/Typeface.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
|
|
@ -9,7 +9,6 @@
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <AK/Function.h>
|
#include <AK/Function.h>
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/OwnPtr.h>
|
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibGfx/Font/Typeface.h>
|
#include <LibGfx/Font/Typeface.h>
|
||||||
|
|
||||||
|
|
|
@ -8,8 +8,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <AK/HashMap.h>
|
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
#include <LibGfx/Font/Font.h>
|
#include <LibGfx/Font/Font.h>
|
||||||
#include <LibGfx/Font/Typeface.h>
|
#include <LibGfx/Font/Typeface.h>
|
||||||
|
|
||||||
|
@ -37,7 +35,7 @@ public:
|
||||||
virtual u8 baseline() const override { return m_point_height; } // FIXME: Read from font
|
virtual u8 baseline() const override { return m_point_height; } // FIXME: Read from font
|
||||||
virtual float width(StringView) const override;
|
virtual float width(StringView) const override;
|
||||||
virtual float width(Utf8View const&) const override;
|
virtual float width(Utf8View const&) const override;
|
||||||
virtual FlyString family() const override { return m_typeface->family(); }
|
virtual FlyString const& family() const override { return m_typeface->family(); }
|
||||||
|
|
||||||
virtual NonnullRefPtr<ScaledFont> scaled_with_size(float point_size) const;
|
virtual NonnullRefPtr<ScaledFont> scaled_with_size(float point_size) const;
|
||||||
virtual NonnullRefPtr<Font> with_size(float point_size) const override;
|
virtual NonnullRefPtr<Font> with_size(float point_size) const override;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <core/SkTypeface.h>
|
|
||||||
#include <harfbuzz/hb.h>
|
#include <harfbuzz/hb.h>
|
||||||
|
|
||||||
#include <LibGfx/Font/ScaledFont.h>
|
#include <LibGfx/Font/ScaledFont.h>
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/Noncopyable.h>
|
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
#include <LibGfx/Font/Font.h>
|
|
||||||
#include <LibGfx/Font/FontData.h>
|
#include <LibGfx/Font/FontData.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
|
|
||||||
|
@ -47,7 +45,7 @@ public:
|
||||||
virtual u32 glyph_count() const = 0;
|
virtual u32 glyph_count() const = 0;
|
||||||
virtual u16 units_per_em() const = 0;
|
virtual u16 units_per_em() const = 0;
|
||||||
virtual u32 glyph_id_for_code_point(u32 code_point) const = 0;
|
virtual u32 glyph_id_for_code_point(u32 code_point) const = 0;
|
||||||
virtual FlyString family() const = 0;
|
virtual FlyString const& family() const = 0;
|
||||||
virtual u16 weight() const = 0;
|
virtual u16 weight() const = 0;
|
||||||
virtual u16 width() const = 0;
|
virtual u16 width() const = 0;
|
||||||
virtual u8 slope() const = 0;
|
virtual u8 slope() const = 0;
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
|
|
||||||
#include <AK/LsanSuppressions.h>
|
#include <AK/LsanSuppressions.h>
|
||||||
#include <LibGfx/Font/FontDatabase.h>
|
#include <LibGfx/Font/FontDatabase.h>
|
||||||
#include <LibGfx/Font/Typeface.h>
|
|
||||||
#include <LibGfx/Font/TypefaceSkia.h>
|
#include <LibGfx/Font/TypefaceSkia.h>
|
||||||
|
|
||||||
#include <core/SkData.h>
|
#include <core/SkData.h>
|
||||||
#include <core/SkFontMgr.h>
|
#include <core/SkFontMgr.h>
|
||||||
#include <core/SkRefCnt.h>
|
|
||||||
#include <core/SkTypeface.h>
|
#include <core/SkTypeface.h>
|
||||||
#ifndef AK_OS_ANDROID
|
#ifndef AK_OS_ANDROID
|
||||||
# include <ports/SkFontMgr_fontconfig.h>
|
# include <ports/SkFontMgr_fontconfig.h>
|
||||||
|
@ -114,7 +112,7 @@ void TypefaceSkia::populate_glyph_page(GlyphPage& glyph_page, size_t page_index)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlyString TypefaceSkia::family() const
|
FlyString const& TypefaceSkia::family() const
|
||||||
{
|
{
|
||||||
if (!m_family.has_value()) {
|
if (!m_family.has_value()) {
|
||||||
SkString family_name;
|
SkString family_name;
|
||||||
|
|
|
@ -19,7 +19,7 @@ public:
|
||||||
virtual u32 glyph_count() const override;
|
virtual u32 glyph_count() const override;
|
||||||
virtual u16 units_per_em() const override;
|
virtual u16 units_per_em() const override;
|
||||||
virtual u32 glyph_id_for_code_point(u32 code_point) const override;
|
virtual u32 glyph_id_for_code_point(u32 code_point) const override;
|
||||||
virtual FlyString family() const override;
|
virtual FlyString const& family() const override;
|
||||||
virtual u16 weight() const override;
|
virtual u16 weight() const override;
|
||||||
virtual u16 width() const override;
|
virtual u16 width() const override;
|
||||||
virtual u8 slope() const override;
|
virtual u8 slope() const override;
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteBuffer.h>
|
|
||||||
|
|
||||||
namespace Gfx::ICC {
|
namespace Gfx::ICC {
|
||||||
|
|
||||||
class Profile;
|
class Profile;
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#include <LibGfx/ICC/Profile.h>
|
#include <LibGfx/ICC/Profile.h>
|
||||||
#include <LibGfx/ICC/Tags.h>
|
#include <LibGfx/ICC/Tags.h>
|
||||||
#include <LibGfx/ICC/WellKnownProfiles.h>
|
#include <LibGfx/ICC/WellKnownProfiles.h>
|
||||||
#include <time.h>
|
|
||||||
|
|
||||||
namespace Gfx::ICC {
|
namespace Gfx::ICC {
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/BitStream.h>
|
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <AK/Optional.h>
|
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -17,7 +17,6 @@
|
||||||
#include <LibCompress/Lzw.h>
|
#include <LibCompress/Lzw.h>
|
||||||
#include <LibGfx/ImageFormats/GIFLoader.h>
|
#include <LibGfx/ImageFormats/GIFLoader.h>
|
||||||
#include <LibGfx/Painter.h>
|
#include <LibGfx/Painter.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
|
||||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -4,14 +4,12 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteBuffer.h>
|
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <LibGfx/ImageFormats/BMPLoader.h>
|
#include <LibGfx/ImageFormats/BMPLoader.h>
|
||||||
#include <LibGfx/ImageFormats/ICOLoader.h>
|
#include <LibGfx/ImageFormats/ICOLoader.h>
|
||||||
#include <LibGfx/ImageFormats/PNGLoader.h>
|
#include <LibGfx/ImageFormats/PNGLoader.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/LexicalPath.h>
|
|
||||||
#include <LibGfx/ImageFormats/AVIFLoader.h>
|
#include <LibGfx/ImageFormats/AVIFLoader.h>
|
||||||
#include <LibGfx/ImageFormats/BMPLoader.h>
|
#include <LibGfx/ImageFormats/BMPLoader.h>
|
||||||
#include <LibGfx/ImageFormats/GIFLoader.h>
|
#include <LibGfx/ImageFormats/GIFLoader.h>
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/ByteBuffer.h>
|
|
||||||
#include <AK/HashMap.h>
|
#include <AK/HashMap.h>
|
||||||
#include <AK/OwnPtr.h>
|
#include <AK/OwnPtr.h>
|
||||||
#include <AK/RefCounted.h>
|
#include <AK/RefCounted.h>
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Debug.h>
|
|
||||||
#include <AK/Error.h>
|
#include <AK/Error.h>
|
||||||
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
#include <LibGfx/ImageFormats/JPEGXLLoader.h>
|
||||||
#include <jxl/decode.h>
|
#include <jxl/decode.h>
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/MemoryStream.h>
|
|
||||||
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
#include <LibGfx/ImageFormats/ImageDecoder.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <AK/LEB128.h>
|
#include <AK/LEB128.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/Variant.h>
|
#include <AK/Variant.h>
|
||||||
#include <LibCore/File.h>
|
|
||||||
#include <LibGfx/AntiAliasingPainter.h>
|
#include <LibGfx/AntiAliasingPainter.h>
|
||||||
#include <LibGfx/DeprecatedPainter.h>
|
#include <LibGfx/DeprecatedPainter.h>
|
||||||
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
#include <LibGfx/ImageFormats/TinyVGLoader.h>
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
#include <LibGfx/ImageFormats/WebPWriterLossless.h>
|
#include <LibGfx/ImageFormats/WebPWriterLossless.h>
|
||||||
#include <LibGfx/Point.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -8,11 +8,9 @@
|
||||||
|
|
||||||
#include <AK/BitStream.h>
|
#include <AK/BitStream.h>
|
||||||
#include <AK/Debug.h>
|
#include <AK/Debug.h>
|
||||||
#include <AK/Endian.h>
|
|
||||||
#include <AK/HashTable.h>
|
#include <AK/HashTable.h>
|
||||||
#include <AK/MemoryStream.h>
|
#include <AK/MemoryStream.h>
|
||||||
#include <AK/QuickSort.h>
|
#include <AK/QuickSort.h>
|
||||||
#include <LibCompress/DeflateTables.h>
|
|
||||||
#include <LibCompress/Huffman.h>
|
#include <LibCompress/Huffman.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/ImageFormats/WebPSharedLossless.h>
|
#include <LibGfx/ImageFormats/WebPSharedLossless.h>
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <AK/Assertions.h>
|
||||||
|
#include <AK/StdLibExtras.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <initializer_list>
|
#include <initializer_list>
|
||||||
|
|
||||||
|
|
|
@ -13,20 +13,9 @@
|
||||||
#include <LibGfx/PathSkia.h>
|
#include <LibGfx/PathSkia.h>
|
||||||
|
|
||||||
#include <AK/TypeCasts.h>
|
#include <AK/TypeCasts.h>
|
||||||
#include <core/SkBitmap.h>
|
|
||||||
#include <core/SkBlurTypes.h>
|
|
||||||
#include <core/SkCanvas.h>
|
#include <core/SkCanvas.h>
|
||||||
#include <core/SkColorFilter.h>
|
|
||||||
#include <core/SkMaskFilter.h>
|
|
||||||
#include <core/SkPath.h>
|
#include <core/SkPath.h>
|
||||||
#include <core/SkPathBuilder.h>
|
|
||||||
#include <core/SkRRect.h>
|
|
||||||
#include <core/SkSurface.h>
|
|
||||||
#include <effects/SkGradientShader.h>
|
#include <effects/SkGradientShader.h>
|
||||||
#include <effects/SkImageFilters.h>
|
|
||||||
#include <gpu/GrDirectContext.h>
|
|
||||||
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
|
||||||
#include <pathops/SkPathOps.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/ImmutableBitmap.h>
|
|
||||||
#include <LibGfx/PaintingSurface.h>
|
#include <LibGfx/PaintingSurface.h>
|
||||||
#include <LibGfx/SkiaUtils.h>
|
#include <LibGfx/SkiaUtils.h>
|
||||||
|
|
||||||
|
@ -16,9 +15,7 @@
|
||||||
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
#include <gpu/ganesh/SkSurfaceGanesh.h>
|
||||||
|
|
||||||
#ifdef AK_OS_MACOS
|
#ifdef AK_OS_MACOS
|
||||||
# include <gpu/ganesh/mtl/GrMtlBackendContext.h>
|
|
||||||
# include <gpu/ganesh/mtl/GrMtlBackendSurface.h>
|
# include <gpu/ganesh/mtl/GrMtlBackendSurface.h>
|
||||||
# include <gpu/ganesh/mtl/GrMtlDirectContext.h>
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
* SPDX-License-Identifier: BSD-2-Clause
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/Badge.h>
|
|
||||||
#include <LibGfx/Palette.h>
|
#include <LibGfx/Palette.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -9,9 +9,10 @@
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/NonnullOwnPtr.h>
|
#include <AK/NonnullOwnPtr.h>
|
||||||
#include <AK/Utf8View.h>
|
#include <AK/Utf8View.h>
|
||||||
|
#include <LibGfx/AffineTransform.h>
|
||||||
#include <LibGfx/Forward.h>
|
#include <LibGfx/Forward.h>
|
||||||
#include <LibGfx/PaintStyle.h>
|
#include <LibGfx/Point.h>
|
||||||
#include <LibGfx/ScalingMode.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibGfx/WindingRule.h>
|
#include <LibGfx/WindingRule.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
#include <AK/TypeCasts.h>
|
#include <AK/TypeCasts.h>
|
||||||
#include <LibGfx/Font/ScaledFont.h>
|
#include <LibGfx/Font/ScaledFont.h>
|
||||||
#include <LibGfx/PathSkia.h>
|
#include <LibGfx/PathSkia.h>
|
||||||
#include <core/SkContourMeasure.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <core/SkFont.h>
|
#include <core/SkFont.h>
|
||||||
#include <core/SkPath.h>
|
#include <core/SkPath.h>
|
||||||
#include <core/SkPathMeasure.h>
|
#include <core/SkPathMeasure.h>
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibGfx/Line.h>
|
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibIPC/Decoder.h>
|
#include <LibIPC/Decoder.h>
|
||||||
#include <LibIPC/Encoder.h>
|
#include <LibIPC/Encoder.h>
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#include <AK/RefPtr.h>
|
#include <AK/RefPtr.h>
|
||||||
#include <LibGfx/Bitmap.h>
|
#include <LibGfx/Bitmap.h>
|
||||||
#include <LibGfx/Size.h>
|
|
||||||
#include <LibIPC/Forward.h>
|
#include <LibIPC/Forward.h>
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
|
@ -11,7 +11,6 @@
|
||||||
#include <LibCore/ConfigFile.h>
|
#include <LibCore/ConfigFile.h>
|
||||||
#include <LibCore/DirIterator.h>
|
#include <LibCore/DirIterator.h>
|
||||||
#include <LibGfx/SystemTheme.h>
|
#include <LibGfx/SystemTheme.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
namespace Gfx {
|
namespace Gfx {
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,6 @@
|
||||||
|
|
||||||
#include <AK/ByteString.h>
|
#include <AK/ByteString.h>
|
||||||
#include <AK/Forward.h>
|
#include <AK/Forward.h>
|
||||||
#include <AK/Types.h>
|
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibCore/AnonymousBuffer.h>
|
#include <LibCore/AnonymousBuffer.h>
|
||||||
#include <LibCore/ConfigFile.h>
|
#include <LibCore/ConfigFile.h>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue