Compare commits
7 Commits
e77de1804f
...
cc2cc2849e
Author | SHA1 | Date |
---|---|---|
Bananymous | cc2cc2849e | |
Bananymous | 06f4b0b29a | |
Bananymous | e22821799b | |
Bananymous | 14dd9294aa | |
Bananymous | 83e3409bd8 | |
Bananymous | 7630170ed6 | |
Bananymous | 0af74fccda |
|
@ -1,280 +0,0 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/New.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
String::String()
|
||||
{
|
||||
}
|
||||
|
||||
String::String(const String& other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::String(String&& other)
|
||||
{
|
||||
*this = move(other);
|
||||
}
|
||||
|
||||
String::String(StringView other)
|
||||
{
|
||||
*this = other;
|
||||
}
|
||||
|
||||
String::~String()
|
||||
{
|
||||
clear();
|
||||
}
|
||||
|
||||
String& String::operator=(const String& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(String&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
if (other.has_sso())
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
else
|
||||
{
|
||||
m_storage.general_storage = other.m_storage.general_storage;
|
||||
m_has_sso = false;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
|
||||
other.m_size = 0;
|
||||
other.m_storage.sso_storage = SSOStorage();
|
||||
other.m_has_sso = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& String::operator=(StringView other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size());
|
||||
m_size = other.size();
|
||||
data()[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
memmove(data() + index + 1, data() + index, m_size - index);
|
||||
data()[index] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||
memcpy(data() + index, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void String::pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void String::clear()
|
||||
{
|
||||
if (!has_sso())
|
||||
{
|
||||
deallocator(m_storage.general_storage.data);
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
}
|
||||
m_size = 0;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
bool String::operator==(const String& str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool String::operator==(StringView str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool String::operator==(const char* cstr) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != cstr[i])
|
||||
return false;
|
||||
if (cstr[size()] != '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::resize(size_type new_size, char init_c)
|
||||
{
|
||||
if (m_size == new_size)
|
||||
return {};
|
||||
|
||||
// expanding
|
||||
if (m_size < new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
memset(data() + m_size, init_c, new_size - m_size);
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> String::shrink_to_fit()
|
||||
{
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
char* data = m_storage.general_storage.data;
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
memcpy(this->data(), data, m_size + 1);
|
||||
deallocator(data);
|
||||
return {};
|
||||
}
|
||||
|
||||
GeneralStorage& storage = m_storage.general_storage;
|
||||
if (storage.capacity == m_size)
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(m_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, storage.data, m_size);
|
||||
deallocator(storage.data);
|
||||
|
||||
storage.capacity = m_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
String::size_type String::capacity() const
|
||||
{
|
||||
if (has_sso())
|
||||
return sso_capacity;
|
||||
return m_storage.general_storage.capacity;
|
||||
}
|
||||
|
||||
char* String::data()
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
const char* String::data() const
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
ErrorOr<void> String::ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
if (has_sso() && fits_in_sso(new_size))
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(new_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
if (m_size)
|
||||
memcpy(new_data, data(), m_size + 1);
|
||||
|
||||
if (has_sso())
|
||||
{
|
||||
m_storage.general_storage = GeneralStorage();
|
||||
m_has_sso = false;
|
||||
}
|
||||
else
|
||||
deallocator(m_storage.general_storage.data);
|
||||
|
||||
auto& storage = m_storage.general_storage;
|
||||
storage.capacity = new_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool String::has_sso() const
|
||||
{
|
||||
return m_has_sso;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,196 +1,11 @@
|
|||
#include <BAN/String.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
||||
StringView::StringView()
|
||||
{ }
|
||||
|
||||
StringView::StringView(const String& other)
|
||||
: StringView(other.data(), other.size())
|
||||
{ }
|
||||
|
||||
StringView::StringView(const char* string, size_type len)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
len = strlen(string);
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
|
||||
char StringView::operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
bool StringView::operator==(const String& other) const
|
||||
{
|
||||
if (m_size != other.size())
|
||||
return false;
|
||||
return memcmp(m_data, other.data(), m_size) == 0;
|
||||
}
|
||||
|
||||
bool StringView::operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
return false;
|
||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||
}
|
||||
|
||||
bool StringView::operator==(const char* other) const
|
||||
{
|
||||
if (memcmp(m_data, other, m_size))
|
||||
return false;
|
||||
return other[m_size] == '\0';
|
||||
}
|
||||
|
||||
StringView StringView::substring(size_type index, size_type len) const
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
if (len == size_type(-1))
|
||||
len = m_size - index;
|
||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||
StringView result;
|
||||
result.m_data = m_data + index;
|
||||
result.m_size = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> StringView::split(char delim, bool allow_empties) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> StringView::split(bool(*comp)(char), bool allow_empties) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
char StringView::back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
char StringView::front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
BAN::Optional<StringView::size_type> StringView::find(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<StringView::size_type> StringView::find(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (comp(m_data[i]))
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool StringView::contains(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
StringView::size_type StringView::count(char ch) const
|
||||
{
|
||||
size_type result = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool StringView::empty() const
|
||||
{
|
||||
return m_size == 0;
|
||||
}
|
||||
|
||||
StringView::size_type StringView::size() const
|
||||
{
|
||||
return m_size;
|
||||
}
|
||||
|
||||
const char* StringView::data() const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,7 +5,6 @@ project(BAN CXX)
|
|||
set(BAN_SOURCES
|
||||
BAN/Assert.cpp
|
||||
BAN/New.cpp
|
||||
BAN/String.cpp
|
||||
BAN/StringView.cpp
|
||||
BAN/Time.cpp
|
||||
)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Variant.h>
|
||||
|
||||
#include <errno.h>
|
||||
|
@ -56,7 +55,7 @@ namespace BAN
|
|||
#endif
|
||||
|
||||
uint64_t get_error_code() const { return m_error_code; }
|
||||
BAN::StringView get_message() const
|
||||
const char* get_message() const
|
||||
{
|
||||
#ifdef __is_kernel
|
||||
if (m_error_code & kernel_error_mask)
|
||||
|
@ -64,7 +63,7 @@ namespace BAN
|
|||
#endif
|
||||
if (auto* desc = strerrordesc_np(m_error_code))
|
||||
return desc;
|
||||
return "Unknown error"sv;
|
||||
return "Unknown error";
|
||||
}
|
||||
|
||||
private:
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
|
||||
#include <BAN/Errors.h>
|
||||
#include <BAN/Formatter.h>
|
||||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/New.h>
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -18,28 +19,125 @@ namespace BAN
|
|||
static constexpr size_type sso_capacity = 15;
|
||||
|
||||
public:
|
||||
String();
|
||||
String(const String&);
|
||||
String(String&&);
|
||||
String(StringView);
|
||||
~String();
|
||||
String() {}
|
||||
String(const String& other) { *this = other; }
|
||||
String(String&& other) { *this = move(other); }
|
||||
String(StringView other) { *this = other; }
|
||||
~String() { clear(); }
|
||||
|
||||
template<typename... Args>
|
||||
static String formatted(const char* format, const Args&... args);
|
||||
static String formatted(const char* format, const Args&... args)
|
||||
{
|
||||
String result;
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
String& operator=(const String&);
|
||||
String& operator=(String&&);
|
||||
String& operator=(StringView);
|
||||
String& operator=(const String& other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
m_size = other.size();
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> push_back(char);
|
||||
ErrorOr<void> insert(char, size_type);
|
||||
ErrorOr<void> insert(StringView, size_type);
|
||||
ErrorOr<void> append(StringView);
|
||||
String& operator=(String&& other)
|
||||
{
|
||||
clear();
|
||||
|
||||
void pop_back();
|
||||
void remove(size_type);
|
||||
if (other.has_sso())
|
||||
memcpy(data(), other.data(), other.size() + 1);
|
||||
else
|
||||
{
|
||||
m_storage.general_storage = other.m_storage.general_storage;
|
||||
m_has_sso = false;
|
||||
}
|
||||
m_size = other.m_size;
|
||||
|
||||
void clear();
|
||||
other.m_size = 0;
|
||||
other.m_storage.sso_storage = SSOStorage();
|
||||
other.m_has_sso = true;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
String& operator=(StringView other)
|
||||
{
|
||||
clear();
|
||||
MUST(ensure_capacity(other.size()));
|
||||
memcpy(data(), other.data(), other.size());
|
||||
m_size = other.size();
|
||||
data()[m_size] = '\0';
|
||||
return *this;
|
||||
}
|
||||
|
||||
ErrorOr<void> push_back(char c)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
data()[m_size] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(char c, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + 1));
|
||||
memmove(data() + index + 1, data() + index, m_size - index);
|
||||
data()[index] = c;
|
||||
m_size++;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> insert(StringView str, size_type index)
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memmove(data() + index + str.size(), data() + index, m_size - index);
|
||||
memcpy(data() + index, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> append(StringView str)
|
||||
{
|
||||
TRY(ensure_capacity(m_size + str.size()));
|
||||
memcpy(data() + m_size, str.data(), str.size());
|
||||
m_size += str.size();
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
void pop_back()
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void remove(size_type index)
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
memcpy(data() + index, data() + index + 1, m_size - index);
|
||||
m_size--;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!has_sso())
|
||||
{
|
||||
deallocator(m_storage.general_storage.data);
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
}
|
||||
m_size = 0;
|
||||
data()[m_size] = '\0';
|
||||
}
|
||||
|
||||
const_iterator begin() const { return const_iterator(data()); }
|
||||
iterator begin() { return iterator(data()); }
|
||||
|
@ -55,27 +153,151 @@ namespace BAN
|
|||
char operator[](size_type index) const { ASSERT(index < m_size); return data()[index]; }
|
||||
char& operator[](size_type index) { ASSERT(index < m_size); return data()[index]; }
|
||||
|
||||
bool operator==(const String&) const;
|
||||
bool operator==(StringView) const;
|
||||
bool operator==(const char*) const;
|
||||
bool operator==(const String& str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> resize(size_type, char = '\0');
|
||||
ErrorOr<void> reserve(size_type);
|
||||
ErrorOr<void> shrink_to_fit();
|
||||
bool operator==(StringView str) const
|
||||
{
|
||||
if (size() != str.size())
|
||||
return false;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != str.data()[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool operator==(const char* cstr) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (data()[i] != cstr[i])
|
||||
return false;
|
||||
if (cstr[size()] != '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ErrorOr<void> resize(size_type new_size, char init_c = '\0')
|
||||
{
|
||||
if (m_size == new_size)
|
||||
return {};
|
||||
|
||||
// expanding
|
||||
if (m_size < new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
memset(data() + m_size, init_c, new_size - m_size);
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
m_size = new_size;
|
||||
data()[m_size] = '\0';
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> reserve(size_type new_size)
|
||||
{
|
||||
TRY(ensure_capacity(new_size));
|
||||
return {};
|
||||
}
|
||||
|
||||
ErrorOr<void> shrink_to_fit()
|
||||
{
|
||||
if (has_sso())
|
||||
return {};
|
||||
|
||||
if (fits_in_sso())
|
||||
{
|
||||
char* data = m_storage.general_storage.data;
|
||||
m_storage.sso_storage = SSOStorage();
|
||||
m_has_sso = true;
|
||||
memcpy(this->data(), data, m_size + 1);
|
||||
deallocator(data);
|
||||
return {};
|
||||
}
|
||||
|
||||
GeneralStorage& storage = m_storage.general_storage;
|
||||
if (storage.capacity == m_size)
|
||||
return {};
|
||||
|
||||
char* new_data = (char*)allocator(m_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
memcpy(new_data, storage.data, m_size);
|
||||
deallocator(storage.data);
|
||||
|
||||
storage.capacity = m_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
StringView sv() const { return StringView(data(), size()); }
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
size_type capacity() const;
|
||||
|
||||
char* data();
|
||||
const char* data() const;
|
||||
size_type capacity() const
|
||||
{
|
||||
if (has_sso())
|
||||
return sso_capacity;
|
||||
return m_storage.general_storage.capacity;
|
||||
}
|
||||
|
||||
char* data()
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
const char* data() const
|
||||
{
|
||||
if (has_sso())
|
||||
return m_storage.sso_storage.data;
|
||||
return m_storage.general_storage.data;
|
||||
}
|
||||
|
||||
private:
|
||||
ErrorOr<void> ensure_capacity(size_type);
|
||||
ErrorOr<void> ensure_capacity(size_type new_size)
|
||||
{
|
||||
if (m_size >= new_size)
|
||||
return {};
|
||||
if (has_sso() && fits_in_sso(new_size))
|
||||
return {};
|
||||
|
||||
bool has_sso() const;
|
||||
char* new_data = (char*)allocator(new_size + 1);
|
||||
if (new_data == nullptr)
|
||||
return Error::from_errno(ENOMEM);
|
||||
|
||||
if (m_size)
|
||||
memcpy(new_data, data(), m_size + 1);
|
||||
|
||||
if (has_sso())
|
||||
{
|
||||
m_storage.general_storage = GeneralStorage();
|
||||
m_has_sso = false;
|
||||
}
|
||||
else
|
||||
deallocator(m_storage.general_storage.data);
|
||||
|
||||
auto& storage = m_storage.general_storage;
|
||||
storage.capacity = new_size;
|
||||
storage.data = new_data;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
bool has_sso() const { return m_has_sso; }
|
||||
|
||||
bool fits_in_sso() const { return fits_in_sso(m_size); }
|
||||
static bool fits_in_sso(size_type size) { return size < sso_capacity; }
|
||||
|
@ -100,14 +322,6 @@ namespace BAN
|
|||
size_type m_has_sso : 1 { true };
|
||||
};
|
||||
|
||||
template<typename... Args>
|
||||
String String::formatted(const char* format, const Args&... args)
|
||||
{
|
||||
String result;
|
||||
BAN::Formatter::print([&](char c){ MUST(result.push_back(c)); }, format, args...);
|
||||
return result;
|
||||
}
|
||||
|
||||
template<>
|
||||
struct hash<String>
|
||||
{
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <BAN/ForwardList.h>
|
||||
#include <BAN/Iterators.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
namespace BAN
|
||||
{
|
||||
|
@ -15,37 +16,171 @@ namespace BAN
|
|||
using const_iterator = ConstIteratorSimple<char, StringView>;
|
||||
|
||||
public:
|
||||
StringView();
|
||||
StringView() {}
|
||||
StringView(const String&);
|
||||
StringView(const char*, size_type = -1);
|
||||
StringView(const char* string, size_type len = -1)
|
||||
{
|
||||
if (len == size_type(-1))
|
||||
len = strlen(string);
|
||||
m_data = string;
|
||||
m_size = len;
|
||||
}
|
||||
|
||||
const_iterator begin() const { return const_iterator(m_data); }
|
||||
const_iterator end() const { return const_iterator(m_data + m_size); }
|
||||
|
||||
char operator[](size_type) const;
|
||||
char operator[](size_type index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return m_data[index];
|
||||
}
|
||||
|
||||
bool operator==(const String&) const;
|
||||
bool operator==(StringView) const;
|
||||
bool operator==(const char*) const;
|
||||
bool operator==(StringView other) const
|
||||
{
|
||||
if (m_size != other.m_size)
|
||||
return false;
|
||||
return memcmp(m_data, other.m_data, m_size) == 0;
|
||||
}
|
||||
|
||||
StringView substring(size_type, size_type = -1) const;
|
||||
bool operator==(const char* other) const
|
||||
{
|
||||
if (memcmp(m_data, other, m_size))
|
||||
return false;
|
||||
return other[m_size] == '\0';
|
||||
}
|
||||
|
||||
ErrorOr<Vector<StringView>> split(char, bool = false) const;
|
||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool = false) const;
|
||||
StringView substring(size_type index, size_type len = -1) const
|
||||
{
|
||||
ASSERT(index <= m_size);
|
||||
if (len == size_type(-1))
|
||||
len = m_size - index;
|
||||
ASSERT(len <= m_size - index); // weird order to avoid overflow
|
||||
StringView result;
|
||||
result.m_data = m_data + index;
|
||||
result.m_size = len;
|
||||
return result;
|
||||
}
|
||||
|
||||
char back() const;
|
||||
char front() const;
|
||||
ErrorOr<Vector<StringView>> split(char delim, bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(char) const;
|
||||
BAN::Optional<size_type> find(bool(*comp)(char)) const;
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
bool contains(char) const;
|
||||
size_type count(char) const;
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (m_data[i] == delim)
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const;
|
||||
size_type size() const;
|
||||
ErrorOr<Vector<StringView>> split(bool(*comp)(char), bool allow_empties = false) const
|
||||
{
|
||||
size_type count = 0;
|
||||
{
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
count++;
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start != m_size)
|
||||
count++;
|
||||
}
|
||||
|
||||
const char* data() const;
|
||||
Vector<StringView> result;
|
||||
TRY(result.reserve(count));
|
||||
|
||||
size_type start = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
{
|
||||
if (comp(m_data[i]))
|
||||
{
|
||||
if (allow_empties || start != i)
|
||||
TRY(result.push_back(this->substring(start, i - start)));
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
if (start < m_size || (start == m_size && allow_empties))
|
||||
TRY(result.push_back(this->substring(start)));
|
||||
return result;
|
||||
}
|
||||
|
||||
char back() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[m_size - 1];
|
||||
}
|
||||
|
||||
char front() const
|
||||
{
|
||||
ASSERT(m_size > 0);
|
||||
return m_data[0];
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
BAN::Optional<size_type> find(bool(*comp)(char)) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (comp(m_data[i]))
|
||||
return i;
|
||||
return {};
|
||||
}
|
||||
|
||||
bool contains(char ch) const
|
||||
{
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
size_type count(char ch) const
|
||||
{
|
||||
size_type result = 0;
|
||||
for (size_type i = 0; i < m_size; i++)
|
||||
if (m_data[i] == ch)
|
||||
result++;
|
||||
return result;
|
||||
}
|
||||
|
||||
bool empty() const { return m_size == 0; }
|
||||
size_type size() const { return m_size; }
|
||||
const char* data() const { return m_data; }
|
||||
|
||||
private:
|
||||
const char* m_data = nullptr;
|
||||
|
|
|
@ -137,7 +137,6 @@ endif()
|
|||
set(BAN_SOURCES
|
||||
../BAN/BAN/Assert.cpp
|
||||
../BAN/BAN/New.cpp
|
||||
../BAN/BAN/String.cpp
|
||||
../BAN/BAN/StringView.cpp
|
||||
../BAN/BAN/Time.cpp
|
||||
)
|
||||
|
|
|
@ -1,21 +0,0 @@
|
|||
#pragma once
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
namespace Kernel::API
|
||||
{
|
||||
|
||||
struct DirectoryEntry
|
||||
{
|
||||
size_t rec_len { 0 };
|
||||
struct dirent dirent;
|
||||
DirectoryEntry* next() const { return (DirectoryEntry*)((uintptr_t)this + rec_len); }
|
||||
};
|
||||
|
||||
struct DirectoryEntryList
|
||||
{
|
||||
size_t entry_count { 0 };
|
||||
DirectoryEntry array[];
|
||||
};
|
||||
|
||||
}
|
|
@ -1,11 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/StringView.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
enum class ErrorCode : uint32_t
|
||||
enum class ErrorCode
|
||||
{
|
||||
None,
|
||||
ACPI_NoRootSDT,
|
||||
|
@ -31,6 +29,6 @@ namespace Kernel
|
|||
Count
|
||||
};
|
||||
|
||||
BAN::StringView error_string(ErrorCode);
|
||||
const char* error_string(ErrorCode);
|
||||
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override;
|
||||
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;
|
||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override;
|
||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||
|
|
|
@ -7,11 +7,11 @@
|
|||
#include <BAN/Vector.h>
|
||||
#include <BAN/WeakPtr.h>
|
||||
|
||||
#include <kernel/API/DirectoryEntry.h>
|
||||
#include <kernel/Credentials.h>
|
||||
#include <kernel/Debug.h>
|
||||
#include <kernel/Lock/Mutex.h>
|
||||
|
||||
#include <dirent.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
|
@ -19,8 +19,6 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
using namespace API;
|
||||
|
||||
class FileBackedRegion;
|
||||
class SharedFileData;
|
||||
|
||||
|
@ -92,7 +90,7 @@ namespace Kernel
|
|||
|
||||
// Directory API
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
||||
BAN::ErrorOr<void> list_next_inodes(off_t, DirectoryEntryList*, size_t);
|
||||
BAN::ErrorOr<size_t> list_next_inodes(off_t, struct dirent* list, size_t list_size);
|
||||
BAN::ErrorOr<void> create_file(BAN::StringView, mode_t, uid_t, gid_t);
|
||||
BAN::ErrorOr<void> create_directory(BAN::StringView, mode_t, uid_t, gid_t);
|
||||
BAN::ErrorOr<void> unlink(BAN::StringView);
|
||||
|
@ -127,7 +125,7 @@ namespace Kernel
|
|||
|
||||
// Directory API
|
||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) { return BAN::Error::from_errno(ENOTSUP); }
|
||||
|
|
|
@ -141,7 +141,7 @@ namespace Kernel
|
|||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override final;
|
||||
virtual BAN::ErrorOr<void> list_next_inodes_impl(off_t, DirectoryEntryList*, size_t) override final;
|
||||
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override final;
|
||||
virtual BAN::ErrorOr<void> create_file_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
||||
virtual BAN::ErrorOr<void> create_directory_impl(BAN::StringView, mode_t, uid_t, gid_t) override final;
|
||||
virtual BAN::ErrorOr<void> unlink_impl(BAN::StringView) override;
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<int> fcntl(int fd, int cmd, int extra);
|
||||
|
||||
BAN::ErrorOr<void> seek(int fd, off_t offset, int whence);
|
||||
BAN::ErrorOr<off_t> seek(int fd, off_t offset, int whence);
|
||||
BAN::ErrorOr<off_t> tell(int) const;
|
||||
|
||||
BAN::ErrorOr<void> fstat(int fd, struct stat*) const;
|
||||
|
@ -47,7 +47,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<size_t> read(int fd, BAN::ByteSpan);
|
||||
BAN::ErrorOr<size_t> write(int fd, BAN::ConstByteSpan);
|
||||
|
||||
BAN::ErrorOr<void> read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size);
|
||||
BAN::ErrorOr<size_t> read_dir_entries(int fd, struct dirent* list, size_t list_len);
|
||||
|
||||
BAN::ErrorOr<BAN::StringView> path_of(int) const;
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> inode_of(int);
|
||||
|
|
|
@ -149,7 +149,7 @@ namespace Kernel
|
|||
|
||||
BAN::ErrorOr<void> mount(BAN::StringView source, BAN::StringView target);
|
||||
|
||||
BAN::ErrorOr<long> sys_readdir(int fd, DirectoryEntryList* buffer, size_t buffer_size);
|
||||
BAN::ErrorOr<long> sys_readdir(int fd, struct dirent* list, size_t list_len);
|
||||
|
||||
BAN::ErrorOr<long> sys_mmap(const sys_mmap_t*);
|
||||
BAN::ErrorOr<long> sys_munmap(void* addr, size_t len);
|
||||
|
|
|
@ -1,34 +1,38 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <kernel/Errors.h>
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
namespace Kernel
|
||||
{
|
||||
|
||||
static BAN::StringView s_error_strings[] {
|
||||
"No Error"sv,
|
||||
"ACPI could not find root SDT header"sv,
|
||||
"ACPI no such header"sv,
|
||||
static const char* s_error_strings[] {
|
||||
"No Error",
|
||||
"ACPI could not find root SDT header",
|
||||
"ACPI no such header",
|
||||
"ACPI root invalid",
|
||||
"Invalid ext2 filesystem"sv,
|
||||
"Ext2 filesystem corrupted"sv,
|
||||
"Ext2 filesystem out of inodes"sv,
|
||||
"Attempted to access outside of device boundaries"sv,
|
||||
"Device has invalid GPT header"sv,
|
||||
"Device does not support LBA addressing"sv,
|
||||
"Address mark not found"sv,
|
||||
"Track zero not found"sv,
|
||||
"Aborted command"sv,
|
||||
"Media change request"sv,
|
||||
"ID not found"sv,
|
||||
"Media changed"sv,
|
||||
"Uncorrectable data error"sv,
|
||||
"Bad Block detected"sv,
|
||||
"Unsupported ata device"sv,
|
||||
"Font file too small"sv,
|
||||
"Unsupported font format"sv,
|
||||
"Invalid ext2 filesystem",
|
||||
"Ext2 filesystem corrupted",
|
||||
"Ext2 filesystem out of inodes",
|
||||
"Attempted to access outside of device boundaries",
|
||||
"Device has invalid GPT header",
|
||||
"Device does not support LBA addressing",
|
||||
"Address mark not found",
|
||||
"Track zero not found",
|
||||
"Aborted command",
|
||||
"Media change request",
|
||||
"ID not found",
|
||||
"Media changed",
|
||||
"Uncorrectable data error",
|
||||
"Bad Block detected",
|
||||
"Unsupported ata device",
|
||||
"Font file too small",
|
||||
"Unsupported font format",
|
||||
};
|
||||
static_assert(sizeof(s_error_strings) / sizeof(*s_error_strings) == (size_t)ErrorCode::Count);
|
||||
|
||||
BAN::StringView error_string(ErrorCode error)
|
||||
const char* error_string(ErrorCode error)
|
||||
{
|
||||
ASSERT((uint32_t)error < (uint32_t)ErrorCode::Count);
|
||||
return s_error_strings[(uint32_t)error];
|
||||
|
|
|
@ -299,16 +299,13 @@ done:
|
|||
m_fs.delete_inode(ino());
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Ext2Inode::list_next_inodes_impl(off_t offset, DirectoryEntryList* list, size_t list_size)
|
||||
BAN::ErrorOr<size_t> Ext2Inode::list_next_inodes_impl(off_t offset, struct dirent* list, size_t list_size)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
ASSERT(offset >= 0);
|
||||
|
||||
if (static_cast<BAN::make_unsigned_t<decltype(offset)>>(offset) >= max_used_data_block_count())
|
||||
{
|
||||
list->entry_count = 0;
|
||||
return {};
|
||||
}
|
||||
return 0;
|
||||
|
||||
// FIXME: can we actually assume directories have all their blocks allocated
|
||||
const uint32_t block_index = fs_block_of_data_block_index(offset).value();
|
||||
|
@ -318,26 +315,25 @@ done:
|
|||
m_fs.read_block(block_index, block_buffer);
|
||||
|
||||
// First determine if we have big enough list
|
||||
size_t entry_count = 0;
|
||||
{
|
||||
BAN::ConstByteSpan entry_span = block_buffer.span();
|
||||
|
||||
size_t needed_size = sizeof(DirectoryEntryList);
|
||||
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
||||
{
|
||||
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
||||
if (entry.inode)
|
||||
needed_size += sizeof(DirectoryEntry) + entry.name_len + 1;
|
||||
entry_count++;
|
||||
entry_span = entry_span.slice(entry.rec_len);
|
||||
}
|
||||
|
||||
if (needed_size > list_size)
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
if (entry_count > list_size)
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
}
|
||||
|
||||
// Second fill the list
|
||||
{
|
||||
DirectoryEntry* ptr = list->array;
|
||||
list->entry_count = 0;
|
||||
dirent* dirp = list;
|
||||
|
||||
BAN::ConstByteSpan entry_span = block_buffer.span();
|
||||
while (entry_span.size() >= sizeof(Ext2::LinkedDirectoryEntry))
|
||||
|
@ -345,20 +341,16 @@ done:
|
|||
auto& entry = entry_span.as<const Ext2::LinkedDirectoryEntry>();
|
||||
if (entry.inode)
|
||||
{
|
||||
ptr->dirent.d_ino = entry.inode;
|
||||
ptr->dirent.d_type = entry.file_type;
|
||||
ptr->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
|
||||
memcpy(ptr->dirent.d_name, entry.name, entry.name_len);
|
||||
ptr->dirent.d_name[entry.name_len] = '\0';
|
||||
|
||||
ptr = ptr->next();
|
||||
list->entry_count++;
|
||||
dirp->d_ino = entry.inode;
|
||||
dirp->d_type = entry.file_type;
|
||||
strncpy(dirp->d_name, entry.name, entry.name_len);
|
||||
dirp++;
|
||||
}
|
||||
entry_span = entry_span.slice(entry.rec_len);
|
||||
}
|
||||
}
|
||||
|
||||
return {};
|
||||
return entry_count;
|
||||
}
|
||||
|
||||
static bool mode_has_valid_type(mode_t mode)
|
||||
|
|
|
@ -70,7 +70,7 @@ namespace Kernel
|
|||
return find_inode_impl(name);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> Inode::list_next_inodes(off_t offset, DirectoryEntryList* list, size_t list_len)
|
||||
BAN::ErrorOr<size_t> Inode::list_next_inodes(off_t offset, struct dirent* list, size_t list_len)
|
||||
{
|
||||
LockGuard _(m_mutex);
|
||||
if (!mode().ifdir())
|
||||
|
|
|
@ -432,9 +432,9 @@ namespace Kernel
|
|||
return BAN::RefPtr<Inode>(inode);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpDirectoryInode::list_next_inodes_impl(off_t data_block_index, DirectoryEntryList* list, size_t list_len)
|
||||
BAN::ErrorOr<size_t> TmpDirectoryInode::list_next_inodes_impl(off_t data_block_index, struct dirent* list, size_t list_len)
|
||||
{
|
||||
if (list_len < (size_t)blksize())
|
||||
if (list_len == 0)
|
||||
{
|
||||
dprintln("buffer is too small");
|
||||
return BAN::Error::from_errno(ENOBUFS);
|
||||
|
@ -442,13 +442,12 @@ namespace Kernel
|
|||
|
||||
auto block_index = this->block_index(data_block_index);
|
||||
|
||||
list->entry_count = 0;
|
||||
|
||||
// if we reach a non-allocated block, it marks the end
|
||||
if (!block_index.has_value())
|
||||
return {};
|
||||
return 0;
|
||||
|
||||
auto* dirp = list->array;
|
||||
dirent* dirp = list;
|
||||
size_t entry_count = 0;
|
||||
|
||||
const size_t byte_count = BAN::Math::min<size_t>(size() - data_block_index * blksize(), blksize());
|
||||
m_fs.with_block_buffer(block_index.value(), [&](BAN::ByteSpan bytespan) {
|
||||
|
@ -462,21 +461,21 @@ namespace Kernel
|
|||
{
|
||||
// TODO: dirents should be aligned
|
||||
|
||||
dirp->dirent.d_ino = entry.ino;
|
||||
dirp->dirent.d_type = entry.type;
|
||||
strncpy(dirp->dirent.d_name, entry.name, entry.name_len);
|
||||
dirp->dirent.d_name[entry.name_len] = '\0';
|
||||
dirp->rec_len = sizeof(DirectoryEntry) + entry.name_len + 1;
|
||||
dirp = dirp->next();
|
||||
entry_count++;
|
||||
if (entry_count > list_len)
|
||||
return;
|
||||
|
||||
list->entry_count++;
|
||||
dirp->d_ino = entry.ino;
|
||||
dirp->d_type = entry.type;
|
||||
strncpy(dirp->d_name, entry.name, entry.name_len);
|
||||
dirp++;
|
||||
}
|
||||
|
||||
bytespan = bytespan.slice(entry.rec_len);
|
||||
}
|
||||
});
|
||||
|
||||
return {};
|
||||
return entry_count;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> TmpDirectoryInode::create_file_impl(BAN::StringView name, mode_t mode, uid_t uid, gid_t gid)
|
||||
|
|
|
@ -207,7 +207,7 @@ namespace Kernel
|
|||
return BAN::Error::from_errno(ENOTSUP);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
||||
BAN::ErrorOr<off_t> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence)
|
||||
{
|
||||
TRY(validate_fd(fd));
|
||||
|
||||
|
@ -233,7 +233,7 @@ namespace Kernel
|
|||
|
||||
m_open_files[fd]->offset = new_offset;
|
||||
|
||||
return {};
|
||||
return new_offset;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const
|
||||
|
@ -351,15 +351,13 @@ namespace Kernel
|
|||
return nwrite;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> OpenFileDescriptorSet::read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size)
|
||||
BAN::ErrorOr<size_t> OpenFileDescriptorSet::read_dir_entries(int fd, struct dirent* list, size_t list_len)
|
||||
{
|
||||
TRY(validate_fd(fd));
|
||||
auto& open_file = m_open_files[fd];
|
||||
if (!(open_file->flags & O_RDONLY))
|
||||
return BAN::Error::from_errno(EACCES);
|
||||
TRY(open_file->inode->list_next_inodes(open_file->offset, list, list_size));
|
||||
open_file->offset++;
|
||||
return {};
|
||||
return TRY(open_file->inode->list_next_inodes(open_file->offset++, list, list_len));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const
|
||||
|
|
|
@ -1136,8 +1136,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(m_open_file_descriptors.seek(fd, offset, whence));
|
||||
return 0;
|
||||
return TRY(m_open_file_descriptors.seek(fd, offset, whence));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_tell(int fd)
|
||||
|
@ -1220,12 +1219,11 @@ namespace Kernel
|
|||
return clean_poweroff(command);
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_readdir(int fd, DirectoryEntryList* list, size_t list_size)
|
||||
BAN::ErrorOr<long> Process::sys_readdir(int fd, struct dirent* list, size_t list_len)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(list, list_size));
|
||||
TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size));
|
||||
return 0;
|
||||
TRY(validate_pointer_access(list, sizeof(dirent) * list_len));
|
||||
return TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_len));
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_setpwd(const char* path)
|
||||
|
|
|
@ -5,16 +5,14 @@
|
|||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <kernel/API/DirectoryEntry.h>
|
||||
|
||||
struct __DIR
|
||||
{
|
||||
int fd { -1 };
|
||||
size_t entry_count { 0 };
|
||||
size_t entry_index { 0 };
|
||||
Kernel::API::DirectoryEntry* current { nullptr };
|
||||
|
||||
size_t buffer_size { 0 };
|
||||
Kernel::API::DirectoryEntryList buffer[];
|
||||
// FIXME: we should probably allocate entries dynamically
|
||||
// based if syscall returns ENOBUFS
|
||||
dirent entries[128];
|
||||
};
|
||||
|
||||
int closedir(DIR* dirp)
|
||||
|
@ -26,7 +24,6 @@ int closedir(DIR* dirp)
|
|||
}
|
||||
|
||||
close(dirp->fd);
|
||||
dirp->fd = -1;
|
||||
free(dirp);
|
||||
|
||||
return 0;
|
||||
|
@ -45,13 +42,13 @@ int dirfd(DIR* dirp)
|
|||
|
||||
DIR* fdopendir(int fd)
|
||||
{
|
||||
DIR* dirp = (DIR*)malloc(sizeof(DIR) + 4096);
|
||||
DIR* dirp = (DIR*)malloc(sizeof(DIR));
|
||||
if (dirp == nullptr)
|
||||
return nullptr;
|
||||
|
||||
dirp->fd = fd;
|
||||
dirp->current = nullptr;
|
||||
dirp->buffer_size = 4096;
|
||||
dirp->entry_count = 0;
|
||||
dirp->entry_index = 0;
|
||||
|
||||
return dirp;
|
||||
}
|
||||
|
@ -73,20 +70,15 @@ struct dirent* readdir(DIR* dirp)
|
|||
}
|
||||
|
||||
dirp->entry_index++;
|
||||
if (dirp->current && dirp->entry_index < dirp->buffer->entry_count)
|
||||
{
|
||||
dirp->current = dirp->current->next();
|
||||
return &dirp->current->dirent;
|
||||
}
|
||||
if (dirp->entry_index < dirp->entry_count)
|
||||
return &dirp->entries[dirp->entry_index];
|
||||
|
||||
if (syscall(SYS_READ_DIR, dirp->fd, dirp->buffer, dirp->buffer_size) == -1)
|
||||
return nullptr;
|
||||
|
||||
if (dirp->buffer->entry_count == 0)
|
||||
long entry_count = syscall(SYS_READ_DIR, dirp->fd, dirp->entries, sizeof(dirp->entries) / sizeof(dirp->entries[0]));
|
||||
if (entry_count <= 0)
|
||||
return nullptr;
|
||||
|
||||
dirp->entry_count = entry_count;
|
||||
dirp->entry_index = 0;
|
||||
dirp->current = dirp->buffer->array;
|
||||
|
||||
return &dirp->current->dirent;
|
||||
return &dirp->entries[0];
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ __BEGIN_DECLS
|
|||
#define __need_ino_t
|
||||
#include <sys/types.h>
|
||||
|
||||
struct __DIR;
|
||||
typedef struct __DIR DIR;
|
||||
|
||||
#define DT_UNKNOWN 0
|
||||
|
@ -26,7 +25,7 @@ struct dirent
|
|||
{
|
||||
ino_t d_ino; /* File serial number. */
|
||||
unsigned char d_type; /* File type. One of DT_* definitions. */
|
||||
char d_name[]; /* Filename string of entry. */
|
||||
char d_name[256]; /* Filename string of entry. */
|
||||
};
|
||||
|
||||
int alphasort(const struct dirent** d1, const struct dirent** d2);
|
||||
|
|
|
@ -7,12 +7,59 @@
|
|||
|
||||
__BEGIN_DECLS
|
||||
|
||||
// FIXME: What do I have to define here?
|
||||
// glibc seems to only define numerical
|
||||
// and posix constants
|
||||
#define _POSIX_AIO_LISTIO_MAX 2
|
||||
#define _POSIX_AIO_MAX 1
|
||||
#define _POSIX_ARG_MAX 4096
|
||||
#define _POSIX_CHILD_MAX 25
|
||||
#define _POSIX_DELAYTIMER_MAX 32
|
||||
#define _POSIX_HOST_NAME_MAX 255
|
||||
#define _POSIX_LINK_MAX 8
|
||||
#define _POSIX_LOGIN_NAME_MAX 9
|
||||
#define _POSIX_MAX_CANON 255
|
||||
#define _POSIX_MAX_INPUT 255
|
||||
#define _POSIX_MQ_OPEN_MAX 8
|
||||
#define _POSIX_MQ_PRIO_MAX 32
|
||||
#define _POSIX_NAME_MAX 14
|
||||
#define _POSIX_NGROUPS_MAX 8
|
||||
#define _POSIX_OPEN_MAX 20
|
||||
#define _POSIX_PATH_MAX 256
|
||||
#define _POSIX_PIPE_BUF 512
|
||||
#define _POSIX_RE_DUP_MAX 255
|
||||
#define _POSIX_RTSIG_MAX 8
|
||||
#define _POSIX_SEM_NSEMS_MAX 256
|
||||
#define _POSIX_SEM_VALUE_MAX 32767
|
||||
#define _POSIX_SIGQUEUE_MAX 32
|
||||
#define _POSIX_SSIZE_MAX 32767
|
||||
#define _POSIX_SS_REPL_MAX 4
|
||||
#define _POSIX_STREAM_MAX 8
|
||||
#define _POSIX_SYMLINK_MAX 255
|
||||
#define _POSIX_SYMLOOP_MAX 8
|
||||
#define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4
|
||||
#define _POSIX_THREAD_KEYS_MAX 128
|
||||
#define _POSIX_THREAD_THREADS_MAX 64
|
||||
#define _POSIX_TIMER_MAX 32
|
||||
#define _POSIX_TRACE_EVENT_NAME_MAX 30
|
||||
#define _POSIX_TRACE_NAME_MAX 8
|
||||
#define _POSIX_TRACE_SYS_MAX 8
|
||||
#define _POSIX_TRACE_USER_EVENT_MAX 32
|
||||
#define _POSIX_TTY_NAME_MAX 9
|
||||
#define _POSIX_TZNAME_MAX 6
|
||||
#define _POSIX2_BC_BASE_MAX 99
|
||||
#define _POSIX2_BC_DIM_MAX 2048
|
||||
#define _POSIX2_BC_SCALE_MAX 99
|
||||
#define _POSIX2_BC_STRING_MAX 1000
|
||||
#define _POSIX2_CHARCLASS_NAME_MAX 14
|
||||
#define _POSIX2_COLL_WEIGHTS_MAX 2
|
||||
#define _POSIX2_EXPR_NEST_MAX 32
|
||||
#define _POSIX2_LINE_MAX 2048
|
||||
#define _POSIX2_RE_DUP_MAX 255
|
||||
#define _XOPEN_IOV_MAX 16
|
||||
#define _XOPEN_NAME_MAX 255
|
||||
#define _XOPEN_PATH_MAX 1024
|
||||
|
||||
#define OPEN_MAX 64
|
||||
#define NAME_MAX 255
|
||||
#define LOGIN_NAME_MAX 256
|
||||
|
||||
__END_DECLS
|
||||
|
||||
|
|
|
@ -516,6 +516,52 @@ int putenv(char* string)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void qsort_swap(void* lhs, void* rhs, size_t width)
|
||||
{
|
||||
uint8_t buffer[64];
|
||||
size_t swapped = 0;
|
||||
while (swapped < width)
|
||||
{
|
||||
const size_t to_swap = BAN::Math::min(width - swapped, sizeof(buffer));
|
||||
memcpy(buffer, lhs, to_swap);
|
||||
memcpy(lhs, rhs, to_swap);
|
||||
memcpy(rhs, buffer, to_swap);
|
||||
swapped += to_swap;
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t* qsort_partition(uint8_t* pbegin, uint8_t* pend, size_t width, int (*compar)(const void*, const void*))
|
||||
{
|
||||
uint8_t* pivot = pend - width;
|
||||
uint8_t* p1 = pbegin;
|
||||
for (uint8_t* p2 = pbegin; p2 < pivot; p2 += width)
|
||||
{
|
||||
if (compar(p2, pivot) >= 0)
|
||||
continue;
|
||||
qsort_swap(p1, p2, width);
|
||||
p1 += width;
|
||||
}
|
||||
qsort_swap(p1, pivot, width);
|
||||
return p1;
|
||||
}
|
||||
|
||||
static void qsort_impl(uint8_t* pbegin, uint8_t* pend, size_t width, int (*compar)(const void*, const void*))
|
||||
{
|
||||
if ((pend - pbegin) / width <= 1)
|
||||
return;
|
||||
uint8_t* mid = qsort_partition(pbegin, pend, width, compar);
|
||||
qsort_impl(pbegin, mid, width, compar);
|
||||
qsort_impl(mid + width, pend, width, compar);
|
||||
}
|
||||
|
||||
void qsort(void* base, size_t nel, size_t width, int (*compar)(const void*, const void*))
|
||||
{
|
||||
if (width == 0)
|
||||
return;
|
||||
uint8_t* pbegin = static_cast<uint8_t*>(base);
|
||||
qsort_impl(pbegin, pbegin + nel * width, width, compar);
|
||||
}
|
||||
|
||||
// Constants and algorithm from https://en.wikipedia.org/wiki/Permuted_congruential_generator
|
||||
|
||||
static uint64_t s_rand_state = 0x4d595df4d0f33173;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <BAN/Assert.h>
|
||||
#include <kernel/Syscall.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
@ -93,6 +94,11 @@ ssize_t pread(int fildes, void* buf, size_t nbyte, off_t offset)
|
|||
return syscall(SYS_PREAD, fildes, buf, nbyte, offset);
|
||||
}
|
||||
|
||||
off_t lseek(int fildes, off_t offset, int whence)
|
||||
{
|
||||
return syscall(SYS_SEEK, fildes, offset, whence);
|
||||
}
|
||||
|
||||
int dup(int fildes)
|
||||
{
|
||||
return syscall(SYS_DUP, fildes);
|
||||
|
@ -460,3 +466,15 @@ int tcsetpgrp(int fildes, pid_t pgid_id)
|
|||
{
|
||||
return syscall(SYS_TCSETPGRP, fildes, pgid_id);
|
||||
}
|
||||
|
||||
char* getlogin(void)
|
||||
{
|
||||
static char buffer[LOGIN_NAME_MAX];
|
||||
auto* pw = getpwuid(geteuid());
|
||||
if (pw == nullptr)
|
||||
return nullptr;
|
||||
strncpy(buffer, pw->pw_name, LOGIN_NAME_MAX - 1);
|
||||
buffer[LOGIN_NAME_MAX - 1] = '\0';
|
||||
endpwent();
|
||||
return buffer;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <BAN/HashSet.h>
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/Hash.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <BAN/Vector.h>
|
||||
#include <BAN/HashSet.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include <BAN/HashMap.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <inttypes.h>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
#include <BAN/StringView.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <ctype.h>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <BAN/Endianness.h>
|
||||
#include <BAN/IPv4.h>
|
||||
#include <BAN/MAC.h>
|
||||
#include <BAN/Optional.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
#include <arpa/inet.h>
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <BAN/Vector.h>
|
||||
#include <BAN/StringView.h>
|
||||
#include <BAN/UniqPtr.h>
|
||||
#include <BAN/Vector.h>
|
||||
|
||||
class Image
|
||||
{
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
#include <pwd.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
|
||||
int main()
|
||||
{
|
||||
auto* pw = getpwuid(geteuid());
|
||||
if (pw == nullptr)
|
||||
char* login = getlogin();
|
||||
if (login == nullptr)
|
||||
{
|
||||
printf("unknown user %d\n", geteuid());
|
||||
return 1;
|
||||
}
|
||||
printf("%s\n", pw->pw_name);
|
||||
endpwent();
|
||||
printf("%s\n", login);
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue