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:
Andreas Kling 2018-10-30 15:33:37 +01:00
parent 68739dc43e
commit 7a7956a595
Notes: sideshowbarker 2024-07-19 18:36:29 +09:00
24 changed files with 251 additions and 103 deletions

View file

@ -38,6 +38,12 @@ static char shift_map[0x100] =
0, 0, 0, ' '
};
void Keyboard::emit(byte ch)
{
if (m_client)
m_client->onKeyPress(ch);
m_queue.enqueue(ch);
}
void Keyboard::handleIRQ()
{
@ -50,7 +56,7 @@ void Keyboard::handleIRQ()
case 0x9D: m_modifiers &= ~MOD_CTRL; break;
case 0x2A: 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;
default:
if (ch & 0x80) {
@ -69,31 +75,33 @@ void Keyboard::handleIRQ()
}
}
if (!m_modifiers) {
if (m_client)
m_client->onKeyPress(map[ch]);
m_queue.enqueue(map[ch]);
emit(map[ch]);
} else if (m_modifiers & MOD_SHIFT) {
if (m_client)
m_client->onKeyPress(shift_map[ch]);
m_queue.enqueue(shift_map[ch]);
emit(shift_map[ch]);
} else if (m_modifiers & MOD_CTRL) {
// FIXME: This is obviously not a good enough way to process ctrl+whatever.
if (m_client) {
m_client->onKeyPress('^');
m_client->onKeyPress(shift_map[ch]);
}
m_queue.enqueue('^');
m_queue.enqueue(shift_map[ch]);
emit('^');
emit(shift_map[ch]);
}
}
//break;
}
}
static Keyboard* s_the;
Keyboard& Keyboard::the()
{
ASSERT(s_the);
return *s_the;
}
Keyboard::Keyboard()
: IRQHandler(IRQ_KEYBOARD)
, CharacterDevice(85, 1)
{
s_the = this;
// Empty the buffer of any pending data.
// I don't care what you've been pressing until now!
while (IO::in8(I8042_STATUS ) & DATA_AVAILABLE)

View file

@ -19,7 +19,7 @@ public:
virtual ~Keyboard() override;
Keyboard();
void setClient(KeyboardClient*);
void setClient(KeyboardClient* client) { m_client = client; }
private:
// ^IRQHandler
@ -30,6 +30,8 @@ private:
virtual ssize_t write(const byte* buffer, size_t) override;
virtual bool hasDataAvailableForRead() const override;
void emit(byte);
KeyboardClient* m_client { nullptr };
CircularQueue<byte, 16> m_queue;
byte m_modifiers { 0 };

View file

@ -201,15 +201,16 @@ ByteBuffer procfs$summary()
auto tasks = Task::allTasks();
auto buffer = ByteBuffer::createUninitialized(tasks.size() * 256);
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) {
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->uid(),
toString(task->state()),
task->parentPID(),
task->timesScheduled(),
task->fileHandleCount(),
task->tty() ? task->tty()->ttyName().characters() : "n/a",
task->name().characters());
}
*ptr = '\0';

View file

@ -70,6 +70,8 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
return current->sys$getcwd((char*)arg1, (size_t)arg2);
case Syscall::PosixOpen:
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:
//kprintf("syscall: close(%d)\n", arg1);
return current->sys$close((int)arg1);

View file

@ -36,6 +36,7 @@ enum Function {
PosixUname = 0x2004,
SetMmapName = 0x2005,
PosixReadlink = 0x2006,
PosixWrite = 0x2007,
};
void initialize();

View file

@ -11,15 +11,30 @@ TTY::~TTY()
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)
{
for (size_t i = 0; i < size; ++i)
onTTYWrite(buffer[i]);
return 0;
}
bool TTY::hasDataAvailableForRead() const
{
return false;
return !m_buffer.isEmpty();
}
void TTY::emit(byte ch)
{
m_buffer.append(ch);
}

View file

@ -10,7 +10,15 @@ public:
virtual ssize_t write(const byte*, size_t) override;
virtual bool hasDataAvailableForRead() const override;
virtual String ttyName() const = 0;
protected:
TTY(unsigned major, unsigned minor);
void emit(byte);
virtual void onTTYWrite(byte) = 0;
private:
Vector<byte> m_buffer;
};

View file

@ -214,13 +214,13 @@ int Task::sys$gethostname(char* buffer, size_t size)
int Task::sys$spawn(const char* path, const char** args)
{
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)
return child->pid();
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('/');
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.
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);
@ -372,8 +372,8 @@ Task::Task(String&& name, uid_t uid, gid_t gid, pid_t parentPID, RingLevel ring,
, m_ring(ring)
, m_cwd(move(cwd))
, m_executable(move(executable))
, m_parentPID(parentPID)
, m_tty(tty)
, m_parentPID(parentPID)
{
if (tty) {
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);
}
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)
{
VALIDATE_USER_BUFFER(outbuf, nread);
@ -763,13 +782,8 @@ ssize_t Task::sys$read(int fd, void* outbuf, size_t nread)
#ifdef DEBUG_IO
kprintf("Task::sys$read: handle=%p\n", handle);
#endif
if (!handle) {
kprintf("Task::sys$read: handle not found :(\n");
return -1;
}
#ifdef DEBUG_IO
kprintf("call read on handle=%p\n", handle);
#endif
if (!handle)
return -EBADF;
if (handle->isBlocking()) {
if (!handle->hasDataAvailableForRead()) {
m_fdBlockedOnRead = fd;

View file

@ -20,7 +20,7 @@ class Task : public InlineLinkedListNode<Task> {
struct Subregion;
public:
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();
static Vector<Task*> allTasks();
@ -90,7 +90,8 @@ public:
pid_t sys$getpid();
int sys$open(const char* path, int options);
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$seek(int fd, int offset);
int sys$kill(pid_t pid, int sig);
@ -115,6 +116,8 @@ public:
static void taskDidCrash(Task*);
const TTY* tty() const { return m_tty; }
size_t regionCount() const { return m_regions.size(); }
const Vector<RetainPtr<Region>>& regions() const { return m_regions; }
size_t subregionCount() const { return m_regions.size(); }

View file

@ -31,16 +31,11 @@ void vga_clear()
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);
vga_mem[cur] = ch;
vga_mem[cur + 1] = current_attr;
}
void vga_set_attr(BYTE attr)
{
current_attr = attr;
vga_mem[cur + 1] = attr;
}
byte vga_get_attr()

View file

@ -3,12 +3,10 @@
#include "types.h"
void vga_init();
BYTE vga_get_attr();
void vga_set_attr(BYTE);
void vga_set_cursor(WORD);
void vga_set_cursor(BYTE row, BYTE column);
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_clear();
void vga_clear_row(word);

View file

@ -3,16 +3,17 @@
#include "kmalloc.h"
#include "i386.h"
#include "StdLib.h"
#include "Keyboard.h"
#include <AK/String.h>
static byte* s_vgaBuffer = (byte*)0xb8000;
static VirtualConsole* s_consoles[6];
static unsigned s_activeConsole;
static int s_activeConsole;
void VirtualConsole::initialize()
{
memset(s_consoles, 0, sizeof(s_consoles));
s_activeConsole = 0;
s_activeConsole = -1;
}
VirtualConsole::VirtualConsole(unsigned index, InitialContents initialContents)
@ -40,7 +41,7 @@ VirtualConsole::~VirtualConsole()
void VirtualConsole::switchTo(unsigned index)
{
if (index == s_activeConsole)
if ((int)index == s_activeConsole)
return;
dbgprintf("[VC] Switch to %u\n", index);
ASSERT(index < 6);
@ -49,6 +50,7 @@ void VirtualConsole::switchTo(unsigned index)
s_consoles[s_activeConsole]->setActive(false);
s_activeConsole = index;
s_consoles[s_activeConsole]->setActive(true);
Console::the().setImplementation(s_consoles[s_activeConsole]);
}
void VirtualConsole::setActive(bool b)
@ -60,14 +62,14 @@ void VirtualConsole::setActive(bool b)
m_active = b;
if (!m_active) {
dbgprintf("%u becomes inactive, copying to buffer\n", m_index);
memcpy(m_buffer, s_vgaBuffer, 80 * 25 * 2);
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);
vga_set_cursor(m_cursorRow, m_cursorColumn);
Keyboard::the().setClient(this);
}
inline bool isParameter(byte ch)
@ -205,7 +207,6 @@ void VirtualConsole::escape$m(const Vector<unsigned>& params)
break;
}
}
vga_set_attr(m_currentAttribute);
}
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>&)
{
m_cursorRow = m_savedCursorRow;
m_cursorColumn = m_savedCursorColumn;
vga_set_cursor(m_cursorRow, m_cursorColumn);
setCursor(m_savedCursorRow, m_savedCursorColumn);
}
void VirtualConsole::escape$H(const Vector<unsigned>& params)
@ -229,9 +228,7 @@ void VirtualConsole::escape$H(const Vector<unsigned>& params)
row = params[0];
if (params.size() >= 2)
col = params[1];
m_cursorRow = row - 1;
m_cursorColumn = col - 1;
vga_set_cursor(row - 1, col - 1);
setCursor(row - 1, col - 1);
}
void VirtualConsole::escape$J(const Vector<unsigned>& params)
@ -284,16 +281,42 @@ void VirtualConsole::executeEscapeSequence(byte final)
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();
} else {
++m_cursorRow;
}
m_cursorColumn = 0;
};
} else {
++m_cursorRow;
}
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) {
case ExpectBracket:
@ -336,32 +359,43 @@ void VirtualConsole::onChar(byte ch)
return;
case 8: // Backspace
if (m_cursorColumn) {
--m_cursorColumn;\
vga_set_cursor(m_cursorRow, m_cursorColumn);
vga_putch_at(m_cursorRow, m_cursorColumn, ' ');
setCursor(m_cursorRow, m_cursorColumn - 1);
putCharacterAt(m_cursorRow, m_cursorColumn, ' ');
return;
}
break;
case '\n':
scrollup();
vga_set_cursor(m_cursorRow, m_cursorColumn);
scrollUp();
setCursor(m_cursorRow, m_cursorColumn);
return;
}
vga_putch_at(m_cursorRow, m_cursorColumn, ch);
putCharacterAt(m_cursorRow, m_cursorColumn, ch);
++m_cursorColumn;
if (m_cursorColumn >= m_columns)
scrollup();
vga_set_cursor(m_cursorRow, m_cursorColumn);
scrollUp();
setCursor(m_cursorRow, m_cursorColumn);
}
void VirtualConsole::onKeyPress(byte ch)
{
onChar(ch);
emit(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);
}

View file

@ -19,17 +19,25 @@ public:
private:
// ^KeyboardClient
void onKeyPress(byte) override;
virtual void onKeyPress(byte) override;
// ^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;
unsigned m_index;
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$J(const Vector<unsigned>&);
void escape$m(const Vector<unsigned>&);
@ -56,6 +64,4 @@ private:
EscapeState m_escState { Normal };
Vector<byte> m_parameters;
Vector<byte> m_intermediates;
};

View file

@ -192,6 +192,8 @@ void exception_13_handler()
EH_ENTRY(14);
void exception_14_handler()
{
ASSERT(current);
dword faultAddress;
asm ("movl %%cr2, %%eax":"=a"(faultAddress));
@ -249,7 +251,6 @@ void exception_14_handler()
#define EH(i, msg) \
static void _exception ## i () \
{ \
vga_set_attr(0x0a); \
kprintf(msg"\n"); \
DWORD cr0, cr2, cr3, cr4; \
asm ("movl %%cr0, %%eax":"=a"(cr0)); \

View file

@ -37,9 +37,11 @@ system_t system;
VirtualConsole* tty0;
VirtualConsole* tty1;
VirtualConsole* tty2;
Keyboard* keyboard;
void banner()
{
InterruptDisabler disabler;
kprintf("\n\033[33;1mWelcome to \033[36;1mSerenity OS!\033[0m\n\n");
}
@ -107,8 +109,6 @@ static void init_stage2()
Syscall::initialize();
auto keyboard = make<Keyboard>();
Disk::initialize();
#ifdef TEST_VFS
@ -189,11 +189,13 @@ static void init_stage2()
}
#endif
int error;
auto* shTask = Task::createUserTask("/bin/sh", (uid_t)100, (gid_t)100, (pid_t)0, error);
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
// 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.
@ -216,21 +218,20 @@ void init()
kmalloc_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();
PIC::initialize();
gdt_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();
VirtualFileSystem::initializeGlobals();

View file

@ -3,6 +3,7 @@
#include "types.h"
#include "string.h"
#include "errno.h"
#include "unistd.h"
#include <Kernel/Syscall.h>
#include <AK/printf.cpp>
@ -10,13 +11,14 @@ extern "C" {
int putchar(int ch)
{
Syscall::invoke(Syscall::PutCharacter, ch);
write(0, &ch, 1);
//Syscall::invoke(Syscall::PutCharacter, 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, ...)

View file

@ -32,6 +32,12 @@ ssize_t read(int fd, void* buf, size_t count)
__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 rc = Syscall::invoke(Syscall::PosixClose, fd);

View file

@ -9,6 +9,7 @@ gid_t getgid();
pid_t getpid();
int open(const char* path, int options);
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);
pid_t waitpid(pid_t, int* wstatus, int options);
int chdir(const char* path);

View file

@ -159,7 +159,7 @@ int main(int, char**)
int linedx = 0;
linebuf[0] = '\0';
int fd = open("/dev/keyboard", O_RDONLY);
int fd = 0; // open("/dev/keyboard", O_RDONLY);
if (fd == -1) {
printf("failed to open /dev/keyboard :(\n");
return 1;

View file

@ -6,5 +6,5 @@ CharacterDevice::~CharacterDevice()
OwnPtr<FileHandle> CharacterDevice::open(int options)
{
//VirtualFileSystem::the().open()
return VirtualFileSystem::the().open(*this, options);
}

View file

@ -101,6 +101,16 @@ Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count)
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()
{
if (m_vnode->isCharacterDevice())

View file

@ -10,7 +10,8 @@ public:
~FileHandle();
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*);
bool hasDataAvailableForRead();

View file

@ -89,6 +89,21 @@ auto VirtualFileSystem::makeNode(InodeIdentifier inode) -> RetainPtr<Node>
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 it = m_inode2vnode.find(inode);
@ -97,6 +112,14 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node
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)
{
ASSERT(fileSystem);
@ -161,10 +184,15 @@ void VirtualFileSystem::freeNode(Node* node)
{
ASSERT(node);
ASSERT(node->inUse());
m_inode2vnode.remove(node->inode);
node->inode.fileSystem()->release();
node->inode = InodeIdentifier();
node->m_characterDevice = nullptr;
if (node->inode.isValid()) {
m_inode2vnode.remove(node->inode);
node->inode.fileSystem()->release();
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));
}
@ -361,6 +389,14 @@ bool VirtualFileSystem::touch(const String& path)
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)
{
auto inode = resolvePath(path, error, base, options);

View file

@ -51,7 +51,7 @@ public:
InodeIdentifier inode;
const InodeMetadata& metadata() const;
bool inUse() const { return inode.isValid(); }
bool inUse() const { return inode.isValid() || m_characterDevice; }
bool isCharacterDevice() const { return m_characterDevice; }
CharacterDevice* characterDevice() { return m_characterDevice; }
@ -91,6 +91,7 @@ public:
bool mountRoot(RetainPtr<FileSystem>&&);
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> create(const String& path, InodeIdentifier base = InodeIdentifier());
OwnPtr<FileHandle> mkdir(const String& path, InodeIdentifier base = InodeIdentifier());
@ -117,7 +118,9 @@ private:
void freeNode(Node*);
RetainPtr<Node> makeNode(InodeIdentifier);
RetainPtr<Node> makeNode(CharacterDevice&);
RetainPtr<Node> getOrCreateNode(InodeIdentifier);
RetainPtr<Node> getOrCreateNode(CharacterDevice&);
Mount* findMountForHost(InodeIdentifier);
Mount* findMountForGuest(InodeIdentifier);