Compare commits

...

7 Commits

Author SHA1 Message Date
Bananymous cc2cc2849e Whoami: Rewrite whoami using getlogin 2024-05-23 15:44:21 +03:00
Bananymous 06f4b0b29a BAN: Make String and StringView header only
This allows linking with libc without having to link ban
2024-05-23 15:43:26 +03:00
Bananymous e22821799b LibC: Implement getlogin() 2024-05-23 15:07:21 +03:00
Bananymous 14dd9294aa LibC: Add _POSIX constants to limits.h 2024-05-23 15:04:59 +03:00
Bananymous 83e3409bd8 Kernel/LibC: Update SYS_SEEK to return new offset and implement lseek 2024-05-23 14:49:23 +03:00
Bananymous 7630170ed6 LibC: Implement qsort as quick sort 2024-05-23 14:44:48 +03:00
Bananymous 0af74fccda Kernel/LibC: Rework dirent structure
dirent now contains statically sized d_name. This allows using
sizeof on the name and dirent properly, which some programs seem
to be using.
2024-05-22 20:19:59 +03:00
33 changed files with 617 additions and 663 deletions

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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
)

View File

@ -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:

View File

@ -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>
{

View File

@ -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;

View File

@ -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
)

View File

@ -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[];
};
}

View File

@ -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);
}

View File

@ -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;

View File

@ -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); }

View File

@ -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;

View File

@ -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);

View File

@ -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);

View File

@ -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];

View File

@ -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)

View File

@ -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())

View File

@ -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)

View File

@ -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

View File

@ -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)

View File

@ -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];
}

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -1,3 +1,4 @@
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <ctype.h>

View File

@ -1,4 +1,5 @@
#include <BAN/HashMap.h>
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <inttypes.h>

View File

@ -1,3 +1,4 @@
#include <BAN/StringView.h>
#include <BAN/Vector.h>
#include <ctype.h>

View File

@ -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>

View File

@ -1,7 +1,8 @@
#pragma once
#include <BAN/Vector.h>
#include <BAN/StringView.h>
#include <BAN/UniqPtr.h>
#include <BAN/Vector.h>
class Image
{

View File

@ -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;
}