mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 11:48:10 +00:00
Virtual consoles kinda work!
We now make three VirtualConsoles at boot: tty0, tty1, and tty2. We launch an instance of /bin/sh in each one. You switch between them with Alt+1/2/3 How very very cool :^)
This commit is contained in:
parent
68739dc43e
commit
7a7956a595
24 changed files with 251 additions and 103 deletions
|
@ -38,6 +38,12 @@ static char shift_map[0x100] =
|
||||||
0, 0, 0, ' '
|
0, 0, 0, ' '
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void Keyboard::emit(byte ch)
|
||||||
|
{
|
||||||
|
if (m_client)
|
||||||
|
m_client->onKeyPress(ch);
|
||||||
|
m_queue.enqueue(ch);
|
||||||
|
}
|
||||||
|
|
||||||
void Keyboard::handleIRQ()
|
void Keyboard::handleIRQ()
|
||||||
{
|
{
|
||||||
|
@ -50,7 +56,7 @@ void Keyboard::handleIRQ()
|
||||||
case 0x9D: m_modifiers &= ~MOD_CTRL; break;
|
case 0x9D: m_modifiers &= ~MOD_CTRL; break;
|
||||||
case 0x2A: m_modifiers |= MOD_SHIFT; break;
|
case 0x2A: m_modifiers |= MOD_SHIFT; break;
|
||||||
case 0xAA: m_modifiers &= ~MOD_SHIFT; break;
|
case 0xAA: m_modifiers &= ~MOD_SHIFT; break;
|
||||||
case 0x1C: /* enter */ m_queue.enqueue('\n'); break;
|
case 0x1C: /* enter */ emit('\n'); break;
|
||||||
case 0xFA: /* i8042 ack */ break;
|
case 0xFA: /* i8042 ack */ break;
|
||||||
default:
|
default:
|
||||||
if (ch & 0x80) {
|
if (ch & 0x80) {
|
||||||
|
@ -69,31 +75,33 @@ void Keyboard::handleIRQ()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!m_modifiers) {
|
if (!m_modifiers) {
|
||||||
if (m_client)
|
emit(map[ch]);
|
||||||
m_client->onKeyPress(map[ch]);
|
|
||||||
m_queue.enqueue(map[ch]);
|
|
||||||
} else if (m_modifiers & MOD_SHIFT) {
|
} else if (m_modifiers & MOD_SHIFT) {
|
||||||
if (m_client)
|
emit(shift_map[ch]);
|
||||||
m_client->onKeyPress(shift_map[ch]);
|
|
||||||
m_queue.enqueue(shift_map[ch]);
|
|
||||||
} else if (m_modifiers & MOD_CTRL) {
|
} else if (m_modifiers & MOD_CTRL) {
|
||||||
// FIXME: This is obviously not a good enough way to process ctrl+whatever.
|
// FIXME: This is obviously not a good enough way to process ctrl+whatever.
|
||||||
if (m_client) {
|
emit('^');
|
||||||
m_client->onKeyPress('^');
|
emit(shift_map[ch]);
|
||||||
m_client->onKeyPress(shift_map[ch]);
|
|
||||||
}
|
|
||||||
m_queue.enqueue('^');
|
|
||||||
m_queue.enqueue(shift_map[ch]);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//break;
|
//break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Keyboard* s_the;
|
||||||
|
|
||||||
|
Keyboard& Keyboard::the()
|
||||||
|
{
|
||||||
|
ASSERT(s_the);
|
||||||
|
return *s_the;
|
||||||
|
}
|
||||||
|
|
||||||
Keyboard::Keyboard()
|
Keyboard::Keyboard()
|
||||||
: IRQHandler(IRQ_KEYBOARD)
|
: IRQHandler(IRQ_KEYBOARD)
|
||||||
, CharacterDevice(85, 1)
|
, CharacterDevice(85, 1)
|
||||||
{
|
{
|
||||||
|
s_the = this;
|
||||||
|
|
||||||
// Empty the buffer of any pending data.
|
// Empty the buffer of any pending data.
|
||||||
// I don't care what you've been pressing until now!
|
// I don't care what you've been pressing until now!
|
||||||
while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE)
|
while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE)
|
||||||
|
|
|
@ -19,7 +19,7 @@ public:
|
||||||
virtual ~Keyboard() override;
|
virtual ~Keyboard() override;
|
||||||
Keyboard();
|
Keyboard();
|
||||||
|
|
||||||
void setClient(KeyboardClient*);
|
void setClient(KeyboardClient* client) { m_client = client; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^IRQHandler
|
// ^IRQHandler
|
||||||
|
@ -30,6 +30,8 @@ private:
|
||||||
virtual ssize_t write(const byte* buffer, size_t) override;
|
virtual ssize_t write(const byte* buffer, size_t) override;
|
||||||
virtual bool hasDataAvailableForRead() const override;
|
virtual bool hasDataAvailableForRead() const override;
|
||||||
|
|
||||||
|
void emit(byte);
|
||||||
|
|
||||||
KeyboardClient* m_client { nullptr };
|
KeyboardClient* m_client { nullptr };
|
||||||
CircularQueue<byte, 16> m_queue;
|
CircularQueue<byte, 16> m_queue;
|
||||||
byte m_modifiers { 0 };
|
byte m_modifiers { 0 };
|
||||||
|
|
|
@ -201,15 +201,16 @@ ByteBuffer procfs$summary()
|
||||||
auto tasks = Task::allTasks();
|
auto tasks = Task::allTasks();
|
||||||
auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256);
|
auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256);
|
||||||
char* ptr = (char*)buffer.pointer();
|
char* ptr = (char*)buffer.pointer();
|
||||||
ptr += ksprintf(ptr, "PID OWNER STATE PPID NSCHED FDS NAME\n");
|
ptr += ksprintf(ptr, "PID OWNER STATE PPID NSCHED FDS TTY NAME\n");
|
||||||
for (auto* task : tasks) {
|
for (auto* task : tasks) {
|
||||||
ptr += ksprintf(ptr, "% 5u % 4u % 8s % 5u % 10u % 3u %s\n",
|
ptr += ksprintf(ptr, "% 5u % 4u % 8s % 5u % 10u % 3u % 4s %s\n",
|
||||||
task->pid(),
|
task->pid(),
|
||||||
task->uid(),
|
task->uid(),
|
||||||
toString(task->state()),
|
toString(task->state()),
|
||||||
task->parentPID(),
|
task->parentPID(),
|
||||||
task->timesScheduled(),
|
task->timesScheduled(),
|
||||||
task->fileHandleCount(),
|
task->fileHandleCount(),
|
||||||
|
task->tty() ? task->tty()->ttyName().characters() : "n/a",
|
||||||
task->name().characters());
|
task->name().characters());
|
||||||
}
|
}
|
||||||
*ptr = '\0';
|
*ptr = '\0';
|
||||||
|
|
|
@ -70,6 +70,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
return current->sys$getcwd((char*)arg1, (size_t)arg2);
|
return current->sys$getcwd((char*)arg1, (size_t)arg2);
|
||||||
case Syscall::PosixOpen:
|
case Syscall::PosixOpen:
|
||||||
return current->sys$open((const char*)arg1, (int)arg2);
|
return current->sys$open((const char*)arg1, (int)arg2);
|
||||||
|
case Syscall::PosixWrite:
|
||||||
|
return current->sys$write((int)arg1, (const void*)arg2, (size_t)arg3);
|
||||||
case Syscall::PosixClose:
|
case Syscall::PosixClose:
|
||||||
//kprintf("syscall: close(%d)\n", arg1);
|
//kprintf("syscall: close(%d)\n", arg1);
|
||||||
return current->sys$close((int)arg1);
|
return current->sys$close((int)arg1);
|
||||||
|
|
|
@ -36,6 +36,7 @@ enum Function {
|
||||||
PosixUname = 0x2004,
|
PosixUname = 0x2004,
|
||||||
SetMmapName = 0x2005,
|
SetMmapName = 0x2005,
|
||||||
PosixReadlink = 0x2006,
|
PosixReadlink = 0x2006,
|
||||||
|
PosixWrite = 0x2007,
|
||||||
};
|
};
|
||||||
|
|
||||||
void initialize();
|
void initialize();
|
||||||
|
|
|
@ -11,15 +11,30 @@ TTY::~TTY()
|
||||||
|
|
||||||
ssize_t TTY::read(byte* buffer, size_t size)
|
ssize_t TTY::read(byte* buffer, size_t size)
|
||||||
{
|
{
|
||||||
return 0;
|
ssize_t nread = min(m_buffer.size(), size);
|
||||||
|
memcpy(buffer, m_buffer.data(), nread);
|
||||||
|
if (nread == m_buffer.size())
|
||||||
|
m_buffer.clear();
|
||||||
|
else {
|
||||||
|
dbgprintf("had %u, read %u\n", m_buffer.size(), nread);
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t TTY::write(const byte* buffer, size_t size)
|
ssize_t TTY::write(const byte* buffer, size_t size)
|
||||||
{
|
{
|
||||||
|
for (size_t i = 0; i < size; ++i)
|
||||||
|
onTTYWrite(buffer[i]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TTY::hasDataAvailableForRead() const
|
bool TTY::hasDataAvailableForRead() const
|
||||||
{
|
{
|
||||||
return false;
|
return !m_buffer.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TTY::emit(byte ch)
|
||||||
|
{
|
||||||
|
m_buffer.append(ch);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,15 @@ public:
|
||||||
virtual ssize_t write(const byte*, size_t) override;
|
virtual ssize_t write(const byte*, size_t) override;
|
||||||
virtual bool hasDataAvailableForRead() const override;
|
virtual bool hasDataAvailableForRead() const override;
|
||||||
|
|
||||||
|
virtual String ttyName() const = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TTY(unsigned major, unsigned minor);
|
TTY(unsigned major, unsigned minor);
|
||||||
|
void emit(byte);
|
||||||
|
|
||||||
|
virtual void onTTYWrite(byte) = 0;
|
||||||
|
|
||||||
|
private:
|
||||||
|
Vector<byte> m_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -214,13 +214,13 @@ int Task::sys$gethostname(char* buffer, size_t size)
|
||||||
int Task::sys$spawn(const char* path, const char** args)
|
int Task::sys$spawn(const char* path, const char** args)
|
||||||
{
|
{
|
||||||
int error = 0;
|
int error = 0;
|
||||||
auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args);
|
auto* child = Task::createUserTask(path, m_uid, m_gid, m_pid, error, args, m_tty);
|
||||||
if (child)
|
if (child)
|
||||||
return child->pid();
|
return child->pid();
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args)
|
Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t parentPID, int& error, const char** args, TTY* tty)
|
||||||
{
|
{
|
||||||
auto parts = path.split('/');
|
auto parts = path.split('/');
|
||||||
if (parts.isEmpty()) {
|
if (parts.isEmpty()) {
|
||||||
|
@ -262,7 +262,7 @@ Task* Task::createUserTask(const String& path, uid_t uid, gid_t gid, pid_t paren
|
||||||
}
|
}
|
||||||
|
|
||||||
InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE.
|
InterruptDisabler disabler; // FIXME: Get rid of this, jesus christ. This "critical" section is HUGE.
|
||||||
Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode());
|
Task* t = new Task(parts.takeLast(), uid, gid, parentPID, Ring3, move(cwd), handle->vnode(), tty);
|
||||||
|
|
||||||
t->m_arguments = move(taskArguments);
|
t->m_arguments = move(taskArguments);
|
||||||
|
|
||||||
|
@ -372,8 +372,8 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring,
|
||||||
, m_ring(ring)
|
, m_ring(ring)
|
||||||
, m_cwd(move(cwd))
|
, m_cwd(move(cwd))
|
||||||
, m_executable(move(executable))
|
, m_executable(move(executable))
|
||||||
, m_parentPID(parentPID)
|
|
||||||
, m_tty(tty)
|
, m_tty(tty)
|
||||||
|
, m_parentPID(parentPID)
|
||||||
{
|
{
|
||||||
if (tty) {
|
if (tty) {
|
||||||
m_fileHandles.append(tty->open(O_RDONLY)); // stdin
|
m_fileHandles.append(tty->open(O_RDONLY)); // stdin
|
||||||
|
@ -753,6 +753,25 @@ int Task::sys$seek(int fd, int offset)
|
||||||
return handle->seek(offset, SEEK_SET);
|
return handle->seek(offset, SEEK_SET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t Task::sys$write(int fd, const void* data, size_t size)
|
||||||
|
{
|
||||||
|
VALIDATE_USER_BUFFER(data, size);
|
||||||
|
#ifdef DEBUG_IO
|
||||||
|
kprintf("Task::sys$write: called(%d, %p, %u)\n", fd, data, size);
|
||||||
|
#endif
|
||||||
|
auto* handle = fileHandleIfExists(fd);
|
||||||
|
#ifdef DEBUG_IO
|
||||||
|
kprintf("Task::sys$write: handle=%p\n", handle);
|
||||||
|
#endif
|
||||||
|
if (!handle)
|
||||||
|
return -EBADF;
|
||||||
|
auto nwritten = handle->write((const byte*)data, size);
|
||||||
|
#ifdef DEBUG_IO
|
||||||
|
kprintf("Task::sys$write: nwritten=%u\n", nwritten);
|
||||||
|
#endif
|
||||||
|
return nwritten;
|
||||||
|
}
|
||||||
|
|
||||||
ssize_t Task::sys$read(int fd, void* outbuf, size_t nread)
|
ssize_t Task::sys$read(int fd, void* outbuf, size_t nread)
|
||||||
{
|
{
|
||||||
VALIDATE_USER_BUFFER(outbuf, nread);
|
VALIDATE_USER_BUFFER(outbuf, nread);
|
||||||
|
@ -763,13 +782,8 @@ ssize_t Task::sys$read(int fd, void* outbuf, size_t nread)
|
||||||
#ifdef DEBUG_IO
|
#ifdef DEBUG_IO
|
||||||
kprintf("Task::sys$read: handle=%p\n", handle);
|
kprintf("Task::sys$read: handle=%p\n", handle);
|
||||||
#endif
|
#endif
|
||||||
if (!handle) {
|
if (!handle)
|
||||||
kprintf("Task::sys$read: handle not found :(\n");
|
return -EBADF;
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
#ifdef DEBUG_IO
|
|
||||||
kprintf("call read on handle=%p\n", handle);
|
|
||||||
#endif
|
|
||||||
if (handle->isBlocking()) {
|
if (handle->isBlocking()) {
|
||||||
if (!handle->hasDataAvailableForRead()) {
|
if (!handle->hasDataAvailableForRead()) {
|
||||||
m_fdBlockedOnRead = fd;
|
m_fdBlockedOnRead = fd;
|
||||||
|
|
|
@ -20,7 +20,7 @@ class Task : public InlineLinkedListNode<Task> {
|
||||||
struct Subregion;
|
struct Subregion;
|
||||||
public:
|
public:
|
||||||
static Task* createKernelTask(void (*entry)(), String&& name);
|
static Task* createKernelTask(void (*entry)(), String&& name);
|
||||||
static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr);
|
static Task* createUserTask(const String& path, uid_t, gid_t, pid_t parentPID, int& error, const char** args = nullptr, TTY* = nullptr);
|
||||||
~Task();
|
~Task();
|
||||||
|
|
||||||
static Vector<Task*> allTasks();
|
static Vector<Task*> allTasks();
|
||||||
|
@ -90,7 +90,8 @@ public:
|
||||||
pid_t sys$getpid();
|
pid_t sys$getpid();
|
||||||
int sys$open(const char* path, int options);
|
int sys$open(const char* path, int options);
|
||||||
int sys$close(int fd);
|
int sys$close(int fd);
|
||||||
int sys$read(int fd, void* outbuf, size_t nread);
|
ssize_t sys$read(int fd, void* outbuf, size_t nread);
|
||||||
|
ssize_t sys$write(int fd, const void*, size_t);
|
||||||
int sys$lstat(const char*, Unix::stat*);
|
int sys$lstat(const char*, Unix::stat*);
|
||||||
int sys$seek(int fd, int offset);
|
int sys$seek(int fd, int offset);
|
||||||
int sys$kill(pid_t pid, int sig);
|
int sys$kill(pid_t pid, int sig);
|
||||||
|
@ -115,6 +116,8 @@ public:
|
||||||
|
|
||||||
static void taskDidCrash(Task*);
|
static void taskDidCrash(Task*);
|
||||||
|
|
||||||
|
const TTY* tty() const { return m_tty; }
|
||||||
|
|
||||||
size_t regionCount() const { return m_regions.size(); }
|
size_t regionCount() const { return m_regions.size(); }
|
||||||
const Vector<RetainPtr<Region>>& regions() const { return m_regions; }
|
const Vector<RetainPtr<Region>>& regions() const { return m_regions; }
|
||||||
size_t subregionCount() const { return m_regions.size(); }
|
size_t subregionCount() const { return m_regions.size(); }
|
||||||
|
|
|
@ -31,16 +31,11 @@ void vga_clear()
|
||||||
vga_clear_row(i);
|
vga_clear_row(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void vga_putch_at(byte row, byte column, byte ch)
|
void vga_putch_at(byte row, byte column, byte ch, byte attr)
|
||||||
{
|
{
|
||||||
word cur = (row * 160) + (column * 2);
|
word cur = (row * 160) + (column * 2);
|
||||||
vga_mem[cur] = ch;
|
vga_mem[cur] = ch;
|
||||||
vga_mem[cur + 1] = current_attr;
|
vga_mem[cur + 1] = attr;
|
||||||
}
|
|
||||||
|
|
||||||
void vga_set_attr(BYTE attr)
|
|
||||||
{
|
|
||||||
current_attr = attr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
byte vga_get_attr()
|
byte vga_get_attr()
|
||||||
|
|
|
@ -3,12 +3,10 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
void vga_init();
|
void vga_init();
|
||||||
BYTE vga_get_attr();
|
|
||||||
void vga_set_attr(BYTE);
|
|
||||||
void vga_set_cursor(WORD);
|
void vga_set_cursor(WORD);
|
||||||
void vga_set_cursor(BYTE row, BYTE column);
|
void vga_set_cursor(BYTE row, BYTE column);
|
||||||
WORD vga_get_cursor();
|
WORD vga_get_cursor();
|
||||||
void vga_putch_at(byte row, byte column, byte ch);
|
void vga_putch_at(byte row, byte column, byte ch, byte attr);
|
||||||
void vga_scroll_up();
|
void vga_scroll_up();
|
||||||
void vga_clear();
|
void vga_clear();
|
||||||
void vga_clear_row(word);
|
void vga_clear_row(word);
|
||||||
|
|
|
@ -3,16 +3,17 @@
|
||||||
#include "kmalloc.h"
|
#include "kmalloc.h"
|
||||||
#include "i386.h"
|
#include "i386.h"
|
||||||
#include "StdLib.h"
|
#include "StdLib.h"
|
||||||
|
#include "Keyboard.h"
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
|
|
||||||
static byte* s_vgaBuffer = (byte*)0xb8000;
|
static byte* s_vgaBuffer = (byte*)0xb8000;
|
||||||
static VirtualConsole* s_consoles[6];
|
static VirtualConsole* s_consoles[6];
|
||||||
static unsigned s_activeConsole;
|
static int s_activeConsole;
|
||||||
|
|
||||||
void VirtualConsole::initialize()
|
void VirtualConsole::initialize()
|
||||||
{
|
{
|
||||||
memset(s_consoles, 0, sizeof(s_consoles));
|
memset(s_consoles, 0, sizeof(s_consoles));
|
||||||
s_activeConsole = 0;
|
s_activeConsole = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents)
|
VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents)
|
||||||
|
@ -40,7 +41,7 @@ VirtualConsole::~VirtualConsole()
|
||||||
|
|
||||||
void VirtualConsole::switchTo(unsigned index)
|
void VirtualConsole::switchTo(unsigned index)
|
||||||
{
|
{
|
||||||
if (index == s_activeConsole)
|
if ((int)index == s_activeConsole)
|
||||||
return;
|
return;
|
||||||
dbgprintf("[VC] Switch to %u\n", index);
|
dbgprintf("[VC] Switch to %u\n", index);
|
||||||
ASSERT(index < 6);
|
ASSERT(index < 6);
|
||||||
|
@ -49,6 +50,7 @@ void VirtualConsole::switchTo(unsigned index)
|
||||||
s_consoles[s_activeConsole]->setActive(false);
|
s_consoles[s_activeConsole]->setActive(false);
|
||||||
s_activeConsole = index;
|
s_activeConsole = index;
|
||||||
s_consoles[s_activeConsole]->setActive(true);
|
s_consoles[s_activeConsole]->setActive(true);
|
||||||
|
Console::the().setImplementation(s_consoles[s_activeConsole]);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::setActive(bool b)
|
void VirtualConsole::setActive(bool b)
|
||||||
|
@ -60,14 +62,14 @@ void VirtualConsole::setActive(bool b)
|
||||||
|
|
||||||
m_active = b;
|
m_active = b;
|
||||||
if (!m_active) {
|
if (!m_active) {
|
||||||
dbgprintf("%u becomes inactive, copying to buffer\n", m_index);
|
|
||||||
memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2);
|
memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
dbgprintf("%u becomes active, copying from buffer, set cursor %u,%u\n", m_index, m_cursorRow, m_cursorColumn);
|
|
||||||
memcpy(s_vgaBuffer, m_buffer, 80 * 25 * 2);
|
memcpy(s_vgaBuffer, m_buffer, 80 * 25 * 2);
|
||||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||||
|
|
||||||
|
Keyboard::the().setClient(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isParameter(byte ch)
|
inline bool isParameter(byte ch)
|
||||||
|
@ -205,7 +207,6 @@ void VirtualConsole::escape$m(const Vector<unsigned>& params)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vga_set_attr(m_currentAttribute);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::escape$s(const Vector<unsigned>&)
|
void VirtualConsole::escape$s(const Vector<unsigned>&)
|
||||||
|
@ -216,9 +217,7 @@ void VirtualConsole::escape$s(const Vector<unsigned>&)
|
||||||
|
|
||||||
void VirtualConsole::escape$u(const Vector<unsigned>&)
|
void VirtualConsole::escape$u(const Vector<unsigned>&)
|
||||||
{
|
{
|
||||||
m_cursorRow = m_savedCursorRow;
|
setCursor(m_savedCursorRow, m_savedCursorColumn);
|
||||||
m_cursorColumn = m_savedCursorColumn;
|
|
||||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::escape$H(const Vector<unsigned>& params)
|
void VirtualConsole::escape$H(const Vector<unsigned>& params)
|
||||||
|
@ -229,9 +228,7 @@ void VirtualConsole::escape$H(const Vector<unsigned>& params)
|
||||||
row = params[0];
|
row = params[0];
|
||||||
if (params.size() >= 2)
|
if (params.size() >= 2)
|
||||||
col = params[1];
|
col = params[1];
|
||||||
m_cursorRow = row - 1;
|
setCursor(row - 1, col - 1);
|
||||||
m_cursorColumn = col - 1;
|
|
||||||
vga_set_cursor(row - 1, col - 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::escape$J(const Vector<unsigned>& params)
|
void VirtualConsole::escape$J(const Vector<unsigned>& params)
|
||||||
|
@ -284,16 +281,42 @@ void VirtualConsole::executeEscapeSequence(byte final)
|
||||||
m_intermediates.clear();
|
m_intermediates.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::onChar(byte ch)
|
void VirtualConsole::scrollUp()
|
||||||
{
|
{
|
||||||
auto scrollup = [&] {
|
if (m_cursorRow == (m_rows - 1)) {
|
||||||
if (m_cursorRow == (m_rows - 1)) {
|
memcpy(m_buffer, m_buffer + 160, 160 * 24);
|
||||||
|
word* linemem = (word*)&m_buffer[24 * 160];
|
||||||
|
for (word i = 0; i < 80; ++i)
|
||||||
|
linemem[i] = 0x0720;
|
||||||
|
if (m_active)
|
||||||
vga_scroll_up();
|
vga_scroll_up();
|
||||||
} else {
|
} else {
|
||||||
++m_cursorRow;
|
++m_cursorRow;
|
||||||
}
|
}
|
||||||
m_cursorColumn = 0;
|
m_cursorColumn = 0;
|
||||||
};
|
}
|
||||||
|
|
||||||
|
void VirtualConsole::setCursor(unsigned row, unsigned column)
|
||||||
|
{
|
||||||
|
m_cursorRow = row;
|
||||||
|
m_cursorColumn = column;
|
||||||
|
if (m_active)
|
||||||
|
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualConsole::putCharacterAt(unsigned row, unsigned column, byte ch)
|
||||||
|
{
|
||||||
|
word cur = (row * 160) + (column * 2);
|
||||||
|
m_buffer[cur] = ch;
|
||||||
|
m_buffer[cur + 1] = m_currentAttribute;
|
||||||
|
if (m_active)
|
||||||
|
vga_putch_at(row, column, ch, m_currentAttribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualConsole::onChar(byte ch, bool shouldEmit)
|
||||||
|
{
|
||||||
|
if (shouldEmit)
|
||||||
|
emit(ch);
|
||||||
|
|
||||||
switch (m_escState) {
|
switch (m_escState) {
|
||||||
case ExpectBracket:
|
case ExpectBracket:
|
||||||
|
@ -336,32 +359,43 @@ void VirtualConsole::onChar(byte ch)
|
||||||
return;
|
return;
|
||||||
case 8: // Backspace
|
case 8: // Backspace
|
||||||
if (m_cursorColumn) {
|
if (m_cursorColumn) {
|
||||||
--m_cursorColumn;\
|
setCursor(m_cursorRow, m_cursorColumn - 1);
|
||||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
putCharacterAt(m_cursorRow, m_cursorColumn, ' ');
|
||||||
vga_putch_at(m_cursorRow, m_cursorColumn, ' ');
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case '\n':
|
case '\n':
|
||||||
scrollup();
|
scrollUp();
|
||||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
setCursor(m_cursorRow, m_cursorColumn);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
vga_putch_at(m_cursorRow, m_cursorColumn, ch);
|
putCharacterAt(m_cursorRow, m_cursorColumn, ch);
|
||||||
|
|
||||||
++m_cursorColumn;
|
++m_cursorColumn;
|
||||||
if (m_cursorColumn >= m_columns)
|
if (m_cursorColumn >= m_columns)
|
||||||
scrollup();
|
scrollUp();
|
||||||
vga_set_cursor(m_cursorRow, m_cursorColumn);
|
setCursor(m_cursorRow, m_cursorColumn);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::onKeyPress(byte ch)
|
void VirtualConsole::onKeyPress(byte ch)
|
||||||
{
|
{
|
||||||
onChar(ch);
|
emit(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualConsole::onConsoleReceive(byte ch)
|
void VirtualConsole::onConsoleReceive(byte ch)
|
||||||
{
|
{
|
||||||
onChar(ch);
|
onChar(ch, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VirtualConsole::onTTYWrite(byte ch)
|
||||||
|
{
|
||||||
|
onChar(ch, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
String VirtualConsole::ttyName() const
|
||||||
|
{
|
||||||
|
char buf[8];
|
||||||
|
ksprintf(buf, "tty%u", m_index);
|
||||||
|
return String(buf);
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,17 +19,25 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// ^KeyboardClient
|
// ^KeyboardClient
|
||||||
void onKeyPress(byte) override;
|
virtual void onKeyPress(byte) override;
|
||||||
|
|
||||||
// ^ConsoleImplementation
|
// ^ConsoleImplementation
|
||||||
void onConsoleReceive(byte) override;
|
virtual void onConsoleReceive(byte) override;
|
||||||
|
|
||||||
void onChar(byte);
|
// ^TTY
|
||||||
|
virtual void onTTYWrite(byte) override;
|
||||||
|
virtual String ttyName() const override;
|
||||||
|
|
||||||
|
void onChar(byte, bool shouldEmit);
|
||||||
|
|
||||||
byte* m_buffer;
|
byte* m_buffer;
|
||||||
unsigned m_index;
|
unsigned m_index;
|
||||||
bool m_active { false };
|
bool m_active { false };
|
||||||
|
|
||||||
|
void scrollUp();
|
||||||
|
void setCursor(unsigned row, unsigned column);
|
||||||
|
void putCharacterAt(unsigned row, unsigned column, byte ch);
|
||||||
|
|
||||||
void escape$H(const Vector<unsigned>&);
|
void escape$H(const Vector<unsigned>&);
|
||||||
void escape$J(const Vector<unsigned>&);
|
void escape$J(const Vector<unsigned>&);
|
||||||
void escape$m(const Vector<unsigned>&);
|
void escape$m(const Vector<unsigned>&);
|
||||||
|
@ -56,6 +64,4 @@ private:
|
||||||
EscapeState m_escState { Normal };
|
EscapeState m_escState { Normal };
|
||||||
Vector<byte> m_parameters;
|
Vector<byte> m_parameters;
|
||||||
Vector<byte> m_intermediates;
|
Vector<byte> m_intermediates;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -192,6 +192,8 @@ void exception_13_handler()
|
||||||
EH_ENTRY(14);
|
EH_ENTRY(14);
|
||||||
void exception_14_handler()
|
void exception_14_handler()
|
||||||
{
|
{
|
||||||
|
ASSERT(current);
|
||||||
|
|
||||||
dword faultAddress;
|
dword faultAddress;
|
||||||
asm ("movl %%cr2, %%eax":"=a"(faultAddress));
|
asm ("movl %%cr2, %%eax":"=a"(faultAddress));
|
||||||
|
|
||||||
|
@ -249,7 +251,6 @@ void exception_14_handler()
|
||||||
#define EH(i, msg) \
|
#define EH(i, msg) \
|
||||||
static void _exception ## i () \
|
static void _exception ## i () \
|
||||||
{ \
|
{ \
|
||||||
vga_set_attr(0x0a); \
|
|
||||||
kprintf(msg"\n"); \
|
kprintf(msg"\n"); \
|
||||||
DWORD cr0, cr2, cr3, cr4; \
|
DWORD cr0, cr2, cr3, cr4; \
|
||||||
asm ("movl %%cr0, %%eax":"=a"(cr0)); \
|
asm ("movl %%cr0, %%eax":"=a"(cr0)); \
|
||||||
|
|
|
@ -37,9 +37,11 @@ system_t system;
|
||||||
VirtualConsole* tty0;
|
VirtualConsole* tty0;
|
||||||
VirtualConsole* tty1;
|
VirtualConsole* tty1;
|
||||||
VirtualConsole* tty2;
|
VirtualConsole* tty2;
|
||||||
|
Keyboard* keyboard;
|
||||||
|
|
||||||
void banner()
|
void banner()
|
||||||
{
|
{
|
||||||
|
InterruptDisabler disabler;
|
||||||
kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n");
|
kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,8 +109,6 @@ static void init_stage2()
|
||||||
|
|
||||||
Syscall::initialize();
|
Syscall::initialize();
|
||||||
|
|
||||||
auto keyboard = make<Keyboard>();
|
|
||||||
|
|
||||||
Disk::initialize();
|
Disk::initialize();
|
||||||
|
|
||||||
#ifdef TEST_VFS
|
#ifdef TEST_VFS
|
||||||
|
@ -189,11 +189,13 @@ static void init_stage2()
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int error;
|
|
||||||
auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error);
|
|
||||||
|
|
||||||
banner();
|
banner();
|
||||||
|
|
||||||
|
int error;
|
||||||
|
auto* sh0 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty0);
|
||||||
|
auto* sh1 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty1);
|
||||||
|
auto* sh2 = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error, nullptr, tty2);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// It would be nice to exit this process, but right now it instantiates all kinds of things.
|
// It would be nice to exit this process, but right now it instantiates all kinds of things.
|
||||||
// At the very least it needs to be made sure those things stick around as appropriate.
|
// At the very least it needs to be made sure those things stick around as appropriate.
|
||||||
|
@ -216,21 +218,20 @@ void init()
|
||||||
kmalloc_init();
|
kmalloc_init();
|
||||||
vga_init();
|
vga_init();
|
||||||
|
|
||||||
VirtualConsole::initialize();
|
|
||||||
tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer);
|
|
||||||
tty1 = new VirtualConsole(1);
|
|
||||||
tty2 = new VirtualConsole(2);
|
|
||||||
tty0->setActive(true);
|
|
||||||
tty1->setActive(false);
|
|
||||||
tty2->setActive(false);
|
|
||||||
auto console = make<Console>();
|
|
||||||
console->setImplementation(tty0);
|
|
||||||
|
|
||||||
RTC::initialize();
|
RTC::initialize();
|
||||||
PIC::initialize();
|
PIC::initialize();
|
||||||
gdt_init();
|
gdt_init();
|
||||||
idt_init();
|
idt_init();
|
||||||
|
|
||||||
|
keyboard = new Keyboard;
|
||||||
|
|
||||||
|
auto console = make<Console>();
|
||||||
|
VirtualConsole::initialize();
|
||||||
|
tty0 = new VirtualConsole(0, VirtualConsole::AdoptCurrentVGABuffer);
|
||||||
|
tty1 = new VirtualConsole(1);
|
||||||
|
tty2 = new VirtualConsole(2);
|
||||||
|
VirtualConsole::switchTo(0);
|
||||||
|
|
||||||
MemoryManager::initialize();
|
MemoryManager::initialize();
|
||||||
|
|
||||||
VirtualFileSystem::initializeGlobals();
|
VirtualFileSystem::initializeGlobals();
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
#include "errno.h"
|
#include "errno.h"
|
||||||
|
#include "unistd.h"
|
||||||
#include <Kernel/Syscall.h>
|
#include <Kernel/Syscall.h>
|
||||||
#include <AK/printf.cpp>
|
#include <AK/printf.cpp>
|
||||||
|
|
||||||
|
@ -10,13 +11,14 @@ extern "C" {
|
||||||
|
|
||||||
int putchar(int ch)
|
int putchar(int ch)
|
||||||
{
|
{
|
||||||
Syscall::invoke(Syscall::PutCharacter, ch);
|
write(0, &ch, 1);
|
||||||
|
//Syscall::invoke(Syscall::PutCharacter, ch);
|
||||||
return (byte)ch;
|
return (byte)ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void sys_putch(char*, char ch)
|
static void sys_putch(char*&, char ch)
|
||||||
{
|
{
|
||||||
Syscall::invoke(Syscall::PutCharacter, ch);
|
putchar(ch);
|
||||||
}
|
}
|
||||||
|
|
||||||
int printf(const char* fmt, ...)
|
int printf(const char* fmt, ...)
|
||||||
|
|
|
@ -32,6 +32,12 @@ ssize_t read(int fd, void* buf, size_t count)
|
||||||
__RETURN_WITH_ERRNO(rc, rc, -1);
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ssize_t write(int fd, const void* buf, size_t count)
|
||||||
|
{
|
||||||
|
int rc = Syscall::invoke(Syscall::PosixWrite, (dword)fd, (dword)buf, (dword)count);
|
||||||
|
__RETURN_WITH_ERRNO(rc, rc, -1);
|
||||||
|
}
|
||||||
|
|
||||||
int close(int fd)
|
int close(int fd)
|
||||||
{
|
{
|
||||||
int rc = Syscall::invoke(Syscall::PosixClose, fd);
|
int rc = Syscall::invoke(Syscall::PosixClose, fd);
|
||||||
|
|
|
@ -9,6 +9,7 @@ gid_t getgid();
|
||||||
pid_t getpid();
|
pid_t getpid();
|
||||||
int open(const char* path, int options);
|
int open(const char* path, int options);
|
||||||
ssize_t read(int fd, void* buf, size_t count);
|
ssize_t read(int fd, void* buf, size_t count);
|
||||||
|
ssize_t write(int fd, const void* buf, size_t count);
|
||||||
int close(int fd);
|
int close(int fd);
|
||||||
pid_t waitpid(pid_t, int* wstatus, int options);
|
pid_t waitpid(pid_t, int* wstatus, int options);
|
||||||
int chdir(const char* path);
|
int chdir(const char* path);
|
||||||
|
|
|
@ -159,7 +159,7 @@ int main(int, char**)
|
||||||
int linedx = 0;
|
int linedx = 0;
|
||||||
linebuf[0] = '\0';
|
linebuf[0] = '\0';
|
||||||
|
|
||||||
int fd = open("/dev/keyboard", O_RDONLY);
|
int fd = 0; // open("/dev/keyboard", O_RDONLY);
|
||||||
if (fd == -1) {
|
if (fd == -1) {
|
||||||
printf("failed to open /dev/keyboard :(\n");
|
printf("failed to open /dev/keyboard :(\n");
|
||||||
return 1;
|
return 1;
|
||||||
|
|
|
@ -6,5 +6,5 @@ CharacterDevice::~CharacterDevice()
|
||||||
|
|
||||||
OwnPtr<FileHandle> CharacterDevice::open(int options)
|
OwnPtr<FileHandle> CharacterDevice::open(int options)
|
||||||
{
|
{
|
||||||
//VirtualFileSystem::the().open()
|
return VirtualFileSystem::the().open(*this, options);
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,16 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count)
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unix::ssize_t FileHandle::write(const byte* data, Unix::size_t size)
|
||||||
|
{
|
||||||
|
if (m_vnode->isCharacterDevice()) {
|
||||||
|
// FIXME: What should happen to m_currentOffset?
|
||||||
|
return m_vnode->characterDevice()->write(data, size);
|
||||||
|
}
|
||||||
|
// FIXME: Implement non-device writes.
|
||||||
|
ASSERT_NOT_REACHED();
|
||||||
|
}
|
||||||
|
|
||||||
bool FileHandle::hasDataAvailableForRead()
|
bool FileHandle::hasDataAvailableForRead()
|
||||||
{
|
{
|
||||||
if (m_vnode->isCharacterDevice())
|
if (m_vnode->isCharacterDevice())
|
||||||
|
|
|
@ -10,7 +10,8 @@ public:
|
||||||
~FileHandle();
|
~FileHandle();
|
||||||
|
|
||||||
Unix::off_t seek(Unix::off_t, int whence);
|
Unix::off_t seek(Unix::off_t, int whence);
|
||||||
Unix::ssize_t read(byte* buffer, Unix::size_t count);
|
Unix::ssize_t read(byte*, Unix::size_t);
|
||||||
|
Unix::ssize_t write(const byte* data, Unix::size_t);
|
||||||
int stat(Unix::stat*);
|
int stat(Unix::stat*);
|
||||||
|
|
||||||
bool hasDataAvailableForRead();
|
bool hasDataAvailableForRead();
|
||||||
|
|
|
@ -89,6 +89,21 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||||
return vnode;
|
return vnode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto VirtualFileSystem::makeNode(CharacterDevice& device) -> RetainPtr<Node>
|
||||||
|
{
|
||||||
|
auto vnode = allocateNode();
|
||||||
|
ASSERT(vnode);
|
||||||
|
|
||||||
|
#ifdef VFS_DEBUG
|
||||||
|
kprintf("makeNode: device=%p (%u,%u)\n", &device, device.major(), device.minor());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
m_device2vnode.set(encodedDevice(device.major(), device.minor()), vnode.ptr());
|
||||||
|
vnode->m_characterDevice = &device;
|
||||||
|
|
||||||
|
return vnode;
|
||||||
|
}
|
||||||
|
|
||||||
auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node>
|
auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node>
|
||||||
{
|
{
|
||||||
auto it = m_inode2vnode.find(inode);
|
auto it = m_inode2vnode.find(inode);
|
||||||
|
@ -97,6 +112,14 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node
|
||||||
return makeNode(inode);
|
return makeNode(inode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto VirtualFileSystem::getOrCreateNode(CharacterDevice& device) -> RetainPtr<Node>
|
||||||
|
{
|
||||||
|
auto it = m_device2vnode.find(encodedDevice(device.major(), device.minor()));
|
||||||
|
if (it != m_device2vnode.end())
|
||||||
|
return (*it).value;
|
||||||
|
return makeNode(device);
|
||||||
|
}
|
||||||
|
|
||||||
bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path)
|
bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path)
|
||||||
{
|
{
|
||||||
ASSERT(fileSystem);
|
ASSERT(fileSystem);
|
||||||
|
@ -161,10 +184,15 @@ void VirtualFileSystem::freeNode(Node* node)
|
||||||
{
|
{
|
||||||
ASSERT(node);
|
ASSERT(node);
|
||||||
ASSERT(node->inUse());
|
ASSERT(node->inUse());
|
||||||
m_inode2vnode.remove(node->inode);
|
if (node->inode.isValid()) {
|
||||||
node->inode.fileSystem()->release();
|
m_inode2vnode.remove(node->inode);
|
||||||
node->inode = InodeIdentifier();
|
node->inode.fileSystem()->release();
|
||||||
node->m_characterDevice = nullptr;
|
node->inode = InodeIdentifier();
|
||||||
|
}
|
||||||
|
if (node->m_characterDevice) {
|
||||||
|
m_device2vnode.remove(encodedDevice(node->m_characterDevice->major(), node->m_characterDevice->minor()));
|
||||||
|
node->m_characterDevice = nullptr;
|
||||||
|
}
|
||||||
m_nodeFreeList.append(move(node));
|
m_nodeFreeList.append(move(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,6 +389,14 @@ bool VirtualFileSystem::touch(const String& path)
|
||||||
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
|
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OwnPtr<FileHandle> VirtualFileSystem::open(CharacterDevice& device, int options)
|
||||||
|
{
|
||||||
|
auto vnode = getOrCreateNode(device);
|
||||||
|
if (!vnode)
|
||||||
|
return nullptr;
|
||||||
|
return make<FileHandle>(move(vnode));
|
||||||
|
}
|
||||||
|
|
||||||
OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int& error, int options, InodeIdentifier base)
|
OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int& error, int options, InodeIdentifier base)
|
||||||
{
|
{
|
||||||
auto inode = resolvePath(path, error, base, options);
|
auto inode = resolvePath(path, error, base, options);
|
||||||
|
|
|
@ -51,7 +51,7 @@ public:
|
||||||
InodeIdentifier inode;
|
InodeIdentifier inode;
|
||||||
const InodeMetadata& metadata() const;
|
const InodeMetadata& metadata() const;
|
||||||
|
|
||||||
bool inUse() const { return inode.isValid(); }
|
bool inUse() const { return inode.isValid() || m_characterDevice; }
|
||||||
|
|
||||||
bool isCharacterDevice() const { return m_characterDevice; }
|
bool isCharacterDevice() const { return m_characterDevice; }
|
||||||
CharacterDevice* characterDevice() { return m_characterDevice; }
|
CharacterDevice* characterDevice() { return m_characterDevice; }
|
||||||
|
@ -91,6 +91,7 @@ public:
|
||||||
bool mountRoot(RetainPtr<FileSystem>&&);
|
bool mountRoot(RetainPtr<FileSystem>&&);
|
||||||
bool mount(RetainPtr<FileSystem>&&, const String& path);
|
bool mount(RetainPtr<FileSystem>&&, const String& path);
|
||||||
|
|
||||||
|
OwnPtr<FileHandle> open(CharacterDevice&, int options);
|
||||||
OwnPtr<FileHandle> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier());
|
OwnPtr<FileHandle> open(const String& path, int& error, int options = 0, InodeIdentifier base = InodeIdentifier());
|
||||||
OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier());
|
OwnPtr<FileHandle> create(const String& path, InodeIdentifier base = InodeIdentifier());
|
||||||
OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
|
OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
|
||||||
|
@ -117,7 +118,9 @@ private:
|
||||||
void freeNode(Node*);
|
void freeNode(Node*);
|
||||||
|
|
||||||
RetainPtr<Node> makeNode(InodeIdentifier);
|
RetainPtr<Node> makeNode(InodeIdentifier);
|
||||||
|
RetainPtr<Node> makeNode(CharacterDevice&);
|
||||||
RetainPtr<Node> getOrCreateNode(InodeIdentifier);
|
RetainPtr<Node> getOrCreateNode(InodeIdentifier);
|
||||||
|
RetainPtr<Node> getOrCreateNode(CharacterDevice&);
|
||||||
|
|
||||||
Mount* findMountForHost(InodeIdentifier);
|
Mount* findMountForHost(InodeIdentifier);
|
||||||
Mount* findMountForGuest(InodeIdentifier);
|
Mount* findMountForGuest(InodeIdentifier);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue