mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
Fix broken SpinLock.
The SpinLock was all backwards and didn't actually work. Fixing it exposed how wrong most of the locking here is. I need to come up with a better granularity here.
This commit is contained in:
parent
bea106fdb2
commit
e6284a8774
Notes:
sideshowbarker
2024-07-19 18:36:50 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/e6284a8774b
24 changed files with 195 additions and 77 deletions
52
AK/Lock.h
52
AK/Lock.h
|
@ -2,6 +2,20 @@
|
||||||
|
|
||||||
#include "Types.h"
|
#include "Types.h"
|
||||||
|
|
||||||
|
#ifdef SERENITY
|
||||||
|
#include "i386.h"
|
||||||
|
#else
|
||||||
|
typedef int InterruptDisabler;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//#define DEBUG_LOCKS
|
||||||
|
|
||||||
|
void log_try_lock(const char*);
|
||||||
|
void log_locked(const char*);
|
||||||
|
void log_unlocked(const char*);
|
||||||
|
|
||||||
|
void yield();
|
||||||
|
|
||||||
namespace AK {
|
namespace AK {
|
||||||
|
|
||||||
static inline dword CAS(volatile dword* mem, dword newval, dword oldval)
|
static inline dword CAS(volatile dword* mem, dword newval, dword oldval)
|
||||||
|
@ -9,28 +23,46 @@ static inline dword CAS(volatile dword* mem, dword newval, dword oldval)
|
||||||
dword ret;
|
dword ret;
|
||||||
asm volatile(
|
asm volatile(
|
||||||
"cmpxchgl %2, %1"
|
"cmpxchgl %2, %1"
|
||||||
:"=a"(ret), "=m"(*mem)
|
:"=a"(ret), "+m"(*mem)
|
||||||
:"r"(newval), "m"(*mem), "0"(oldval));
|
:"r"(newval), "0"(oldval)
|
||||||
|
:"memory");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
class SpinLock {
|
class SpinLock {
|
||||||
public:
|
public:
|
||||||
SpinLock() { }
|
SpinLock() { }
|
||||||
~SpinLock() { unlock(); }
|
~SpinLock() { }
|
||||||
|
|
||||||
void lock()
|
void lock(const char* func = nullptr)
|
||||||
{
|
{
|
||||||
|
#ifdef DEBUG_LOCKS
|
||||||
|
{
|
||||||
|
InterruptDisabler dis;
|
||||||
|
log_try_lock(func);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (CAS(&m_lock, 1, 0) == 1)
|
if (CAS(&m_lock, 1, 0) == 0) {
|
||||||
|
#ifdef DEBUG_LOCKS
|
||||||
|
InterruptDisabler dis;
|
||||||
|
log_locked(func);
|
||||||
|
#endif
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
yield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void unlock()
|
void unlock(const char* func = nullptr)
|
||||||
{
|
{
|
||||||
// barrier();
|
// barrier();
|
||||||
|
ASSERT(m_lock);
|
||||||
m_lock = 0;
|
m_lock = 0;
|
||||||
|
#ifdef DEBUG_LOCKS
|
||||||
|
InterruptDisabler dis;
|
||||||
|
log_unlocked(func);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void init()
|
void init()
|
||||||
|
@ -44,14 +76,18 @@ private:
|
||||||
|
|
||||||
class Locker {
|
class Locker {
|
||||||
public:
|
public:
|
||||||
explicit Locker(SpinLock& l) : m_lock(l) { m_lock.lock(); }
|
explicit Locker(SpinLock& l, const char* func) : m_lock(l), m_func(func) { lock(); }
|
||||||
~Locker() { unlock(); }
|
~Locker() { unlock(); }
|
||||||
void unlock() { m_lock.unlock(); }
|
void unlock() { m_lock.unlock(m_func); }
|
||||||
|
void lock() { m_lock.lock(m_func); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
SpinLock& m_lock;
|
SpinLock& m_lock;
|
||||||
|
const char* m_func { nullptr };
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define LOCKER(lock) Locker locker(lock, __FUNCTION__)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
using AK::SpinLock;
|
using AK::SpinLock;
|
||||||
|
|
|
@ -18,7 +18,7 @@ String StringBuilder::build()
|
||||||
if (strings.isEmpty())
|
if (strings.isEmpty())
|
||||||
return String::empty();
|
return String::empty();
|
||||||
|
|
||||||
size_t sizeNeeded = 1;
|
size_t sizeNeeded = 0;
|
||||||
for (auto& string : strings)
|
for (auto& string : strings)
|
||||||
sizeNeeded += string.length();
|
sizeNeeded += string.length();
|
||||||
|
|
||||||
|
|
|
@ -29,7 +29,7 @@ struct Traits<T*> {
|
||||||
#ifdef SERENITY
|
#ifdef SERENITY
|
||||||
return intHash((dword)p);
|
return intHash((dword)p);
|
||||||
#else
|
#else
|
||||||
return intHash((ptrdiff_t)p & 0xffffffff);
|
return intHash((unsigned long long)p & 0xffffffff);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
static void dump(const T* p) { kprintf("%p", p); }
|
static void dump(const T* p) { kprintf("%p", p); }
|
||||||
|
|
|
@ -11,13 +11,22 @@
|
||||||
#include "WeakPtr.h"
|
#include "WeakPtr.h"
|
||||||
#include "CircularQueue.h"
|
#include "CircularQueue.h"
|
||||||
#include "FileSystemPath.h"
|
#include "FileSystemPath.h"
|
||||||
|
#include "Lock.h"
|
||||||
|
|
||||||
static void testWeakPtr();
|
static void testWeakPtr();
|
||||||
|
|
||||||
|
void log_locked() { }
|
||||||
|
void log_unlocked() { }
|
||||||
|
|
||||||
int main(int c, char** v)
|
int main(int c, char** v)
|
||||||
{
|
{
|
||||||
StringImpl::initializeGlobals();
|
StringImpl::initializeGlobals();
|
||||||
|
|
||||||
|
{
|
||||||
|
SpinLock lock;
|
||||||
|
Locker locker(lock);
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char* testpath = "/proc/../proc/1/../../proc/1/vm";
|
const char* testpath = "/proc/../proc/1/../../proc/1/vm";
|
||||||
if (c == 2)
|
if (c == 2)
|
||||||
|
|
|
@ -178,7 +178,7 @@ const ELFImage::RelocationSection ELFImage::Section::relocations() const
|
||||||
{
|
{
|
||||||
// FIXME: This is ugly.
|
// FIXME: This is ugly.
|
||||||
char relocationSectionName[128];
|
char relocationSectionName[128];
|
||||||
int x = ksprintf(relocationSectionName, ".rel%s", name());
|
ksprintf(relocationSectionName, ".rel%s", name());
|
||||||
|
|
||||||
#ifdef ELFIMAGE_DEBUG
|
#ifdef ELFIMAGE_DEBUG
|
||||||
kprintf("looking for '%s'\n", relocationSectionName);
|
kprintf("looking for '%s'\n", relocationSectionName);
|
||||||
|
|
|
@ -28,11 +28,10 @@ bool Console::hasDataAvailableForRead() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t Console::read(byte* buffer, size_t bufferSize)
|
ssize_t Console::read(byte*, size_t)
|
||||||
{
|
{
|
||||||
// FIXME: Implement reading from the console.
|
// FIXME: Implement reading from the console.
|
||||||
// Maybe we could use a ring buffer for this device?
|
// Maybe we could use a ring buffer for this device?
|
||||||
// A generalized ring buffer would probably be useful.
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,18 +41,15 @@ asm(
|
||||||
|
|
||||||
namespace Syscall {
|
namespace Syscall {
|
||||||
|
|
||||||
static SpinLock* s_lock;
|
|
||||||
|
|
||||||
void initialize()
|
void initialize()
|
||||||
{
|
{
|
||||||
s_lock = new SpinLock;
|
|
||||||
registerUserCallableInterruptHandler(0x80, syscall_ISR);
|
registerUserCallableInterruptHandler(0x80, syscall_ISR);
|
||||||
kprintf("syscall: int 0x80 handler installed\n");
|
kprintf("syscall: int 0x80 handler installed\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
{
|
{
|
||||||
Locker locker(*s_lock);
|
ASSERT_INTERRUPTS_ENABLED();
|
||||||
switch (function) {
|
switch (function) {
|
||||||
case Syscall::Yield:
|
case Syscall::Yield:
|
||||||
yield();
|
yield();
|
||||||
|
@ -73,8 +70,7 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
case Syscall::PosixGetcwd:
|
case Syscall::PosixGetcwd:
|
||||||
return current->sys$getcwd((char*)arg1, (size_t)arg2);
|
return current->sys$getcwd((char*)arg1, (size_t)arg2);
|
||||||
case Syscall::PosixOpen:
|
case Syscall::PosixOpen:
|
||||||
//kprintf("syscall: open('%s', %u)\n", arg1, arg2);
|
return current->sys$open((const char*)arg1, (int)arg2);
|
||||||
return current->sys$open((const char*)arg1, (size_t)arg2);
|
|
||||||
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);
|
||||||
|
@ -104,7 +100,7 @@ DWORD handle(DWORD function, DWORD arg1, DWORD arg2, DWORD arg3)
|
||||||
return current->sys$gethostname((char*)arg1, (size_t)arg2);
|
return current->sys$gethostname((char*)arg1, (size_t)arg2);
|
||||||
case Syscall::PosixExit:
|
case Syscall::PosixExit:
|
||||||
cli();
|
cli();
|
||||||
locker.unlock();
|
//locker.unlock();
|
||||||
current->sys$exit((int)arg1);
|
current->sys$exit((int)arg1);
|
||||||
ASSERT_NOT_REACHED();
|
ASSERT_NOT_REACHED();
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
|
|
||||||
//#define DEBUG_IO
|
//#define DEBUG_IO
|
||||||
//#define TASK_DEBUG
|
//#define TASK_DEBUG
|
||||||
|
//#define SCHEDULER_DEBUG
|
||||||
|
|
||||||
#define VALIDATE_USER_BUFFER(b, s) \
|
#define VALIDATE_USER_BUFFER(b, s) \
|
||||||
do { \
|
do { \
|
||||||
|
@ -605,12 +606,12 @@ bool scheduleNewTask()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
#ifdef SCHEDULER_DEBUG
|
||||||
kprintf("Scheduler choices:\n");
|
dbgprintf("Scheduler choices:\n");
|
||||||
for (auto* task = s_tasks->head(); task; task = task->next()) {
|
for (auto* task = s_tasks->head(); task; task = task->next()) {
|
||||||
if (task->state() == Task::BlockedWait || task->state() == Task::BlockedSleep)
|
//if (task->state() == Task::BlockedWait || task->state() == Task::BlockedSleep)
|
||||||
continue;
|
// continue;
|
||||||
kprintf("%w %s(%u)\n", task->state(), task->name().characters(), task->pid());
|
dbgprintf("%w %s(%u)\n", task->state(), task->name().characters(), task->pid());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -621,7 +622,9 @@ bool scheduleNewTask()
|
||||||
auto* task = s_tasks->head();
|
auto* task = s_tasks->head();
|
||||||
|
|
||||||
if (task->state() == Task::Runnable || task->state() == Task::Running) {
|
if (task->state() == Task::Runnable || task->state() == Task::Running) {
|
||||||
//kprintf("switch to %s (%p vs %p)\n", task->name().characters(), task, current);
|
#ifdef SCHEDULER_DEBUG
|
||||||
|
dbgprintf("switch to %s(%u) (%p vs %p)\n", task->name().characters(), task->pid(), task, current);
|
||||||
|
#endif
|
||||||
return contextSwitch(task);
|
return contextSwitch(task);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,7 +847,7 @@ int Task::sys$open(const char* path, int options)
|
||||||
if (m_fileHandles.size() >= m_maxFileHandles)
|
if (m_fileHandles.size() >= m_maxFileHandles)
|
||||||
return -EMFILE;
|
return -EMFILE;
|
||||||
int error;
|
int error;
|
||||||
auto handle = VirtualFileSystem::the().open(path, error, 0, cwdInode());
|
auto handle = VirtualFileSystem::the().open(path, error, options, cwdInode());
|
||||||
if (!handle)
|
if (!handle)
|
||||||
return error;
|
return error;
|
||||||
if (options & O_DIRECTORY && !handle->isDirectory())
|
if (options & O_DIRECTORY && !handle->isDirectory())
|
||||||
|
|
|
@ -247,3 +247,17 @@ void init()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void log_try_lock(const char* where)
|
||||||
|
{
|
||||||
|
kprintf("[%u] >>> locking... (%s)\n", current->pid(), where);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_locked(const char* where)
|
||||||
|
{
|
||||||
|
kprintf("[%u] >>> locked() in %s\n", current->pid(), where);
|
||||||
|
}
|
||||||
|
|
||||||
|
void log_unlocked(const char* where)
|
||||||
|
{
|
||||||
|
kprintf("[%u] <<< unlocked()\n", current->pid(), where);
|
||||||
|
}
|
||||||
|
|
|
@ -8,3 +8,4 @@
|
||||||
#define RELEASE_ASSERT(x) do { if (!(x)) CRASH(); } while(0)
|
#define RELEASE_ASSERT(x) do { if (!(x)) CRASH(); } while(0)
|
||||||
#define ASSERT_NOT_REACHED() ASSERT(false)
|
#define ASSERT_NOT_REACHED() ASSERT(false)
|
||||||
#define ASSERT_INTERRUPTS_DISABLED() ASSERT(!(cpuFlags() & 0x200))
|
#define ASSERT_INTERRUPTS_DISABLED() ASSERT(!(cpuFlags() & 0x200))
|
||||||
|
#define ASSERT_INTERRUPTS_ENABLED() ASSERT(cpuFlags() & 0x200)
|
||||||
|
|
|
@ -20,7 +20,7 @@ typedef struct
|
||||||
} PACKED allocation_t;
|
} PACKED allocation_t;
|
||||||
|
|
||||||
#define CHUNK_SIZE 128
|
#define CHUNK_SIZE 128
|
||||||
#define POOL_SIZE (512 * 1024)
|
#define POOL_SIZE (1024 * 1024)
|
||||||
|
|
||||||
#define BASE_PHYS 0x200000
|
#define BASE_PHYS 0x200000
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
#include "kprintf.h"
|
#include "kprintf.h"
|
||||||
#include "Console.h"
|
#include "Console.h"
|
||||||
|
#include "IO.h"
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <AK/Types.h>
|
#include <AK/Types.h>
|
||||||
#include <AK/printf.cpp>
|
#include <AK/printf.cpp>
|
||||||
|
|
||||||
static void console_putch(char*, char ch)
|
static void console_putch(char*&, char ch)
|
||||||
{
|
{
|
||||||
Console::the().write((byte*)&ch, 1);
|
Console::the().write((byte*)&ch, 1);
|
||||||
}
|
}
|
||||||
|
@ -32,3 +33,17 @@ int ksprintf(char* buffer, const char* fmt, ...)
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void debugger_putch(char*&, char ch)
|
||||||
|
{
|
||||||
|
IO::out8(0xe9, ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int dbgprintf(const char* fmt, ...)
|
||||||
|
{
|
||||||
|
va_list ap;
|
||||||
|
va_start(ap, fmt);
|
||||||
|
int ret = printfInternal(debugger_putch, nullptr, fmt, ap);
|
||||||
|
va_end(ap);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include <AK/Compiler.h>
|
#include <AK/Compiler.h>
|
||||||
|
|
||||||
|
int dbgprintf(const char *fmt, ...);
|
||||||
int kprintf(const char *fmt, ...);
|
int kprintf(const char *fmt, ...);
|
||||||
int ksprintf(char* buf, const char *fmt, ...);
|
int ksprintf(char* buf, const char *fmt, ...);
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ static void prompt()
|
||||||
if (getuid() == 0)
|
if (getuid() == 0)
|
||||||
printf("# ");
|
printf("# ");
|
||||||
else
|
else
|
||||||
printf("\033[32;1m%s\033[0m:\033[34;1m%s\033[0m$> ", g->hostname, g->cwd.characters());
|
printf("(%u) \033[32;1m%s\033[0m:\033[34;1m%s\033[0m$> ", getpid(), g->hostname, g->cwd.characters());
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sh_pwd(int, const char**)
|
static int sh_pwd(int, const char**)
|
||||||
|
@ -91,6 +91,21 @@ static bool handle_builtin(int argc, const char** argv, int& retval)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int try_spawn(const char* path, const char** argv)
|
||||||
|
{
|
||||||
|
int ret = spawn(path, argv);
|
||||||
|
if (ret >= 0)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
const char* search_path = "/bin";
|
||||||
|
char pathbuf[128];
|
||||||
|
sprintf(pathbuf, "%s/%s", search_path, argv[0]);
|
||||||
|
ret = spawn(pathbuf, argv);
|
||||||
|
if (ret == -1)
|
||||||
|
return -1;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int runcmd(char* cmd)
|
static int runcmd(char* cmd)
|
||||||
{
|
{
|
||||||
if (cmd[0] == 0)
|
if (cmd[0] == 0)
|
||||||
|
@ -115,15 +130,12 @@ static int runcmd(char* cmd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char* search_path = "/bin";
|
int ret = try_spawn(argv[0], argv);
|
||||||
|
if (ret < 0) {
|
||||||
char pathbuf[128];
|
|
||||||
sprintf(pathbuf, "%s/%s", search_path, argv[0]);
|
|
||||||
int ret = spawn(pathbuf, argv);
|
|
||||||
if (ret == -1) {
|
|
||||||
printf("spawn failed: %s (%s)\n", cmd, strerror(errno));
|
printf("spawn failed: %s (%s)\n", cmd, strerror(errno));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: waitpid should give us the spawned process's exit status
|
// FIXME: waitpid should give us the spawned process's exit status
|
||||||
int wstatus = 0;
|
int wstatus = 0;
|
||||||
waitpid(ret, &wstatus, 0);
|
waitpid(ret, &wstatus, 0);
|
||||||
|
|
|
@ -7,6 +7,7 @@ typedef int InterruptDisabler;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//#define DBFS_DEBUG
|
//#define DBFS_DEBUG
|
||||||
|
#define BLOCK_CACHE
|
||||||
|
|
||||||
DiskBackedFileSystem::DiskBackedFileSystem(RetainPtr<DiskDevice>&& device)
|
DiskBackedFileSystem::DiskBackedFileSystem(RetainPtr<DiskDevice>&& device)
|
||||||
: m_device(move(device))
|
: m_device(move(device))
|
||||||
|
@ -42,6 +43,8 @@ ByteBuffer DiskBackedFileSystem::readBlock(unsigned index) const
|
||||||
#ifdef DBFS_DEBUG
|
#ifdef DBFS_DEBUG
|
||||||
kprintf("DiskBackedFileSystem::readBlock %u\n", index);
|
kprintf("DiskBackedFileSystem::readBlock %u\n", index);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef BLOCK_CACHE
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
auto it = m_blockCache.find(index);
|
auto it = m_blockCache.find(index);
|
||||||
|
@ -49,19 +52,24 @@ ByteBuffer DiskBackedFileSystem::readBlock(unsigned index) const
|
||||||
return (*it).value;
|
return (*it).value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
auto buffer = ByteBuffer::createUninitialized(blockSize());
|
auto buffer = ByteBuffer::createUninitialized(blockSize());
|
||||||
|
//kprintf("created block buffer with size %u\n", blockSize());
|
||||||
DiskOffset baseOffset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(blockSize());
|
DiskOffset baseOffset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(blockSize());
|
||||||
auto* bufferPointer = buffer.pointer();
|
auto* bufferPointer = buffer.pointer();
|
||||||
device().read(baseOffset, blockSize(), bufferPointer);
|
bool success = device().read(baseOffset, blockSize(), bufferPointer);
|
||||||
|
ASSERT(success);
|
||||||
ASSERT(buffer.size() == blockSize());
|
ASSERT(buffer.size() == blockSize());
|
||||||
|
|
||||||
|
#ifdef BLOCK_CACHE
|
||||||
{
|
{
|
||||||
InterruptDisabler disabler;
|
InterruptDisabler disabler;
|
||||||
if (m_blockCache.size() >= 32)
|
if (m_blockCache.size() >= 32)
|
||||||
m_blockCache.removeOneRandomly();
|
m_blockCache.removeOneRandomly();
|
||||||
m_blockCache.set(index, buffer);
|
m_blockCache.set(index, buffer);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ DiskDevice::~DiskDevice()
|
||||||
|
|
||||||
bool DiskDevice::read(DiskOffset offset, unsigned length, byte* out) const
|
bool DiskDevice::read(DiskOffset offset, unsigned length, byte* out) const
|
||||||
{
|
{
|
||||||
|
//kprintf("DD::read %u x%u\n", offset, length);
|
||||||
ASSERT((offset % blockSize()) == 0);
|
ASSERT((offset % blockSize()) == 0);
|
||||||
ASSERT((length % blockSize()) == 0);
|
ASSERT((length % blockSize()) == 0);
|
||||||
dword firstBlock = offset / blockSize();
|
dword firstBlock = offset / blockSize();
|
||||||
|
|
|
@ -293,7 +293,6 @@ Unix::ssize_t Ext2FileSystem::readInodeBytes(InodeIdentifier inode, Unix::off_t
|
||||||
static const unsigned maxInlineSymlinkLength = 60;
|
static const unsigned maxInlineSymlinkLength = 60;
|
||||||
if (isSymbolicLink(e2inode->i_mode) && e2inode->i_size < maxInlineSymlinkLength) {
|
if (isSymbolicLink(e2inode->i_mode) && e2inode->i_size < maxInlineSymlinkLength) {
|
||||||
Unix::ssize_t nread = min((Unix::off_t)e2inode->i_size - offset, static_cast<Unix::off_t>(count));
|
Unix::ssize_t nread = min((Unix::off_t)e2inode->i_size - offset, static_cast<Unix::off_t>(count));
|
||||||
kprintf("nread = %d\n", nread);
|
|
||||||
memcpy(buffer, e2inode->i_block + offset, nread);
|
memcpy(buffer, e2inode->i_block + offset, nread);
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ bool additionWouldOverflow(Unix::off_t a, Unix::off_t b)
|
||||||
|
|
||||||
int FileHandle::stat(Unix::stat* buffer)
|
int FileHandle::stat(Unix::stat* buffer)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
if (!m_vnode)
|
if (!m_vnode)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
@ -52,7 +52,7 @@ int FileHandle::stat(Unix::stat* buffer)
|
||||||
|
|
||||||
Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
|
Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
if (!m_vnode)
|
if (!m_vnode)
|
||||||
return -EBADF;
|
return -EBADF;
|
||||||
|
@ -96,7 +96,7 @@ Unix::off_t FileHandle::seek(Unix::off_t offset, int whence)
|
||||||
|
|
||||||
Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count)
|
Unix::ssize_t FileHandle::read(byte* buffer, Unix::size_t count)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
if (m_vnode->isCharacterDevice()) {
|
if (m_vnode->isCharacterDevice()) {
|
||||||
// FIXME: What should happen to m_currentOffset?
|
// FIXME: What should happen to m_currentOffset?
|
||||||
|
@ -116,7 +116,7 @@ bool FileHandle::hasDataAvailableForRead()
|
||||||
|
|
||||||
ByteBuffer FileHandle::readEntireFile()
|
ByteBuffer FileHandle::readEntireFile()
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
if (m_vnode->isCharacterDevice()) {
|
if (m_vnode->isCharacterDevice()) {
|
||||||
auto buffer = ByteBuffer::createUninitialized(1024);
|
auto buffer = ByteBuffer::createUninitialized(1024);
|
||||||
|
@ -135,7 +135,7 @@ bool FileHandle::isDirectory() const
|
||||||
|
|
||||||
ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size)
|
ssize_t FileHandle::get_dir_entries(byte* buffer, Unix::size_t size)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
auto metadata = m_vnode->metadata();
|
auto metadata = m_vnode->metadata();
|
||||||
if (!metadata.isValid())
|
if (!metadata.isValid())
|
||||||
|
|
|
@ -78,11 +78,13 @@ ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle
|
||||||
auto contents = ByteBuffer::createUninitialized(initialSize);
|
auto contents = ByteBuffer::createUninitialized(initialSize);
|
||||||
|
|
||||||
Unix::ssize_t nread;
|
Unix::ssize_t nread;
|
||||||
byte buffer[512];
|
byte buffer[4096];
|
||||||
byte* out = contents.pointer();
|
byte* out = contents.pointer();
|
||||||
Unix::off_t offset = 0;
|
Unix::off_t offset = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
nread = readInodeBytes(inode, offset, sizeof(buffer), buffer, handle);
|
nread = readInodeBytes(inode, offset, sizeof(buffer), buffer, handle);
|
||||||
|
//kprintf("nread: %u, bufsiz: %u, initialSize: %u\n", nread, sizeof(buffer), initialSize);
|
||||||
|
ASSERT(nread <= sizeof(buffer));
|
||||||
if (nread <= 0)
|
if (nread <= 0)
|
||||||
break;
|
break;
|
||||||
memcpy(out, buffer, nread);
|
memcpy(out, buffer, nread);
|
||||||
|
@ -95,6 +97,7 @@ ByteBuffer FileSystem::readEntireInode(InodeIdentifier inode, FileHandle* handle
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
contents.trim(offset);
|
||||||
return contents;
|
return contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@ AK_OBJS = \
|
||||||
../AK/MappedFile.o \
|
../AK/MappedFile.o \
|
||||||
../AK/TemporaryFile.o \
|
../AK/TemporaryFile.o \
|
||||||
../AK/SimpleMalloc.o \
|
../AK/SimpleMalloc.o \
|
||||||
|
../AK/StringBuilder.o \
|
||||||
../AK/kmalloc.o
|
../AK/kmalloc.o
|
||||||
|
|
||||||
VFS_OBJS = \
|
VFS_OBJS = \
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
#include "FileHandle.h"
|
#include "FileHandle.h"
|
||||||
#include <AK/StdLib.h>
|
#include <AK/StdLib.h>
|
||||||
|
|
||||||
|
#ifndef SERENITY
|
||||||
|
typedef int InterruptDisabler;
|
||||||
|
#define ASSERT_INTERRUPTS_DISABLED()
|
||||||
|
#endif
|
||||||
|
|
||||||
//#define SYNTHFS_DEBUG
|
//#define SYNTHFS_DEBUG
|
||||||
|
|
||||||
RetainPtr<SyntheticFileSystem> SyntheticFileSystem::create()
|
RetainPtr<SyntheticFileSystem> SyntheticFileSystem::create()
|
||||||
|
@ -31,11 +36,10 @@ bool SyntheticFileSystem::initialize()
|
||||||
rootDir->metadata.mtime = mepoch;
|
rootDir->metadata.mtime = mepoch;
|
||||||
m_inodes.set(RootInodeIndex, move(rootDir));
|
m_inodes.set(RootInodeIndex, move(rootDir));
|
||||||
|
|
||||||
#if 0
|
|
||||||
#ifndef SERENITY
|
#ifndef SERENITY
|
||||||
addFile(createTextFile("file", "I'm a synthetic file!\n"));
|
addFile(createTextFile("file", "I'm a synthetic file!\n"));
|
||||||
addFile(createTextFile("message", "Hey! This isn't my bottle!\n"));
|
addFile(createTextFile("message", "Hey! This isn't my bottle!\n"));
|
||||||
#endif
|
addFile(createGeneratedFile("lunk", [] { return String("/home/andreas/file1").toByteBuffer(); }, 00120777));
|
||||||
#endif
|
#endif
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +64,7 @@ auto SyntheticFileSystem::createTextFile(String&& name, String&& text) -> OwnPtr
|
||||||
file->metadata.size = file->data.size();
|
file->metadata.size = file->data.size();
|
||||||
file->metadata.uid = 100;
|
file->metadata.uid = 100;
|
||||||
file->metadata.gid = 200;
|
file->metadata.gid = 200;
|
||||||
file->metadata.mode = 0040644;
|
file->metadata.mode = 0010644;
|
||||||
file->metadata.mtime = mepoch;
|
file->metadata.mtime = mepoch;
|
||||||
return file;
|
return file;
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,10 +103,11 @@ auto VirtualFileSystem::getOrCreateNode(InodeIdentifier inode) -> RetainPtr<Node
|
||||||
|
|
||||||
bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path)
|
bool VirtualFileSystem::mount(RetainPtr<FileSystem>&& fileSystem, const String& path)
|
||||||
{
|
{
|
||||||
|
kprintf("mount\n");
|
||||||
|
LOCKER(VirtualFileSystem::lock());
|
||||||
ASSERT(fileSystem);
|
ASSERT(fileSystem);
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
auto inode = resolvePath(path, error);
|
auto inode = resolvePath(path, error, locker);
|
||||||
if (!inode.isValid()) {
|
if (!inode.isValid()) {
|
||||||
kprintf("[VFS] mount can't resolve mount point '%s'\n", path.characters());
|
kprintf("[VFS] mount can't resolve mount point '%s'\n", path.characters());
|
||||||
return false;
|
return false;
|
||||||
|
@ -150,6 +151,7 @@ bool VirtualFileSystem::mountRoot(RetainPtr<FileSystem>&& fileSystem)
|
||||||
|
|
||||||
auto VirtualFileSystem::allocateNode() -> RetainPtr<Node>
|
auto VirtualFileSystem::allocateNode() -> RetainPtr<Node>
|
||||||
{
|
{
|
||||||
|
|
||||||
if (m_nodeFreeList.isEmpty()) {
|
if (m_nodeFreeList.isEmpty()) {
|
||||||
kprintf("[VFS] allocateNode has no nodes left\n");
|
kprintf("[VFS] allocateNode has no nodes left\n");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -172,6 +174,7 @@ void VirtualFileSystem::freeNode(Node* node)
|
||||||
m_nodeFreeList.append(move(node));
|
m_nodeFreeList.append(move(node));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SERENITY
|
||||||
bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base)
|
bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -181,6 +184,7 @@ bool VirtualFileSystem::isDirectory(const String& path, InodeIdentifier base)
|
||||||
|
|
||||||
return inode.metadata().isDirectory();
|
return inode.metadata().isDirectory();
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
auto VirtualFileSystem::findMountForHost(InodeIdentifier inode) -> Mount*
|
auto VirtualFileSystem::findMountForHost(InodeIdentifier inode) -> Mount*
|
||||||
{
|
{
|
||||||
|
@ -227,6 +231,7 @@ void VirtualFileSystem::enumerateDirectoryInode(InodeIdentifier directoryInode,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifndef SERENITY
|
||||||
void VirtualFileSystem::listDirectory(const String& path)
|
void VirtualFileSystem::listDirectory(const String& path)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
|
@ -351,13 +356,14 @@ void VirtualFileSystem::listDirectoryRecursively(const String& path)
|
||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
bool VirtualFileSystem::touch(const String& path)
|
bool VirtualFileSystem::touch(const String& path)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
int error;
|
int error;
|
||||||
auto inode = resolvePath(path, error);
|
auto inode = resolvePath(path, error, locker);
|
||||||
if (!inode.isValid())
|
if (!inode.isValid())
|
||||||
return false;
|
return false;
|
||||||
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
|
return inode.fileSystem()->setModificationTime(inode, ktime(nullptr));
|
||||||
|
@ -365,9 +371,9 @@ bool VirtualFileSystem::touch(const String& path)
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
auto inode = resolvePath(path, error, base, options);
|
auto inode = resolvePath(path, error, locker, base, options);
|
||||||
if (!inode.isValid())
|
if (!inode.isValid())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
auto vnode = getOrCreateNode(inode);
|
auto vnode = getOrCreateNode(inode);
|
||||||
|
@ -378,7 +384,7 @@ OwnPtr<FileHandle> VirtualFileSystem::open(const String& path, int& error, int o
|
||||||
|
|
||||||
OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, InodeIdentifier base)
|
OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, InodeIdentifier base)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
// FIXME: Do the real thing, not just this fake thing!
|
// FIXME: Do the real thing, not just this fake thing!
|
||||||
(void) path;
|
(void) path;
|
||||||
|
@ -388,26 +394,29 @@ OwnPtr<FileHandle> VirtualFileSystem::create(const String& path, InodeIdentifier
|
||||||
|
|
||||||
OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, InodeIdentifier base)
|
OwnPtr<FileHandle> VirtualFileSystem::mkdir(const String& path, InodeIdentifier base)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
|
||||||
// FIXME: Do the real thing, not just this fake thing!
|
// FIXME: Do the real thing, not just this fake thing!
|
||||||
(void) path;
|
(void) path;
|
||||||
m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755);
|
m_rootNode->fileSystem()->makeDirectory(m_rootNode->fileSystem()->rootInode(), "mydir", 0400755);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
InodeIdentifier VirtualFileSystem::resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error)
|
InodeIdentifier VirtualFileSystem::resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error, Locker& locker)
|
||||||
{
|
{
|
||||||
|
locker.unlock();
|
||||||
auto symlinkContents = symlinkInode.readEntireFile();
|
auto symlinkContents = symlinkInode.readEntireFile();
|
||||||
|
locker.lock();
|
||||||
if (!symlinkContents)
|
if (!symlinkContents)
|
||||||
return { };
|
return { };
|
||||||
return resolvePath((const char*)symlinkContents.pointer(), error, base);
|
auto linkee = String((const char*)symlinkContents.pointer(), symlinkContents.size());
|
||||||
|
#ifdef VFS_DEBUG
|
||||||
|
kprintf("linkee (%s)(%u) from %u:%u\n", linkee.characters(), linkee.length(), base.fileSystemID(), base.index());
|
||||||
|
#endif
|
||||||
|
return resolvePath(linkee, error, locker, base);
|
||||||
}
|
}
|
||||||
|
|
||||||
String VirtualFileSystem::absolutePath(InodeIdentifier inode)
|
String VirtualFileSystem::absolutePathInternal(InodeIdentifier inode, Locker& locker)
|
||||||
{
|
{
|
||||||
Locker locker(VirtualFileSystem::lock());
|
|
||||||
|
|
||||||
if (!inode.isValid())
|
if (!inode.isValid())
|
||||||
return String();
|
return String();
|
||||||
|
|
||||||
|
@ -419,7 +428,7 @@ String VirtualFileSystem::absolutePath(InodeIdentifier inode)
|
||||||
else
|
else
|
||||||
lineage.append(inode);
|
lineage.append(inode);
|
||||||
if (inode.metadata().isDirectory()) {
|
if (inode.metadata().isDirectory()) {
|
||||||
inode = resolvePath("..", error, inode);
|
inode = resolvePath("..", error, locker, inode);
|
||||||
} else
|
} else
|
||||||
inode = inode.fileSystem()->findParentOfInode(inode);
|
inode = inode.fileSystem()->findParentOfInode(inode);
|
||||||
ASSERT(inode.isValid());
|
ASSERT(inode.isValid());
|
||||||
|
@ -439,7 +448,13 @@ String VirtualFileSystem::absolutePath(InodeIdentifier inode)
|
||||||
return builder.build();
|
return builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, InodeIdentifier base, int options)
|
String VirtualFileSystem::absolutePath(InodeIdentifier inode)
|
||||||
|
{
|
||||||
|
LOCKER(VirtualFileSystem::lock());
|
||||||
|
return absolutePathInternal(inode, locker);
|
||||||
|
}
|
||||||
|
|
||||||
|
InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, Locker& locker, InodeIdentifier base, int options)
|
||||||
{
|
{
|
||||||
if (path.isEmpty())
|
if (path.isEmpty())
|
||||||
return { };
|
return { };
|
||||||
|
@ -465,7 +480,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, I
|
||||||
}
|
}
|
||||||
if (!metadata.isDirectory()) {
|
if (!metadata.isDirectory()) {
|
||||||
#ifdef VFS_DEBUG
|
#ifdef VFS_DEBUG
|
||||||
kprintf("not directory\n");
|
kprintf("parent of <%s> not directory, it's inode %u:%u / %u:%u, mode: %u, size: %u\n", part.characters(), inode.fileSystemID(), inode.index(), metadata.inode.fileSystemID(), metadata.inode.index(), metadata.mode, metadata.size);
|
||||||
#endif
|
#endif
|
||||||
error = -EIO;
|
error = -EIO;
|
||||||
return { };
|
return { };
|
||||||
|
@ -474,7 +489,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, I
|
||||||
inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, part);
|
inode = inode.fileSystem()->childOfDirectoryInodeWithName(inode, part);
|
||||||
if (!inode.isValid()) {
|
if (!inode.isValid()) {
|
||||||
#ifdef VFS_DEBUG
|
#ifdef VFS_DEBUG
|
||||||
kprintf("bad child\n");
|
kprintf("child <%s>(%u) not found in directory, %02u:%08u\n", part.characters(), part.length(), parent.fileSystemID(), parent.index());
|
||||||
#endif
|
#endif
|
||||||
error = -ENOENT;
|
error = -ENOENT;
|
||||||
return { };
|
return { };
|
||||||
|
@ -506,12 +521,7 @@ InodeIdentifier VirtualFileSystem::resolvePath(const String& path, int& error, I
|
||||||
if (options & O_NOFOLLOW_NOERROR)
|
if (options & O_NOFOLLOW_NOERROR)
|
||||||
return inode;
|
return inode;
|
||||||
}
|
}
|
||||||
char buf[4096] = "";
|
inode = resolveSymbolicLink(parent, inode, error, locker);
|
||||||
char* p = buf;
|
|
||||||
for (unsigned j = 0; j < i; ++j) {
|
|
||||||
p += ksprintf(p, "/%s", parts[j].characters());
|
|
||||||
}
|
|
||||||
inode = resolveSymbolicLink(parent, inode, error);
|
|
||||||
if (!inode.isValid()) {
|
if (!inode.isValid()) {
|
||||||
kprintf("Symbolic link resolution failed :(\n");
|
kprintf("Symbolic link resolution failed :(\n");
|
||||||
return { };
|
return { };
|
||||||
|
|
|
@ -104,9 +104,11 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class FileHandle;
|
friend class FileHandle;
|
||||||
|
|
||||||
|
String absolutePathInternal(InodeIdentifier, Locker&);
|
||||||
|
|
||||||
void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
|
void enumerateDirectoryInode(InodeIdentifier, Function<bool(const FileSystem::DirectoryEntry&)>);
|
||||||
InodeIdentifier resolvePath(const String& path, int& error, InodeIdentifier base = InodeIdentifier(), int options = 0);
|
InodeIdentifier resolvePath(const String& path, int& error, Locker&, InodeIdentifier base = InodeIdentifier(), int options = 0);
|
||||||
InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error);
|
InodeIdentifier resolveSymbolicLink(InodeIdentifier base, InodeIdentifier symlinkInode, int& error, Locker&);
|
||||||
|
|
||||||
RetainPtr<Node> allocateNode();
|
RetainPtr<Node> allocateNode();
|
||||||
void freeNode(Node*);
|
void freeNode(Node*);
|
||||||
|
|
|
@ -53,7 +53,8 @@ int main(int c, char** v)
|
||||||
//return 0;
|
//return 0;
|
||||||
|
|
||||||
if (!strcmp(v[0], "./vcat")) {
|
if (!strcmp(v[0], "./vcat")) {
|
||||||
auto handle = vfs.open(v[2]);
|
int error;
|
||||||
|
auto handle = vfs.open(v[2], error);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("failed to open %s inside fs image\n", v[2]);
|
printf("failed to open %s inside fs image\n", v[2]);
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -149,7 +150,8 @@ int main(int c, char** v)
|
||||||
if (cmd == "stat" && parts.size() > 1) {
|
if (cmd == "stat" && parts.size() > 1) {
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
sprintf(buf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
sprintf(buf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
||||||
auto handle = vfs.open(buf);
|
int error;
|
||||||
|
auto handle = vfs.open(buf, error);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("Can't open '%s' :(\n", buf);
|
printf("Can't open '%s' :(\n", buf);
|
||||||
continue;
|
continue;
|
||||||
|
@ -179,7 +181,8 @@ int main(int c, char** v)
|
||||||
if (cmd == "cat" && parts.size() > 1) {
|
if (cmd == "cat" && parts.size() > 1) {
|
||||||
char pathbuf[1024];
|
char pathbuf[1024];
|
||||||
sprintf(pathbuf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
sprintf(pathbuf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
||||||
auto handle = vfs.open(pathbuf);
|
int error;
|
||||||
|
auto handle = vfs.open(pathbuf, error);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("failed to open %s\n", pathbuf);
|
printf("failed to open %s\n", pathbuf);
|
||||||
continue;
|
continue;
|
||||||
|
@ -192,7 +195,8 @@ int main(int c, char** v)
|
||||||
if (cmd == "kat" && parts.size() > 1) {
|
if (cmd == "kat" && parts.size() > 1) {
|
||||||
char pathbuf[1024];
|
char pathbuf[1024];
|
||||||
sprintf(pathbuf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
sprintf(pathbuf, "%s/%s", currentDirectory.characters(), parts[1].characters());
|
||||||
auto handle = vfs.open(pathbuf);
|
int error;
|
||||||
|
auto handle = vfs.open(pathbuf, error);
|
||||||
if (!handle) {
|
if (!handle) {
|
||||||
printf("failed to open %s\n", pathbuf);
|
printf("failed to open %s\n", pathbuf);
|
||||||
continue;
|
continue;
|
||||||
|
|
Loading…
Reference in a new issue