mirror of
https://github.com/RGBCube/serenity
synced 2025-07-27 13:57:35 +00:00
Move VFS sources into Kernel/.
This commit is contained in:
parent
19104570cc
commit
754037874c
49 changed files with 35 additions and 37 deletions
16
Kernel/CharacterDevice.cpp
Normal file
16
Kernel/CharacterDevice.cpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#include "CharacterDevice.h"
|
||||
#include <LibC/errno_numbers.h>
|
||||
|
||||
CharacterDevice::~CharacterDevice()
|
||||
{
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> CharacterDevice::open(int& error, int options)
|
||||
{
|
||||
return VFS::the().open(*this, error, options);
|
||||
}
|
||||
|
||||
int CharacterDevice::ioctl(Process&, unsigned, unsigned)
|
||||
{
|
||||
return -ENOTTY;
|
||||
}
|
40
Kernel/CharacterDevice.h
Normal file
40
Kernel/CharacterDevice.h
Normal file
|
@ -0,0 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Retainable.h>
|
||||
#include <AK/Types.h>
|
||||
#include "Limits.h"
|
||||
#include "FileDescriptor.h"
|
||||
|
||||
class Process;
|
||||
|
||||
class CharacterDevice : public Retainable<CharacterDevice> {
|
||||
public:
|
||||
virtual ~CharacterDevice();
|
||||
|
||||
InodeMetadata metadata() const { return { }; }
|
||||
|
||||
virtual RetainPtr<FileDescriptor> open(int& error, int options);
|
||||
|
||||
virtual bool can_read(Process&) const = 0;
|
||||
virtual bool can_write(Process&) const = 0;
|
||||
|
||||
virtual ssize_t read(Process&, byte* buffer, size_t bufferSize) = 0;
|
||||
virtual ssize_t write(Process&, const byte* buffer, size_t bufferSize) = 0;
|
||||
|
||||
unsigned major() const { return m_major; }
|
||||
unsigned minor() const { return m_minor; }
|
||||
|
||||
virtual bool is_tty() const { return false; }
|
||||
virtual bool is_master_pty() const { return false; }
|
||||
|
||||
virtual int ioctl(Process&, unsigned request, unsigned arg);
|
||||
|
||||
virtual const char* class_name() const = 0;
|
||||
|
||||
protected:
|
||||
CharacterDevice(unsigned major, unsigned minor) : m_major(major), m_minor(minor) { }
|
||||
|
||||
private:
|
||||
unsigned m_major { 0 };
|
||||
unsigned m_minor { 0 };
|
||||
};
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <AK/Compiler.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
|
||||
class ConsoleImplementation {
|
||||
public:
|
||||
|
|
75
Kernel/DiskBackedFileSystem.cpp
Normal file
75
Kernel/DiskBackedFileSystem.cpp
Normal file
|
@ -0,0 +1,75 @@
|
|||
#include "DiskBackedFileSystem.h"
|
||||
#include "i386.h"
|
||||
|
||||
//#define DBFS_DEBUG
|
||||
|
||||
DiskBackedFS::DiskBackedFS(RetainPtr<DiskDevice>&& device)
|
||||
: m_device(move(device))
|
||||
{
|
||||
ASSERT(m_device);
|
||||
}
|
||||
|
||||
DiskBackedFS::~DiskBackedFS()
|
||||
{
|
||||
}
|
||||
|
||||
bool DiskBackedFS::writeBlock(unsigned index, const ByteBuffer& data)
|
||||
{
|
||||
#ifdef DBFS_DEBUG
|
||||
kprintf("DiskBackedFileSystem::writeBlock %u, size=%u\n", index, data.size());
|
||||
#endif
|
||||
ASSERT(data.size() == blockSize());
|
||||
DiskOffset baseOffset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(blockSize());
|
||||
return device().write(baseOffset, blockSize(), data.pointer());
|
||||
}
|
||||
|
||||
bool DiskBackedFS::writeBlocks(unsigned index, unsigned count, const ByteBuffer& data)
|
||||
{
|
||||
#ifdef DBFS_DEBUG
|
||||
kprintf("DiskBackedFileSystem::writeBlocks %u x%u\n", index, count);
|
||||
#endif
|
||||
DiskOffset baseOffset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(blockSize());
|
||||
return device().write(baseOffset, count * blockSize(), data.pointer());
|
||||
}
|
||||
|
||||
ByteBuffer DiskBackedFS::readBlock(unsigned index) const
|
||||
{
|
||||
#ifdef DBFS_DEBUG
|
||||
kprintf("DiskBackedFileSystem::readBlock %u\n", index);
|
||||
#endif
|
||||
auto buffer = ByteBuffer::create_uninitialized(blockSize());
|
||||
//kprintf("created block buffer with size %u\n", blockSize());
|
||||
DiskOffset baseOffset = static_cast<DiskOffset>(index) * static_cast<DiskOffset>(blockSize());
|
||||
auto* bufferPointer = buffer.pointer();
|
||||
bool success = device().read(baseOffset, blockSize(), bufferPointer);
|
||||
ASSERT(success);
|
||||
ASSERT(buffer.size() == blockSize());
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ByteBuffer DiskBackedFS::readBlocks(unsigned index, unsigned count) const
|
||||
{
|
||||
if (!count)
|
||||
return nullptr;
|
||||
if (count == 1)
|
||||
return readBlock(index);
|
||||
auto blocks = ByteBuffer::create_uninitialized(count * blockSize());
|
||||
byte* out = blocks.pointer();
|
||||
|
||||
for (unsigned i = 0; i < count; ++i) {
|
||||
auto block = readBlock(index + i);
|
||||
if (!block)
|
||||
return nullptr;
|
||||
memcpy(out, block.pointer(), block.size());
|
||||
out += blockSize();
|
||||
}
|
||||
|
||||
return blocks;
|
||||
}
|
||||
|
||||
void DiskBackedFS::setBlockSize(unsigned blockSize)
|
||||
{
|
||||
if (blockSize == m_blockSize)
|
||||
return;
|
||||
m_blockSize = blockSize;
|
||||
}
|
29
Kernel/DiskBackedFileSystem.h
Normal file
29
Kernel/DiskBackedFileSystem.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
#pragma once
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include <AK/ByteBuffer.h>
|
||||
|
||||
class DiskBackedFS : public FS {
|
||||
public:
|
||||
virtual ~DiskBackedFS() override;
|
||||
|
||||
DiskDevice& device() { return *m_device; }
|
||||
const DiskDevice& device() const { return *m_device; }
|
||||
|
||||
size_t blockSize() const { return m_blockSize; }
|
||||
|
||||
protected:
|
||||
explicit DiskBackedFS(RetainPtr<DiskDevice>&&);
|
||||
|
||||
void setBlockSize(unsigned);
|
||||
|
||||
ByteBuffer readBlock(unsigned index) const;
|
||||
ByteBuffer readBlocks(unsigned index, unsigned count) const;
|
||||
|
||||
bool writeBlock(unsigned index, const ByteBuffer&);
|
||||
bool writeBlocks(unsigned index, unsigned count, const ByteBuffer&);
|
||||
|
||||
private:
|
||||
size_t m_blockSize { 0 };
|
||||
RetainPtr<DiskDevice> m_device;
|
||||
};
|
43
Kernel/DiskDevice.cpp
Normal file
43
Kernel/DiskDevice.cpp
Normal file
|
@ -0,0 +1,43 @@
|
|||
#include "DiskDevice.h"
|
||||
|
||||
DiskDevice::DiskDevice()
|
||||
{
|
||||
}
|
||||
|
||||
DiskDevice::~DiskDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool DiskDevice::read(DiskOffset offset, unsigned length, byte* out) const
|
||||
{
|
||||
//kprintf("DD::read %u x%u\n", offset, length);
|
||||
ASSERT((offset % block_size()) == 0);
|
||||
ASSERT((length % block_size()) == 0);
|
||||
dword firstBlock = offset / block_size();
|
||||
dword endBlock = (offset + length) / block_size();
|
||||
byte* outptr = out;
|
||||
for (unsigned bi = firstBlock; bi < endBlock; ++bi) {
|
||||
if (!read_block(bi, outptr))
|
||||
return false;
|
||||
outptr += block_size();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DiskDevice::write(DiskOffset offset, unsigned length, const byte* in)
|
||||
{
|
||||
ASSERT((offset % block_size()) == 0);
|
||||
ASSERT((length % block_size()) == 0);
|
||||
dword firstBlock = offset / block_size();
|
||||
dword endBlock = (offset + length) / block_size();
|
||||
ASSERT(firstBlock <= 0xffffffff);
|
||||
ASSERT(endBlock <= 0xffffffff);
|
||||
const byte* inptr = in;
|
||||
for (unsigned bi = firstBlock; bi < endBlock; ++bi) {
|
||||
if (!write_block(bi, inptr))
|
||||
return false;
|
||||
inptr += block_size();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
23
Kernel/DiskDevice.h
Normal file
23
Kernel/DiskDevice.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Retainable.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
// FIXME: Support 64-bit DiskOffset
|
||||
typedef dword DiskOffset;
|
||||
|
||||
class DiskDevice : public Retainable<DiskDevice> {
|
||||
public:
|
||||
virtual ~DiskDevice();
|
||||
|
||||
virtual unsigned block_size() const = 0;
|
||||
virtual bool read_block(unsigned index, byte*) const = 0;
|
||||
virtual bool write_block(unsigned index, const byte*) = 0;
|
||||
virtual const char* class_name() const = 0;
|
||||
bool read(DiskOffset, unsigned length, byte*) const;
|
||||
bool write(DiskOffset, unsigned length, const byte*);
|
||||
|
||||
protected:
|
||||
DiskDevice();
|
||||
};
|
||||
|
1272
Kernel/Ext2FileSystem.cpp
Normal file
1272
Kernel/Ext2FileSystem.cpp
Normal file
File diff suppressed because it is too large
Load diff
140
Kernel/Ext2FileSystem.h
Normal file
140
Kernel/Ext2FileSystem.h
Normal file
|
@ -0,0 +1,140 @@
|
|||
#pragma once
|
||||
|
||||
#include "DiskBackedFileSystem.h"
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/Buffer.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Lock.h>
|
||||
#include "ext2_fs.h"
|
||||
|
||||
struct ext2_group_desc;
|
||||
struct ext2_inode;
|
||||
struct ext2_super_block;
|
||||
|
||||
class Ext2FS;
|
||||
|
||||
class Ext2FSInode final : public Inode {
|
||||
friend class Ext2FS;
|
||||
public:
|
||||
virtual ~Ext2FSInode() override;
|
||||
|
||||
size_t size() const { return m_raw_inode.i_size; }
|
||||
bool is_symlink() const { return isSymbolicLink(m_raw_inode.i_mode); }
|
||||
|
||||
// ^Inode (Retainable magic)
|
||||
virtual void one_retain_left() override;
|
||||
|
||||
private:
|
||||
// ^Inode
|
||||
virtual ssize_t read_bytes(Unix::off_t, size_t, byte* buffer, FileDescriptor*) override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) override;
|
||||
virtual InodeIdentifier lookup(const String& name) override;
|
||||
virtual String reverse_lookup(InodeIdentifier) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(Unix::off_t, size_t, const byte* data, FileDescriptor*) override;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override;
|
||||
virtual bool remove_child(const String& name, int& error) override;
|
||||
virtual RetainPtr<Inode> parent() const override;
|
||||
virtual int set_atime(Unix::time_t) override;
|
||||
virtual int set_ctime(Unix::time_t) override;
|
||||
virtual int set_mtime(Unix::time_t) override;
|
||||
virtual int increment_link_count() override;
|
||||
virtual int decrement_link_count() override;
|
||||
|
||||
void populate_lookup_cache();
|
||||
|
||||
Ext2FS& fs();
|
||||
const Ext2FS& fs() const;
|
||||
Ext2FSInode(Ext2FS&, unsigned index, const ext2_inode&);
|
||||
|
||||
Lock m_lock;
|
||||
Vector<unsigned> m_block_list;
|
||||
HashMap<String, unsigned> m_lookup_cache;
|
||||
ext2_inode m_raw_inode;
|
||||
mutable InodeIdentifier m_parent_id;
|
||||
};
|
||||
|
||||
class Ext2FS final : public DiskBackedFS {
|
||||
friend class Ext2FSInode;
|
||||
public:
|
||||
static RetainPtr<Ext2FS> create(RetainPtr<DiskDevice>&&);
|
||||
virtual ~Ext2FS() override;
|
||||
virtual bool initialize() override;
|
||||
|
||||
private:
|
||||
typedef unsigned BlockIndex;
|
||||
typedef unsigned GroupIndex;
|
||||
typedef unsigned InodeIndex;
|
||||
explicit Ext2FS(RetainPtr<DiskDevice>&&);
|
||||
|
||||
const ext2_super_block& super_block() const;
|
||||
const ext2_group_desc& group_descriptor(unsigned groupIndex) const;
|
||||
unsigned first_block_of_group(unsigned groupIndex) const;
|
||||
unsigned inodes_per_block() const;
|
||||
unsigned inodes_per_group() const;
|
||||
unsigned blocks_per_group() const;
|
||||
unsigned inode_size() const;
|
||||
|
||||
bool write_ext2_inode(unsigned, const ext2_inode&);
|
||||
ByteBuffer read_block_containing_inode(unsigned inode, unsigned& blockIndex, unsigned& offset) const;
|
||||
|
||||
ByteBuffer read_super_block() const;
|
||||
bool write_super_block(const ext2_super_block&);
|
||||
|
||||
virtual const char* class_name() const override;
|
||||
virtual InodeIdentifier root_inode() const override;
|
||||
virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override;
|
||||
virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override;
|
||||
virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override;
|
||||
|
||||
unsigned allocate_inode(unsigned preferredGroup, unsigned expectedSize);
|
||||
Vector<BlockIndex> allocate_blocks(unsigned group, unsigned count);
|
||||
unsigned group_index_from_inode(unsigned) const;
|
||||
|
||||
Vector<unsigned> block_list_for_inode(const ext2_inode&, bool include_block_list_blocks = false) const;
|
||||
bool write_block_list_for_inode(InodeIndex, ext2_inode&, const Vector<BlockIndex>&);
|
||||
|
||||
void dump_block_bitmap(unsigned groupIndex) const;
|
||||
void dump_inode_bitmap(unsigned groupIndex) const;
|
||||
|
||||
template<typename F> void traverse_inode_bitmap(unsigned groupIndex, F) const;
|
||||
template<typename F> void traverse_block_bitmap(unsigned groupIndex, F) const;
|
||||
|
||||
bool add_inode_to_directory(InodeIndex parent, InodeIndex child, const String& name, byte fileType, int& error);
|
||||
bool write_directory_inode(unsigned directoryInode, Vector<DirectoryEntry>&&);
|
||||
bool get_inode_allocation_state(InodeIndex) const;
|
||||
bool set_inode_allocation_state(unsigned inode, bool);
|
||||
bool set_block_allocation_state(GroupIndex, BlockIndex, bool);
|
||||
|
||||
void uncache_inode(InodeIndex);
|
||||
void free_inode(Ext2FSInode&);
|
||||
|
||||
struct BlockListShape {
|
||||
unsigned direct_blocks { 0 };
|
||||
unsigned indirect_blocks { 0 };
|
||||
unsigned doubly_indirect_blocks { 0 };
|
||||
unsigned triply_indirect_blocks { 0 };
|
||||
unsigned meta_blocks { 0 };
|
||||
};
|
||||
|
||||
BlockListShape compute_block_list_shape(unsigned blocks);
|
||||
|
||||
unsigned m_blockGroupCount { 0 };
|
||||
|
||||
mutable ByteBuffer m_cached_super_block;
|
||||
mutable ByteBuffer m_cached_group_descriptor_table;
|
||||
|
||||
mutable Lock m_inode_cache_lock;
|
||||
mutable HashMap<BlockIndex, RetainPtr<Ext2FSInode>> m_inode_cache;
|
||||
};
|
||||
|
||||
inline Ext2FS& Ext2FSInode::fs()
|
||||
{
|
||||
return static_cast<Ext2FS&>(Inode::fs());
|
||||
}
|
||||
|
||||
inline const Ext2FS& Ext2FSInode::fs() const
|
||||
{
|
||||
return static_cast<const Ext2FS&>(Inode::fs());
|
||||
}
|
|
@ -3,7 +3,7 @@
|
|||
#include "DoubleBuffer.h"
|
||||
#include <AK/Retainable.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <VirtualFileSystem/UnixTypes.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
|
||||
class FIFO : public Retainable<FIFO> {
|
||||
public:
|
||||
|
|
82
Kernel/FileBackedDiskDevice.cpp
Normal file
82
Kernel/FileBackedDiskDevice.cpp
Normal file
|
@ -0,0 +1,82 @@
|
|||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "FileBackedDiskDevice.h"
|
||||
#include <cstring>
|
||||
#include <sys/stat.h>
|
||||
|
||||
//#define FBBD_DEBUG
|
||||
#define IGNORE_FILE_LENGTH // Useful for e.g /dev/hda2
|
||||
|
||||
RetainPtr<FileBackedDiskDevice> FileBackedDiskDevice::create(String&& image_path, unsigned block_size)
|
||||
{
|
||||
return adopt(*new FileBackedDiskDevice(move(image_path), block_size));
|
||||
}
|
||||
|
||||
FileBackedDiskDevice::FileBackedDiskDevice(String&& image_path, unsigned block_size)
|
||||
: m_image_path(move(image_path))
|
||||
, m_block_size(block_size)
|
||||
{
|
||||
struct stat st;
|
||||
int result = stat(m_image_path.characters(), &st);
|
||||
ASSERT(result != -1);
|
||||
m_file_length = st.st_size;
|
||||
m_file = fopen(m_image_path.characters(), "r+");
|
||||
}
|
||||
|
||||
FileBackedDiskDevice::~FileBackedDiskDevice()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned FileBackedDiskDevice::block_size() const
|
||||
{
|
||||
return m_block_size;
|
||||
}
|
||||
|
||||
bool FileBackedDiskDevice::read_block(unsigned index, byte* out) const
|
||||
{
|
||||
DiskOffset offset = index * m_block_size;
|
||||
return read_internal(offset, block_size(), out);
|
||||
}
|
||||
|
||||
bool FileBackedDiskDevice::write_block(unsigned index, const byte* data)
|
||||
{
|
||||
DiskOffset offset = index * m_block_size;
|
||||
return write_internal(offset, block_size(), data);
|
||||
}
|
||||
|
||||
bool FileBackedDiskDevice::read_internal(DiskOffset offset, unsigned length, byte* out) const
|
||||
{
|
||||
#ifndef IGNORE_FILE_LENGTH
|
||||
if (offset + length >= m_fileLength)
|
||||
return false;
|
||||
#endif
|
||||
#ifdef FBBD_DEBUG
|
||||
printf("[FileBackedDiskDevice] Read device @ offset %llx, length %u\n", offset, length);
|
||||
#endif
|
||||
fseeko(m_file, offset, SEEK_SET);
|
||||
unsigned nread = fread(out, sizeof(byte), length, m_file);
|
||||
ASSERT(nread == length);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileBackedDiskDevice::write_internal(DiskOffset offset, unsigned length, const byte* data)
|
||||
{
|
||||
#ifndef IGNORE_FILE_LENGTH
|
||||
if (offset + length >= m_fileLength)
|
||||
return false;
|
||||
#endif
|
||||
#ifdef FBBD_DEBUG
|
||||
printf("[FileBackedDiskDevice] Write device @ offset %llx, length %u\n", offset, length);
|
||||
#endif
|
||||
fseeko(m_file, offset, SEEK_SET);
|
||||
// size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
|
||||
unsigned nwritten = fwrite(data, sizeof(byte), length, m_file);
|
||||
ASSERT(nwritten == length);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* FileBackedDiskDevice::class_name() const
|
||||
{
|
||||
return "FileBackedDiskDevice";
|
||||
}
|
||||
|
33
Kernel/FileBackedDiskDevice.h
Normal file
33
Kernel/FileBackedDiskDevice.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
#include "DiskDevice.h"
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Types.h>
|
||||
#include <stdio.h>
|
||||
|
||||
class FileBackedDiskDevice final : public DiskDevice {
|
||||
public:
|
||||
static RetainPtr<FileBackedDiskDevice> create(String&& image_path, unsigned block_size);
|
||||
virtual ~FileBackedDiskDevice() override;
|
||||
|
||||
bool is_valid() const { return m_file; }
|
||||
|
||||
virtual unsigned block_size() const override;
|
||||
virtual bool read_block(unsigned index, byte* out) const override;
|
||||
virtual bool write_block(unsigned index, const byte*) override;
|
||||
|
||||
private:
|
||||
virtual const char* class_name() const override;
|
||||
|
||||
bool read_internal(DiskOffset, unsigned length, byte* out) const;
|
||||
bool write_internal(DiskOffset, unsigned length, const byte* data);
|
||||
|
||||
FileBackedDiskDevice(String&& imagePath, unsigned block_size);
|
||||
|
||||
String m_image_path;
|
||||
FILE* m_file { nullptr };
|
||||
DiskOffset m_file_length { 0 };
|
||||
unsigned m_block_size { 0 };
|
||||
};
|
||||
|
322
Kernel/FileDescriptor.cpp
Normal file
322
Kernel/FileDescriptor.cpp
Normal file
|
@ -0,0 +1,322 @@
|
|||
#include "FileDescriptor.h"
|
||||
#include "FileSystem.h"
|
||||
#include "CharacterDevice.h"
|
||||
#include <LibC/errno_numbers.h>
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/BufferStream.h>
|
||||
#include "FIFO.h"
|
||||
#include "TTY.h"
|
||||
#include "MasterPTY.h"
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<Inode>&& inode)
|
||||
{
|
||||
return adopt(*new FileDescriptor(move(inode)));
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::create(RetainPtr<CharacterDevice>&& device)
|
||||
{
|
||||
return adopt(*new FileDescriptor(move(device)));
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::create_pipe_writer(FIFO& fifo)
|
||||
{
|
||||
return adopt(*new FileDescriptor(fifo, FIFO::Writer));
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::create_pipe_reader(FIFO& fifo)
|
||||
{
|
||||
return adopt(*new FileDescriptor(fifo, FIFO::Reader));
|
||||
}
|
||||
|
||||
FileDescriptor::FileDescriptor(RetainPtr<Inode>&& inode)
|
||||
: m_inode(move(inode))
|
||||
{
|
||||
}
|
||||
|
||||
FileDescriptor::FileDescriptor(RetainPtr<CharacterDevice>&& device)
|
||||
: m_device(move(device))
|
||||
{
|
||||
}
|
||||
|
||||
FileDescriptor::~FileDescriptor()
|
||||
{
|
||||
if (m_fifo)
|
||||
m_fifo->close(fifo_direction());
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> FileDescriptor::clone()
|
||||
{
|
||||
RetainPtr<FileDescriptor> descriptor;
|
||||
if (is_fifo()) {
|
||||
descriptor = fifo_direction() == FIFO::Reader
|
||||
? FileDescriptor::create_pipe_reader(*m_fifo)
|
||||
: FileDescriptor::create_pipe_writer(*m_fifo);
|
||||
} else {
|
||||
if (m_inode)
|
||||
descriptor = FileDescriptor::create(m_inode.copyRef());
|
||||
else {
|
||||
descriptor = FileDescriptor::create(m_device.copyRef());
|
||||
}
|
||||
}
|
||||
if (!descriptor)
|
||||
return nullptr;
|
||||
descriptor->m_current_offset = m_current_offset;
|
||||
descriptor->m_is_blocking = m_is_blocking;
|
||||
descriptor->m_file_flags = m_file_flags;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
bool additionWouldOverflow(Unix::off_t a, Unix::off_t b)
|
||||
{
|
||||
ASSERT(a > 0);
|
||||
uint64_t ua = a;
|
||||
return (ua + b) > maxFileOffset;
|
||||
}
|
||||
|
||||
int FileDescriptor::stat(Unix::stat* buffer)
|
||||
{
|
||||
ASSERT(!is_fifo());
|
||||
if (!m_inode && !m_device)
|
||||
return -EBADF;
|
||||
|
||||
auto metadata = this->metadata();
|
||||
if (!metadata.isValid())
|
||||
return -EIO;
|
||||
|
||||
buffer->st_dev = 0; // FIXME
|
||||
buffer->st_ino = metadata.inode.index();
|
||||
buffer->st_mode = metadata.mode;
|
||||
buffer->st_nlink = metadata.linkCount;
|
||||
buffer->st_uid = metadata.uid;
|
||||
buffer->st_gid = metadata.gid;
|
||||
buffer->st_rdev = 0; // FIXME
|
||||
buffer->st_size = metadata.size;
|
||||
buffer->st_blksize = metadata.blockSize;
|
||||
buffer->st_blocks = metadata.blockCount;
|
||||
buffer->st_atime = metadata.atime;
|
||||
buffer->st_mtime = metadata.mtime;
|
||||
buffer->st_ctime = metadata.ctime;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Unix::off_t FileDescriptor::seek(Unix::off_t offset, int whence)
|
||||
{
|
||||
ASSERT(!is_fifo());
|
||||
if (!m_inode && !m_device)
|
||||
return -EBADF;
|
||||
|
||||
// FIXME: The file type should be cached on the vnode.
|
||||
// It's silly that we have to do a full metadata lookup here.
|
||||
auto metadata = this->metadata();
|
||||
if (!metadata.isValid())
|
||||
return -EIO;
|
||||
|
||||
if (metadata.isSocket() || metadata.isFIFO())
|
||||
return -ESPIPE;
|
||||
|
||||
Unix::off_t newOffset;
|
||||
|
||||
switch (whence) {
|
||||
case SEEK_SET:
|
||||
newOffset = offset;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
newOffset = m_current_offset + offset;
|
||||
#ifndef SERENITY
|
||||
if (additionWouldOverflow(m_currentOffset, offset))
|
||||
return -EOVERFLOW;
|
||||
#endif
|
||||
if (newOffset < 0)
|
||||
return -EINVAL;
|
||||
break;
|
||||
case SEEK_END:
|
||||
ASSERT(metadata.size); // FIXME: What do I do?
|
||||
newOffset = metadata.size;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
m_current_offset = newOffset;
|
||||
return m_current_offset;
|
||||
}
|
||||
|
||||
ssize_t FileDescriptor::read(Process& process, byte* buffer, size_t count)
|
||||
{
|
||||
if (is_fifo()) {
|
||||
ASSERT(fifo_direction() == FIFO::Reader);
|
||||
return m_fifo->read(buffer, count);
|
||||
}
|
||||
if (m_device) {
|
||||
// FIXME: What should happen to m_currentOffset?
|
||||
return m_device->read(process, buffer, count);
|
||||
}
|
||||
ASSERT(inode());
|
||||
ssize_t nread = inode()->read_bytes(m_current_offset, count, buffer, this);
|
||||
m_current_offset += nread;
|
||||
return nread;
|
||||
}
|
||||
|
||||
ssize_t FileDescriptor::write(Process& process, const byte* data, size_t size)
|
||||
{
|
||||
if (is_fifo()) {
|
||||
ASSERT(fifo_direction() == FIFO::Writer);
|
||||
return m_fifo->write(data, size);
|
||||
}
|
||||
if (m_device) {
|
||||
// FIXME: What should happen to m_currentOffset?
|
||||
return m_device->write(process, data, size);
|
||||
}
|
||||
ASSERT(m_inode);
|
||||
ssize_t nwritten = m_inode->write_bytes(m_current_offset, size, data, this);
|
||||
m_current_offset += nwritten;
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
bool FileDescriptor::can_write(Process& process)
|
||||
{
|
||||
if (is_fifo()) {
|
||||
ASSERT(fifo_direction() == FIFO::Writer);
|
||||
return m_fifo->can_write();
|
||||
}
|
||||
if (m_device)
|
||||
return m_device->can_write(process);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FileDescriptor::can_read(Process& process)
|
||||
{
|
||||
if (is_fifo()) {
|
||||
ASSERT(fifo_direction() == FIFO::Reader);
|
||||
return m_fifo->can_read();
|
||||
}
|
||||
if (m_device)
|
||||
return m_device->can_read(process);
|
||||
return true;
|
||||
}
|
||||
|
||||
ByteBuffer FileDescriptor::read_entire_file(Process& process)
|
||||
{
|
||||
ASSERT(!is_fifo());
|
||||
|
||||
if (m_device) {
|
||||
auto buffer = ByteBuffer::create_uninitialized(1024);
|
||||
ssize_t nread = m_device->read(process, buffer.pointer(), buffer.size());
|
||||
buffer.trim(nread);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
ASSERT(m_inode);
|
||||
return m_inode->read_entire(this);
|
||||
}
|
||||
|
||||
bool FileDescriptor::is_directory() const
|
||||
{
|
||||
ASSERT(!is_fifo());
|
||||
return metadata().isDirectory();
|
||||
}
|
||||
|
||||
ssize_t FileDescriptor::get_dir_entries(byte* buffer, size_t size)
|
||||
{
|
||||
auto metadata = this->metadata();
|
||||
if (!metadata.isValid())
|
||||
return -EIO;
|
||||
if (!metadata.isDirectory())
|
||||
return -ENOTDIR;
|
||||
|
||||
// FIXME: Compute the actual size needed.
|
||||
auto tempBuffer = ByteBuffer::create_uninitialized(2048);
|
||||
BufferStream stream(tempBuffer);
|
||||
VFS::the().traverse_directory_inode(*m_inode, [&stream] (auto& entry) {
|
||||
stream << (dword)entry.inode.index();
|
||||
stream << (byte)entry.fileType;
|
||||
stream << (dword)entry.name_length;
|
||||
stream << entry.name;
|
||||
return true;
|
||||
});
|
||||
|
||||
if (size < stream.offset())
|
||||
return -1;
|
||||
|
||||
memcpy(buffer, tempBuffer.pointer(), stream.offset());
|
||||
return stream.offset();
|
||||
}
|
||||
|
||||
bool FileDescriptor::is_tty() const
|
||||
{
|
||||
return m_device && m_device->is_tty();
|
||||
}
|
||||
|
||||
const TTY* FileDescriptor::tty() const
|
||||
{
|
||||
if (!is_tty())
|
||||
return nullptr;
|
||||
return static_cast<const TTY*>(m_device.ptr());
|
||||
}
|
||||
|
||||
TTY* FileDescriptor::tty()
|
||||
{
|
||||
if (!is_tty())
|
||||
return nullptr;
|
||||
return static_cast<TTY*>(m_device.ptr());
|
||||
}
|
||||
|
||||
bool FileDescriptor::is_master_pty() const
|
||||
{
|
||||
if (m_device)
|
||||
return m_device->is_master_pty();
|
||||
return false;
|
||||
}
|
||||
|
||||
const MasterPTY* FileDescriptor::master_pty() const
|
||||
{
|
||||
if (!is_master_pty())
|
||||
return nullptr;
|
||||
return static_cast<const MasterPTY*>(m_device.ptr());
|
||||
}
|
||||
|
||||
MasterPTY* FileDescriptor::master_pty()
|
||||
{
|
||||
if (!is_master_pty())
|
||||
return nullptr;
|
||||
return static_cast<MasterPTY*>(m_device.ptr());
|
||||
}
|
||||
|
||||
int FileDescriptor::close()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
String FileDescriptor::absolute_path()
|
||||
{
|
||||
Stopwatch sw("absolute_path");
|
||||
if (is_tty())
|
||||
return tty()->tty_name();
|
||||
if (is_fifo()) {
|
||||
char buf[32];
|
||||
ksprintf(buf, "fifo:%x", m_fifo.ptr());
|
||||
return buf;
|
||||
}
|
||||
if (is_character_device()) {
|
||||
char buf[128];
|
||||
ksprintf(buf, "device:%u,%u (%s)", m_device->major(), m_device->minor(), m_device->class_name());
|
||||
return buf;
|
||||
}
|
||||
ASSERT(m_inode);
|
||||
return VFS::the().absolute_path(*m_inode);
|
||||
}
|
||||
|
||||
FileDescriptor::FileDescriptor(FIFO& fifo, FIFO::Direction direction)
|
||||
: m_is_blocking(true)
|
||||
, m_fifo(fifo)
|
||||
, m_fifo_direction(direction)
|
||||
{
|
||||
m_fifo->open(direction);
|
||||
}
|
||||
|
||||
InodeMetadata FileDescriptor::metadata() const
|
||||
{
|
||||
if (m_inode)
|
||||
return m_inode->metadata();
|
||||
return { };
|
||||
}
|
90
Kernel/FileDescriptor.h
Normal file
90
Kernel/FileDescriptor.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "VirtualFileSystem.h"
|
||||
#include "InodeMetadata.h"
|
||||
#include "FIFO.h"
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <AK/Retainable.h>
|
||||
|
||||
class TTY;
|
||||
class MasterPTY;
|
||||
class Process;
|
||||
|
||||
class FileDescriptor : public Retainable<FileDescriptor> {
|
||||
public:
|
||||
static RetainPtr<FileDescriptor> create(RetainPtr<Inode>&&);
|
||||
static RetainPtr<FileDescriptor> create(RetainPtr<CharacterDevice>&&);
|
||||
static RetainPtr<FileDescriptor> create_pipe_writer(FIFO&);
|
||||
static RetainPtr<FileDescriptor> create_pipe_reader(FIFO&);
|
||||
~FileDescriptor();
|
||||
|
||||
RetainPtr<FileDescriptor> clone();
|
||||
|
||||
int close();
|
||||
|
||||
Unix::off_t seek(Unix::off_t, int whence);
|
||||
ssize_t read(Process&, byte*, size_t);
|
||||
ssize_t write(Process&, const byte* data, size_t);
|
||||
int stat(Unix::stat*);
|
||||
|
||||
bool can_read(Process&);
|
||||
bool can_write(Process&);
|
||||
|
||||
ssize_t get_dir_entries(byte* buffer, size_t);
|
||||
|
||||
ByteBuffer read_entire_file(Process&);
|
||||
|
||||
String absolute_path();
|
||||
|
||||
bool is_directory() const;
|
||||
|
||||
bool is_character_device() const { return m_device.ptr(); }
|
||||
CharacterDevice* character_device() { return m_device.ptr(); }
|
||||
const CharacterDevice* character_device() const { return m_device.ptr(); }
|
||||
|
||||
bool is_tty() const;
|
||||
const TTY* tty() const;
|
||||
TTY* tty();
|
||||
|
||||
bool is_master_pty() const;
|
||||
const MasterPTY* master_pty() const;
|
||||
MasterPTY* master_pty();
|
||||
|
||||
InodeMetadata metadata() const;
|
||||
Inode* inode() { return m_inode.ptr(); }
|
||||
const Inode* inode() const { return m_inode.ptr(); }
|
||||
|
||||
bool supports_mmap() const { return m_inode && !m_device; }
|
||||
|
||||
bool is_blocking() const { return m_is_blocking; }
|
||||
void set_blocking(bool b) { m_is_blocking = b; }
|
||||
|
||||
dword file_flags() const { return m_file_flags; }
|
||||
void set_file_flags(dword flags) { m_file_flags = flags; }
|
||||
|
||||
bool is_fifo() const { return m_fifo; }
|
||||
FIFO::Direction fifo_direction() { return m_fifo_direction; }
|
||||
|
||||
ByteBuffer& generator_cache() { return m_generator_cache; }
|
||||
|
||||
private:
|
||||
friend class VFS;
|
||||
explicit FileDescriptor(RetainPtr<Inode>&&);
|
||||
explicit FileDescriptor(RetainPtr<CharacterDevice>&&);
|
||||
FileDescriptor(FIFO&, FIFO::Direction);
|
||||
|
||||
RetainPtr<Inode> m_inode;
|
||||
RetainPtr<CharacterDevice> m_device;
|
||||
|
||||
Unix::off_t m_current_offset { 0 };
|
||||
|
||||
ByteBuffer m_generator_cache;
|
||||
|
||||
bool m_is_blocking { true };
|
||||
dword m_file_flags { 0 };
|
||||
|
||||
RetainPtr<FIFO> m_fifo;
|
||||
FIFO::Direction m_fifo_direction { FIFO::Neither };
|
||||
};
|
||||
|
151
Kernel/FileSystem.cpp
Normal file
151
Kernel/FileSystem.cpp
Normal file
|
@ -0,0 +1,151 @@
|
|||
#include <AK/Assertions.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <LibC/errno_numbers.h>
|
||||
#include "FileSystem.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
static dword s_lastFileSystemID;
|
||||
static HashMap<dword, FS*>* s_fs_map;
|
||||
static HashTable<Inode*>* s_inode_set;
|
||||
|
||||
static HashMap<dword, FS*>& all_fses()
|
||||
{
|
||||
if (!s_fs_map)
|
||||
s_fs_map = new HashMap<dword, FS*>();
|
||||
return *s_fs_map;
|
||||
}
|
||||
|
||||
HashTable<Inode*>& all_inodes()
|
||||
{
|
||||
if (!s_inode_set)
|
||||
s_inode_set = new HashTable<Inode*>();
|
||||
return *s_inode_set;
|
||||
}
|
||||
|
||||
void FS::initialize_globals()
|
||||
{
|
||||
s_lastFileSystemID = 0;
|
||||
s_fs_map = nullptr;
|
||||
s_inode_set = nullptr;
|
||||
}
|
||||
|
||||
FS::FS()
|
||||
: m_fsid(++s_lastFileSystemID)
|
||||
{
|
||||
all_fses().set(m_fsid, this);
|
||||
}
|
||||
|
||||
FS::~FS()
|
||||
{
|
||||
all_fses().remove(m_fsid);
|
||||
}
|
||||
|
||||
FS* FS::from_fsid(dword id)
|
||||
{
|
||||
auto it = all_fses().find(id);
|
||||
if (it != all_fses().end())
|
||||
return (*it).value;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ByteBuffer Inode::read_entire(FileDescriptor* descriptor)
|
||||
{
|
||||
size_t initial_size = metadata().size ? metadata().size : 4096;
|
||||
auto contents = ByteBuffer::create_uninitialized(initial_size);
|
||||
|
||||
ssize_t nread;
|
||||
byte buffer[4096];
|
||||
byte* out = contents.pointer();
|
||||
Unix::off_t offset = 0;
|
||||
for (;;) {
|
||||
nread = read_bytes(offset, sizeof(buffer), buffer, descriptor);
|
||||
ASSERT(nread <= (ssize_t)sizeof(buffer));
|
||||
if (nread <= 0)
|
||||
break;
|
||||
memcpy(out, buffer, nread);
|
||||
out += nread;
|
||||
offset += nread;
|
||||
ASSERT(offset <= (ssize_t)initial_size); // FIXME: Support dynamically growing the buffer.
|
||||
}
|
||||
if (nread < 0) {
|
||||
kprintf("Inode::read_entire: ERROR: %d\n", nread);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
contents.trim(offset);
|
||||
return contents;
|
||||
}
|
||||
|
||||
FS::DirectoryEntry::DirectoryEntry(const char* n, InodeIdentifier i, byte ft)
|
||||
: name_length(strlen(n))
|
||||
, inode(i)
|
||||
, fileType(ft)
|
||||
{
|
||||
memcpy(name, n, name_length);
|
||||
name[name_length] = '\0';
|
||||
}
|
||||
|
||||
FS::DirectoryEntry::DirectoryEntry(const char* n, size_t nl, InodeIdentifier i, byte ft)
|
||||
: name_length(nl)
|
||||
, inode(i)
|
||||
, fileType(ft)
|
||||
{
|
||||
memcpy(name, n, nl);
|
||||
name[nl] = '\0';
|
||||
}
|
||||
|
||||
Inode::Inode(FS& fs, unsigned index)
|
||||
: m_fs(fs)
|
||||
, m_index(index)
|
||||
{
|
||||
all_inodes().set(this);
|
||||
}
|
||||
|
||||
Inode::~Inode()
|
||||
{
|
||||
all_inodes().remove(this);
|
||||
}
|
||||
|
||||
void Inode::will_be_destroyed()
|
||||
{
|
||||
if (m_metadata_dirty)
|
||||
flush_metadata();
|
||||
}
|
||||
|
||||
int Inode::set_atime(Unix::time_t)
|
||||
{
|
||||
return -ENOTIMPL;
|
||||
}
|
||||
|
||||
int Inode::set_ctime(Unix::time_t)
|
||||
{
|
||||
return -ENOTIMPL;
|
||||
}
|
||||
|
||||
int Inode::set_mtime(Unix::time_t)
|
||||
{
|
||||
return -ENOTIMPL;
|
||||
}
|
||||
|
||||
int Inode::increment_link_count()
|
||||
{
|
||||
return -ENOTIMPL;
|
||||
}
|
||||
|
||||
int Inode::decrement_link_count()
|
||||
{
|
||||
return -ENOTIMPL;
|
||||
}
|
||||
|
||||
void FS::sync()
|
||||
{
|
||||
for (auto* inode : all_inodes()) {
|
||||
if (inode->is_metadata_dirty())
|
||||
inode->flush_metadata();
|
||||
}
|
||||
}
|
||||
|
||||
void Inode::set_vmo(RetainPtr<VMObject>&& vmo)
|
||||
{
|
||||
m_vmo = move(vmo);
|
||||
}
|
148
Kernel/FileSystem.h
Normal file
148
Kernel/FileSystem.h
Normal file
|
@ -0,0 +1,148 @@
|
|||
#pragma once
|
||||
|
||||
#include "DiskDevice.h"
|
||||
#include "InodeIdentifier.h"
|
||||
#include "InodeMetadata.h"
|
||||
#include "Limits.h"
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/Retainable.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Function.h>
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
static const dword mepoch = 476763780;
|
||||
|
||||
class Inode;
|
||||
class FileDescriptor;
|
||||
class VMObject;
|
||||
|
||||
class FS : public Retainable<FS> {
|
||||
public:
|
||||
static void initialize_globals();
|
||||
virtual ~FS();
|
||||
|
||||
dword id() const { return m_fsid; }
|
||||
static FS* from_fsid(dword);
|
||||
static void sync();
|
||||
|
||||
virtual bool initialize() = 0;
|
||||
virtual const char* class_name() const = 0;
|
||||
virtual InodeIdentifier root_inode() const = 0;
|
||||
|
||||
bool is_readonly() const { return m_readonly; }
|
||||
|
||||
struct DirectoryEntry {
|
||||
DirectoryEntry(const char* name, InodeIdentifier, byte fileType);
|
||||
DirectoryEntry(const char* name, size_t name_length, InodeIdentifier, byte fileType);
|
||||
char name[256];
|
||||
size_t name_length { 0 };
|
||||
InodeIdentifier inode;
|
||||
byte fileType { 0 };
|
||||
};
|
||||
|
||||
virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) = 0;
|
||||
virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) = 0;
|
||||
|
||||
virtual RetainPtr<Inode> get_inode(InodeIdentifier) const = 0;
|
||||
|
||||
protected:
|
||||
FS();
|
||||
|
||||
private:
|
||||
dword m_fsid { 0 };
|
||||
bool m_readonly { false };
|
||||
};
|
||||
|
||||
class Inode : public Retainable<Inode> {
|
||||
friend class VFS;
|
||||
public:
|
||||
virtual ~Inode();
|
||||
|
||||
virtual void one_retain_left() { }
|
||||
|
||||
FS& fs() { return m_fs; }
|
||||
const FS& fs() const { return m_fs; }
|
||||
unsigned fsid() const;
|
||||
unsigned index() const { return m_index; }
|
||||
|
||||
size_t size() const { return metadata().size; }
|
||||
bool is_symlink() const { return metadata().isSymbolicLink(); }
|
||||
bool is_directory() const { return metadata().isDirectory(); }
|
||||
bool is_character_device() const { return metadata().isCharacterDevice(); }
|
||||
|
||||
InodeIdentifier identifier() const { return { fsid(), index() }; }
|
||||
virtual InodeMetadata metadata() const = 0;
|
||||
|
||||
ByteBuffer read_entire(FileDescriptor* = nullptr);
|
||||
|
||||
virtual ssize_t read_bytes(Unix::off_t, size_t, byte* buffer, FileDescriptor*) = 0;
|
||||
virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) = 0;
|
||||
virtual InodeIdentifier lookup(const String& name) = 0;
|
||||
virtual String reverse_lookup(InodeIdentifier) = 0;
|
||||
virtual ssize_t write_bytes(Unix::off_t, size_t, const byte* data, FileDescriptor*) = 0;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) = 0;
|
||||
virtual bool remove_child(const String& name, int& error) = 0;
|
||||
virtual RetainPtr<Inode> parent() const = 0;
|
||||
|
||||
bool is_metadata_dirty() const { return m_metadata_dirty; }
|
||||
|
||||
virtual int set_atime(Unix::time_t);
|
||||
virtual int set_ctime(Unix::time_t);
|
||||
virtual int set_mtime(Unix::time_t);
|
||||
virtual int increment_link_count();
|
||||
virtual int decrement_link_count();
|
||||
|
||||
virtual void flush_metadata() = 0;
|
||||
|
||||
void will_be_destroyed();
|
||||
|
||||
void set_vmo(RetainPtr<VMObject>&&);
|
||||
VMObject* vmo() { return m_vmo.ptr(); }
|
||||
const VMObject* vmo() const { return m_vmo.ptr(); }
|
||||
|
||||
protected:
|
||||
Inode(FS& fs, unsigned index);
|
||||
|
||||
void set_metadata_dirty(bool b) { m_metadata_dirty = b; }
|
||||
private:
|
||||
FS& m_fs;
|
||||
unsigned m_index { 0 };
|
||||
RetainPtr<VMObject> m_vmo;
|
||||
bool m_metadata_dirty { false };
|
||||
};
|
||||
|
||||
inline FS* InodeIdentifier::fs()
|
||||
{
|
||||
return FS::from_fsid(m_fsid);
|
||||
}
|
||||
|
||||
inline const FS* InodeIdentifier::fs() const
|
||||
{
|
||||
return FS::from_fsid(m_fsid);
|
||||
}
|
||||
|
||||
inline bool InodeIdentifier::is_root_inode() const
|
||||
{
|
||||
return (*this) == fs()->root_inode();
|
||||
}
|
||||
|
||||
inline unsigned Inode::fsid() const
|
||||
{
|
||||
return m_fs.id();
|
||||
}
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<>
|
||||
struct Traits<InodeIdentifier> {
|
||||
// FIXME: This is a shitty hash.
|
||||
static unsigned hash(const InodeIdentifier& inode) { return Traits<unsigned>::hash(inode.fsid()) + Traits<unsigned>::hash(inode.index()); }
|
||||
static void dump(const InodeIdentifier& inode) { kprintf("%02u:%08u", inode.fsid(), inode.index()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
34
Kernel/FullDevice.cpp
Normal file
34
Kernel/FullDevice.cpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#include "FullDevice.h"
|
||||
#include "Limits.h"
|
||||
#include <LibC/errno_numbers.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
FullDevice::FullDevice()
|
||||
: CharacterDevice(1, 7)
|
||||
{
|
||||
}
|
||||
|
||||
FullDevice::~FullDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool FullDevice::can_read(Process&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t FullDevice::read(Process&, byte* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t count = min(GoodBufferSize, bufferSize);
|
||||
memset(buffer, 0, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t FullDevice::write(Process&, const byte*, size_t bufferSize)
|
||||
{
|
||||
if (bufferSize == 0)
|
||||
return 0;
|
||||
return -ENOSPC;
|
||||
}
|
||||
|
19
Kernel/FullDevice.h
Normal file
19
Kernel/FullDevice.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "CharacterDevice.h"
|
||||
|
||||
class FullDevice final : public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
FullDevice();
|
||||
virtual ~FullDevice() override;
|
||||
|
||||
private:
|
||||
// ^CharacterDevice
|
||||
virtual ssize_t read(Process&, byte* buffer, size_t bufferSize) override;
|
||||
virtual ssize_t write(Process&, const byte* buffer, size_t bufferSize) override;
|
||||
virtual bool can_read(Process&) const override;
|
||||
virtual bool can_write(Process&) const override { return true; }
|
||||
virtual const char* class_name() const override { return "FullDevice"; }
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
|
||||
class GUIEventDevice final : public CharacterDevice {
|
||||
public:
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
#include <AK/Lock.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <VirtualFileSystem/DiskDevice.h>
|
||||
#include <Kernel/DiskDevice.h>
|
||||
#include "IRQHandler.h"
|
||||
|
||||
class IDEDiskDevice final : public IRQHandler, public DiskDevice {
|
||||
|
|
42
Kernel/InodeIdentifier.h
Normal file
42
Kernel/InodeIdentifier.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/ByteBuffer.h>
|
||||
#include <AK/Types.h>
|
||||
|
||||
class FS;
|
||||
struct InodeMetadata;
|
||||
|
||||
class InodeIdentifier {
|
||||
public:
|
||||
InodeIdentifier() { }
|
||||
InodeIdentifier(dword fileSystemID, dword inode)
|
||||
: m_fsid(fileSystemID)
|
||||
, m_index(inode)
|
||||
{
|
||||
}
|
||||
|
||||
bool is_valid() const { return m_fsid != 0 && m_index != 0; }
|
||||
|
||||
dword fsid() const { return m_fsid; }
|
||||
dword index() const { return m_index; }
|
||||
|
||||
FS* fs();
|
||||
const FS* fs() const;
|
||||
|
||||
bool operator==(const InodeIdentifier& other) const
|
||||
{
|
||||
return m_fsid == other.m_fsid && m_index == other.m_index;
|
||||
}
|
||||
|
||||
bool operator!=(const InodeIdentifier& other) const
|
||||
{
|
||||
return m_fsid != other.m_fsid || m_index != other.m_index;
|
||||
}
|
||||
|
||||
bool is_root_inode() const;
|
||||
|
||||
private:
|
||||
dword m_fsid { 0 };
|
||||
dword m_index { 0 };
|
||||
};
|
||||
|
57
Kernel/InodeMetadata.h
Normal file
57
Kernel/InodeMetadata.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
|
||||
#include "InodeIdentifier.h"
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/HashTable.h>
|
||||
|
||||
inline bool isDirectory(Unix::mode_t mode) { return (mode & 0170000) == 0040000; }
|
||||
inline bool isCharacterDevice(Unix::mode_t mode) { return (mode & 0170000) == 0020000; }
|
||||
inline bool isBlockDevice(Unix::mode_t mode) { return (mode & 0170000) == 0060000; }
|
||||
inline bool isRegularFile(Unix::mode_t mode) { return (mode & 0170000) == 0100000; }
|
||||
inline bool isFIFO(Unix::mode_t mode) { return (mode & 0170000) == 0010000; }
|
||||
inline bool isSymbolicLink(Unix::mode_t mode) { return (mode & 0170000) == 0120000; }
|
||||
inline bool isSocket(Unix::mode_t mode) { return (mode & 0170000) == 0140000; }
|
||||
inline bool isSticky(Unix::mode_t mode) { return mode & 01000; }
|
||||
inline bool isSetUID(Unix::mode_t mode) { return mode & 04000; }
|
||||
inline bool isSetGID(Unix::mode_t mode) { return mode & 02000; }
|
||||
|
||||
struct InodeMetadata {
|
||||
bool isValid() const { return inode.is_valid(); }
|
||||
|
||||
bool mayExecute(uid_t u, const HashTable<gid_t>& g) const
|
||||
{
|
||||
if (uid == u)
|
||||
return mode & 0100;
|
||||
if (g.contains(gid))
|
||||
return mode & 0010;
|
||||
return mode & 0001;
|
||||
}
|
||||
|
||||
bool isDirectory() const { return ::isDirectory(mode); }
|
||||
bool isCharacterDevice() const { return ::isCharacterDevice(mode); }
|
||||
bool isBlockDevice() const { return ::isBlockDevice(mode); }
|
||||
bool isRegularFile() const { return ::isRegularFile(mode); }
|
||||
bool isFIFO() const { return ::isFIFO(mode); }
|
||||
bool isSymbolicLink() const { return ::isSymbolicLink(mode); }
|
||||
bool isSocket() const { return ::isSocket(mode); }
|
||||
bool isSticky() const { return ::isSticky(mode); }
|
||||
bool isSetUID() const { return ::isSetUID(mode); }
|
||||
bool isSetGID() const { return ::isSetGID(mode); }
|
||||
|
||||
InodeIdentifier inode;
|
||||
Unix::off_t size { 0 };
|
||||
Unix::mode_t mode { 0 };
|
||||
Unix::uid_t uid { 0 };
|
||||
Unix::gid_t gid { 0 };
|
||||
Unix::nlink_t linkCount { 0 };
|
||||
Unix::time_t atime { 0 };
|
||||
Unix::time_t ctime { 0 };
|
||||
Unix::time_t mtime { 0 };
|
||||
Unix::time_t dtime { 0 };
|
||||
Unix::blkcnt_t blockCount { 0 };
|
||||
Unix::blksize_t blockSize { 0 };
|
||||
unsigned majorDevice { 0 };
|
||||
unsigned minorDevice { 0 };
|
||||
};
|
||||
|
||||
|
|
@ -3,7 +3,7 @@
|
|||
#include <AK/Types.h>
|
||||
#include <AK/DoublyLinkedList.h>
|
||||
#include <AK/CircularQueue.h>
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
#include "IRQHandler.h"
|
||||
|
||||
class KeyboardClient;
|
||||
|
|
9
Kernel/Limits.h
Normal file
9
Kernel/Limits.h
Normal file
|
@ -0,0 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include "UnixTypes.h"
|
||||
|
||||
inline static const Unix::off_t maxFileOffset = 2147483647;
|
||||
|
||||
static const size_t GoodBufferSize = 4096;
|
||||
|
||||
|
|
@ -33,18 +33,18 @@ KERNEL_OBJS = \
|
|||
GUIEventDevice.o
|
||||
|
||||
VFS_OBJS = \
|
||||
../VirtualFileSystem/DiskDevice.o \
|
||||
../VirtualFileSystem/CharacterDevice.o \
|
||||
../VirtualFileSystem/NullDevice.o \
|
||||
../VirtualFileSystem/FullDevice.o \
|
||||
../VirtualFileSystem/ZeroDevice.o \
|
||||
../VirtualFileSystem/RandomDevice.o \
|
||||
../VirtualFileSystem/FileSystem.o \
|
||||
../VirtualFileSystem/DiskBackedFileSystem.o \
|
||||
../VirtualFileSystem/Ext2FileSystem.o \
|
||||
../VirtualFileSystem/VirtualFileSystem.o \
|
||||
../VirtualFileSystem/FileDescriptor.o \
|
||||
../VirtualFileSystem/SyntheticFileSystem.o
|
||||
DiskDevice.o \
|
||||
CharacterDevice.o \
|
||||
NullDevice.o \
|
||||
FullDevice.o \
|
||||
ZeroDevice.o \
|
||||
RandomDevice.o \
|
||||
FileSystem.o \
|
||||
DiskBackedFileSystem.o \
|
||||
Ext2FileSystem.o \
|
||||
VirtualFileSystem.o \
|
||||
FileDescriptor.o \
|
||||
SyntheticFileSystem.o
|
||||
|
||||
SHAREDGRAPHICS_OBJS = \
|
||||
../SharedGraphics/Rect.o \
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
#include "DoubleBuffer.h"
|
||||
|
||||
class SlavePTY;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include <AK/Vector.h>
|
||||
#include <AK/HashTable.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <Kernel/VirtualFileSystem.h>
|
||||
|
||||
#define PAGE_ROUND_UP(x) ((((dword)(x)) + PAGE_SIZE-1) & (~(PAGE_SIZE-1)))
|
||||
|
||||
|
|
29
Kernel/NullDevice.cpp
Normal file
29
Kernel/NullDevice.cpp
Normal file
|
@ -0,0 +1,29 @@
|
|||
#include "NullDevice.h"
|
||||
#include "Limits.h"
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
NullDevice::NullDevice()
|
||||
: CharacterDevice(1, 3)
|
||||
{
|
||||
}
|
||||
|
||||
NullDevice::~NullDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool NullDevice::can_read(Process&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t NullDevice::read(Process&, byte*, size_t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t NullDevice::write(Process&, const byte*, size_t bufferSize)
|
||||
{
|
||||
return min(GoodBufferSize, bufferSize);
|
||||
}
|
||||
|
19
Kernel/NullDevice.h
Normal file
19
Kernel/NullDevice.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "CharacterDevice.h"
|
||||
|
||||
class NullDevice final : public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
NullDevice();
|
||||
virtual ~NullDevice() override;
|
||||
|
||||
private:
|
||||
// ^CharacterDevice
|
||||
virtual ssize_t read(Process&, byte* buffer, size_t bufferSize) override;
|
||||
virtual ssize_t write(Process&, const byte* buffer, size_t bufferSize) override;
|
||||
virtual bool can_write(Process&) const override { return true; }
|
||||
virtual bool can_read(Process&) const override;
|
||||
virtual const char* class_name() const override { return "CharacterDevice"; }
|
||||
};
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
#include "IRQHandler.h"
|
||||
|
||||
class PS2MouseDevice final : public IRQHandler, public CharacterDevice {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
#include <AK/Lock.h>
|
||||
|
||||
class MasterPTY;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#include "ProcFileSystem.h"
|
||||
#include "Process.h"
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <Kernel/VirtualFileSystem.h>
|
||||
#include "system.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "StdLib.h"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/Types.h>
|
||||
#include <VirtualFileSystem/SyntheticFileSystem.h>
|
||||
#include <Kernel/SyntheticFileSystem.h>
|
||||
|
||||
class Process;
|
||||
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
#include "StdLib.h"
|
||||
#include "i386.h"
|
||||
#include "system.h"
|
||||
#include <VirtualFileSystem/FileDescriptor.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <Kernel/FileDescriptor.h>
|
||||
#include <Kernel/VirtualFileSystem.h>
|
||||
#include "ELFLoader.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "i8253.h"
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
#include "TTY.h"
|
||||
#include "Syscall.h"
|
||||
#include "GUITypes.h"
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <VirtualFileSystem/UnixTypes.h>
|
||||
#include <Kernel/VirtualFileSystem.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
#include <AK/InlineLinkedList.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Vector.h>
|
||||
|
|
53
Kernel/RandomDevice.cpp
Normal file
53
Kernel/RandomDevice.cpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
#include "RandomDevice.h"
|
||||
#include "Limits.h"
|
||||
#include <AK/StdLibExtras.h>
|
||||
|
||||
RandomDevice::RandomDevice()
|
||||
: CharacterDevice(1, 8)
|
||||
{
|
||||
}
|
||||
|
||||
RandomDevice::~RandomDevice()
|
||||
{
|
||||
}
|
||||
|
||||
// Simple rand() and srand() borrowed from the POSIX standard:
|
||||
|
||||
static unsigned long next = 1;
|
||||
|
||||
#define MY_RAND_MAX 32767
|
||||
static int myrand()
|
||||
{
|
||||
next = next * 1103515245 + 12345;
|
||||
return((unsigned)(next/((MY_RAND_MAX + 1) * 2)) % (MY_RAND_MAX + 1));
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void mysrand(unsigned seed)
|
||||
{
|
||||
next = seed;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool RandomDevice::can_read(Process&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t RandomDevice::read(Process&, byte* buffer, size_t bufferSize)
|
||||
{
|
||||
const int range = 'z' - 'a';
|
||||
ssize_t nread = min(bufferSize, GoodBufferSize);
|
||||
for (ssize_t i = 0; i < nread; ++i) {
|
||||
dword r = myrand() % range;
|
||||
buffer[i] = 'a' + r;
|
||||
}
|
||||
return nread;
|
||||
}
|
||||
|
||||
ssize_t RandomDevice::write(Process&, const byte*, size_t bufferSize)
|
||||
{
|
||||
// FIXME: Use input for entropy? I guess that could be a neat feature?
|
||||
return min(GoodBufferSize, bufferSize);
|
||||
}
|
||||
|
19
Kernel/RandomDevice.h
Normal file
19
Kernel/RandomDevice.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "CharacterDevice.h"
|
||||
|
||||
class RandomDevice final : public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
RandomDevice();
|
||||
virtual ~RandomDevice() override;
|
||||
|
||||
private:
|
||||
// ^CharacterDevice
|
||||
virtual ssize_t read(Process&, byte* buffer, size_t bufferSize) override;
|
||||
virtual ssize_t write(Process&, const byte* buffer, size_t bufferSize) override;
|
||||
virtual bool can_read(Process&) const override;
|
||||
virtual bool can_write(Process&) const override { return true; }
|
||||
virtual const char* class_name() const override { return "RandomDevice"; }
|
||||
};
|
||||
|
307
Kernel/SyntheticFileSystem.cpp
Normal file
307
Kernel/SyntheticFileSystem.cpp
Normal file
|
@ -0,0 +1,307 @@
|
|||
#include "SyntheticFileSystem.h"
|
||||
#include "FileDescriptor.h"
|
||||
#include <LibC/errno_numbers.h>
|
||||
#include <AK/StdLibExtras.h>
|
||||
|
||||
#ifndef SERENITY
|
||||
typedef int InterruptDisabler;
|
||||
#define ASSERT_INTERRUPTS_DISABLED()
|
||||
#endif
|
||||
|
||||
//#define SYNTHFS_DEBUG
|
||||
|
||||
RetainPtr<SynthFS> SynthFS::create()
|
||||
{
|
||||
return adopt(*new SynthFS);
|
||||
}
|
||||
|
||||
SynthFS::SynthFS()
|
||||
{
|
||||
}
|
||||
|
||||
SynthFS::~SynthFS()
|
||||
{
|
||||
}
|
||||
|
||||
bool SynthFS::initialize()
|
||||
{
|
||||
// Add a File for the root directory.
|
||||
// FIXME: This needs work.
|
||||
auto root = adopt(*new SynthFSInode(*this, RootInodeIndex));
|
||||
root->m_parent = { id(), RootInodeIndex };
|
||||
root->m_metadata.mode = 0040555;
|
||||
root->m_metadata.uid = 0;
|
||||
root->m_metadata.gid = 0;
|
||||
root->m_metadata.size = 0;
|
||||
root->m_metadata.mtime = mepoch;
|
||||
m_inodes.set(RootInodeIndex, move(root));
|
||||
|
||||
#ifndef SERENITY
|
||||
addFile(createTextFile("file", String("I'm a synthetic file!\n").toByteBuffer(), 0100644));
|
||||
addFile(createTextFile("message", String("Hey! This isn't my bottle!\n").toByteBuffer(), 0100644));
|
||||
addFile(createGeneratedFile("lunk", [] { return String("/home/andreas/file1").toByteBuffer(); }, 00120777));
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
RetainPtr<SynthFSInode> SynthFS::create_directory(String&& name)
|
||||
{
|
||||
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
|
||||
file->m_name = move(name);
|
||||
file->m_metadata.size = 0;
|
||||
file->m_metadata.uid = 0;
|
||||
file->m_metadata.gid = 0;
|
||||
file->m_metadata.mode = 0040555;
|
||||
file->m_metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
||||
RetainPtr<SynthFSInode> SynthFS::create_text_file(String&& name, ByteBuffer&& contents, Unix::mode_t mode)
|
||||
{
|
||||
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
|
||||
file->m_data = contents;
|
||||
file->m_name = move(name);
|
||||
file->m_metadata.size = file->m_data.size();
|
||||
file->m_metadata.uid = 100;
|
||||
file->m_metadata.gid = 200;
|
||||
file->m_metadata.mode = mode;
|
||||
file->m_metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
||||
RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& generator, Unix::mode_t mode)
|
||||
{
|
||||
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
|
||||
file->m_generator = move(generator);
|
||||
file->m_name = move(name);
|
||||
file->m_metadata.size = 0;
|
||||
file->m_metadata.uid = 0;
|
||||
file->m_metadata.gid = 0;
|
||||
file->m_metadata.mode = mode;
|
||||
file->m_metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
||||
RetainPtr<SynthFSInode> SynthFS::create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&& read_callback, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&& write_callback, Unix::mode_t mode)
|
||||
{
|
||||
auto file = adopt(*new SynthFSInode(*this, generate_inode_index()));
|
||||
file->m_generator = move(read_callback);
|
||||
file->m_write_callback = move(write_callback);
|
||||
file->m_name = move(name);
|
||||
file->m_metadata.size = 0;
|
||||
file->m_metadata.uid = 0;
|
||||
file->m_metadata.gid = 0;
|
||||
file->m_metadata.mode = mode;
|
||||
file->m_metadata.mtime = mepoch;
|
||||
return file;
|
||||
}
|
||||
|
||||
InodeIdentifier SynthFS::add_file(RetainPtr<SynthFSInode>&& file, InodeIndex parent)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
ASSERT(file);
|
||||
auto it = m_inodes.find(parent);
|
||||
ASSERT(it != m_inodes.end());
|
||||
auto new_inode_id = file->identifier();
|
||||
file->m_metadata.inode = new_inode_id;
|
||||
file->m_parent = { id(), parent };
|
||||
(*it).value->m_children.append(file.ptr());
|
||||
m_inodes.set(new_inode_id.index(), move(file));
|
||||
return new_inode_id;
|
||||
}
|
||||
|
||||
bool SynthFS::remove_file(InodeIndex inode)
|
||||
{
|
||||
ASSERT_INTERRUPTS_DISABLED();
|
||||
auto it = m_inodes.find(inode);
|
||||
if (it == m_inodes.end())
|
||||
return false;
|
||||
auto& file = *(*it).value;
|
||||
|
||||
auto pit = m_inodes.find(file.m_parent.index());
|
||||
if (pit == m_inodes.end())
|
||||
return false;
|
||||
auto& parent = *(*pit).value;
|
||||
for (size_t i = 0; i < parent.m_children.size(); ++i) {
|
||||
if (parent.m_children[i]->m_metadata.inode.index() != inode) {
|
||||
continue;
|
||||
}
|
||||
parent.m_children.remove(i);
|
||||
break;
|
||||
}
|
||||
|
||||
Vector<InodeIndex> indices_to_remove;
|
||||
indices_to_remove.ensure_capacity(file.m_children.size());
|
||||
for (auto& child : file.m_children)
|
||||
indices_to_remove.unchecked_append(child->m_metadata.inode.index());
|
||||
for (auto& index : indices_to_remove)
|
||||
remove_file(index);
|
||||
m_inodes.remove(inode);
|
||||
return true;
|
||||
}
|
||||
|
||||
const char* SynthFS::class_name() const
|
||||
{
|
||||
return "synthfs";
|
||||
}
|
||||
|
||||
InodeIdentifier SynthFS::root_inode() const
|
||||
{
|
||||
return { id(), 1 };
|
||||
}
|
||||
|
||||
RetainPtr<Inode> SynthFS::create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t mode, unsigned size, int& error)
|
||||
{
|
||||
(void) parentInode;
|
||||
(void) name;
|
||||
(void) mode;
|
||||
(void) size;
|
||||
(void) error;
|
||||
kprintf("FIXME: Implement SyntheticFileSystem::create_inode().\n");
|
||||
return { };
|
||||
}
|
||||
|
||||
RetainPtr<Inode> SynthFS::create_directory(InodeIdentifier, const String&, Unix::mode_t, int& error)
|
||||
{
|
||||
error = -EROFS;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto SynthFS::generate_inode_index() -> InodeIndex
|
||||
{
|
||||
return m_next_inode_index++;
|
||||
}
|
||||
|
||||
RetainPtr<Inode> SynthFSInode::parent() const
|
||||
{
|
||||
return fs().get_inode(m_parent);
|
||||
}
|
||||
|
||||
RetainPtr<Inode> SynthFS::get_inode(InodeIdentifier inode) const
|
||||
{
|
||||
auto it = m_inodes.find(inode.index());
|
||||
if (it == m_inodes.end())
|
||||
return { };
|
||||
return (*it).value;
|
||||
}
|
||||
|
||||
SynthFSInode::SynthFSInode(SynthFS& fs, unsigned index)
|
||||
: Inode(fs, index)
|
||||
{
|
||||
m_metadata.inode = { fs.id(), index };
|
||||
}
|
||||
|
||||
SynthFSInode::~SynthFSInode()
|
||||
{
|
||||
}
|
||||
|
||||
InodeMetadata SynthFSInode::metadata() const
|
||||
{
|
||||
return m_metadata;
|
||||
}
|
||||
|
||||
ssize_t SynthFSInode::read_bytes(Unix::off_t offset, size_t count, byte* buffer, FileDescriptor* descriptor)
|
||||
{
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("SynthFS: read_bytes %u\n", index());
|
||||
#endif
|
||||
ASSERT(offset >= 0);
|
||||
ASSERT(buffer);
|
||||
|
||||
ByteBuffer generatedData;
|
||||
if (m_generator) {
|
||||
if (!descriptor) {
|
||||
generatedData = m_generator(*this);
|
||||
} else {
|
||||
if (!descriptor->generator_cache())
|
||||
descriptor->generator_cache() = m_generator(*this);
|
||||
generatedData = descriptor->generator_cache();
|
||||
}
|
||||
}
|
||||
|
||||
auto* data = generatedData ? &generatedData : &m_data;
|
||||
ssize_t nread = min(static_cast<Unix::off_t>(data->size() - offset), static_cast<Unix::off_t>(count));
|
||||
memcpy(buffer, data->pointer() + offset, nread);
|
||||
if (nread == 0 && descriptor && descriptor->generator_cache())
|
||||
descriptor->generator_cache().clear();
|
||||
return nread;
|
||||
}
|
||||
|
||||
bool SynthFSInode::traverse_as_directory(Function<bool(const FS::DirectoryEntry&)> callback)
|
||||
{
|
||||
InterruptDisabler disabler;
|
||||
#ifdef SYNTHFS_DEBUG
|
||||
kprintf("SynthFS: traverse_as_directory %u\n", index());
|
||||
#endif
|
||||
|
||||
if (!m_metadata.isDirectory())
|
||||
return false;
|
||||
|
||||
callback({ ".", 1, m_metadata.inode, 2 });
|
||||
callback({ "..", 2, m_parent, 2 });
|
||||
|
||||
for (auto& child : m_children)
|
||||
callback({ child->m_name.characters(), child->m_name.length(), child->m_metadata.inode, child->m_metadata.isDirectory() ? (byte)2 : (byte)1 });
|
||||
return true;
|
||||
}
|
||||
|
||||
InodeIdentifier SynthFSInode::lookup(const String& name)
|
||||
{
|
||||
ASSERT(is_directory());
|
||||
if (name == ".")
|
||||
return identifier();
|
||||
if (name == "..")
|
||||
return m_parent;
|
||||
for (auto& child : m_children) {
|
||||
if (child->m_name == name)
|
||||
return child->identifier();
|
||||
}
|
||||
return { };
|
||||
}
|
||||
|
||||
String SynthFSInode::reverse_lookup(InodeIdentifier child_id)
|
||||
{
|
||||
ASSERT(is_directory());
|
||||
for (auto& child : m_children) {
|
||||
if (child->identifier() == child_id)
|
||||
return child->m_name;
|
||||
}
|
||||
return { };
|
||||
}
|
||||
|
||||
void SynthFSInode::flush_metadata()
|
||||
{
|
||||
}
|
||||
|
||||
ssize_t SynthFSInode::write_bytes(Unix::off_t offset, size_t size, const byte* buffer, FileDescriptor*)
|
||||
{
|
||||
if (!m_write_callback)
|
||||
return -EPERM;
|
||||
// FIXME: Being able to write into SynthFS at a non-zero offset seems like something we should support..
|
||||
ASSERT(offset == 0);
|
||||
bool success = m_write_callback(*this, ByteBuffer::wrap((byte*)buffer, size));
|
||||
ASSERT(success);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SynthFSInode::add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error)
|
||||
{
|
||||
(void) child_id;
|
||||
(void) name;
|
||||
(void) file_type;
|
||||
(void) error;
|
||||
ASSERT_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SynthFSInode::remove_child(const String& name, int& error)
|
||||
{
|
||||
(void) name;
|
||||
(void) error;
|
||||
ASSERT_NOT_REACHED();
|
||||
return false;
|
||||
}
|
||||
|
||||
SynthFSInodeCustomData::~SynthFSInodeCustomData()
|
||||
{
|
||||
}
|
90
Kernel/SyntheticFileSystem.h
Normal file
90
Kernel/SyntheticFileSystem.h
Normal file
|
@ -0,0 +1,90 @@
|
|||
#pragma once
|
||||
|
||||
#include "FileSystem.h"
|
||||
#include "UnixTypes.h"
|
||||
#include <AK/HashMap.h>
|
||||
|
||||
class SynthFSInode;
|
||||
|
||||
class SynthFS : public FS {
|
||||
public:
|
||||
virtual ~SynthFS() override;
|
||||
static RetainPtr<SynthFS> create();
|
||||
|
||||
virtual bool initialize() override;
|
||||
virtual const char* class_name() const override;
|
||||
virtual InodeIdentifier root_inode() const override;
|
||||
virtual RetainPtr<Inode> create_inode(InodeIdentifier parentInode, const String& name, Unix::mode_t, unsigned size, int& error) override;
|
||||
virtual RetainPtr<Inode> create_directory(InodeIdentifier parentInode, const String& name, Unix::mode_t, int& error) override;
|
||||
virtual RetainPtr<Inode> get_inode(InodeIdentifier) const override;
|
||||
|
||||
protected:
|
||||
typedef unsigned InodeIndex;
|
||||
|
||||
InodeIndex generate_inode_index();
|
||||
static constexpr InodeIndex RootInodeIndex = 1;
|
||||
|
||||
SynthFS();
|
||||
|
||||
RetainPtr<SynthFSInode> create_directory(String&& name);
|
||||
RetainPtr<SynthFSInode> create_text_file(String&& name, ByteBuffer&&, Unix::mode_t = 0010644);
|
||||
RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Unix::mode_t = 0100644);
|
||||
RetainPtr<SynthFSInode> create_generated_file(String&& name, Function<ByteBuffer(SynthFSInode&)>&&, Function<ssize_t(SynthFSInode&, const ByteBuffer&)>&&, Unix::mode_t = 0100644);
|
||||
|
||||
InodeIdentifier add_file(RetainPtr<SynthFSInode>&&, InodeIndex parent = RootInodeIndex);
|
||||
bool remove_file(InodeIndex);
|
||||
|
||||
private:
|
||||
InodeIndex m_next_inode_index { 2 };
|
||||
HashMap<InodeIndex, RetainPtr<SynthFSInode>> m_inodes;
|
||||
};
|
||||
|
||||
struct SynthFSInodeCustomData {
|
||||
virtual ~SynthFSInodeCustomData();
|
||||
};
|
||||
|
||||
class SynthFSInode final : public Inode {
|
||||
friend class SynthFS;
|
||||
public:
|
||||
virtual ~SynthFSInode() override;
|
||||
|
||||
void set_custom_data(OwnPtr<SynthFSInodeCustomData>&& custom_data) { m_custom_data = move(custom_data); }
|
||||
SynthFSInodeCustomData* custom_data() { return m_custom_data.ptr(); }
|
||||
const SynthFSInodeCustomData* custom_data() const { return m_custom_data.ptr(); }
|
||||
|
||||
private:
|
||||
// ^Inode
|
||||
virtual ssize_t read_bytes(Unix::off_t, size_t, byte* buffer, FileDescriptor*) override;
|
||||
virtual InodeMetadata metadata() const override;
|
||||
virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) override;
|
||||
virtual InodeIdentifier lookup(const String& name) override;
|
||||
virtual String reverse_lookup(InodeIdentifier) override;
|
||||
virtual void flush_metadata() override;
|
||||
virtual ssize_t write_bytes(Unix::off_t, size_t, const byte* buffer, FileDescriptor*) override;
|
||||
virtual bool add_child(InodeIdentifier child_id, const String& name, byte file_type, int& error) override;
|
||||
virtual bool remove_child(const String& name, int& error) override;
|
||||
virtual RetainPtr<Inode> parent() const override;
|
||||
|
||||
SynthFS& fs();
|
||||
const SynthFS& fs() const;
|
||||
SynthFSInode(SynthFS&, unsigned index);
|
||||
|
||||
String m_name;
|
||||
InodeIdentifier m_parent;
|
||||
ByteBuffer m_data;
|
||||
Function<ByteBuffer(SynthFSInode&)> m_generator;
|
||||
Function<ssize_t(SynthFSInode&, const ByteBuffer&)> m_write_callback;
|
||||
Vector<SynthFSInode*> m_children;
|
||||
InodeMetadata m_metadata;
|
||||
OwnPtr<SynthFSInodeCustomData> m_custom_data;
|
||||
};
|
||||
|
||||
inline SynthFS& SynthFSInode::fs()
|
||||
{
|
||||
return static_cast<SynthFS&>(Inode::fs());
|
||||
}
|
||||
|
||||
inline const SynthFS& SynthFSInode::fs() const
|
||||
{
|
||||
return static_cast<const SynthFS&>(Inode::fs());
|
||||
}
|
|
@ -1,8 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include "DoubleBuffer.h"
|
||||
#include <VirtualFileSystem/CharacterDevice.h>
|
||||
#include <VirtualFileSystem/UnixTypes.h>
|
||||
#include <Kernel/CharacterDevice.h>
|
||||
#include <Kernel/UnixTypes.h>
|
||||
|
||||
class Process;
|
||||
|
||||
|
|
302
Kernel/UnixTypes.h
Normal file
302
Kernel/UnixTypes.h
Normal file
|
@ -0,0 +1,302 @@
|
|||
#pragma once
|
||||
|
||||
extern "C" {
|
||||
|
||||
#define FD_SETSIZE 64
|
||||
struct fd_set { unsigned char bits[FD_SETSIZE / 8]; };
|
||||
|
||||
namespace Unix {
|
||||
|
||||
#define WNOHANG 1
|
||||
|
||||
#define SIG_DFL ((void*)0)
|
||||
#define SIG_ERR ((void*)-1)
|
||||
#define SIG_IGN ((void*)1)
|
||||
|
||||
#define SEEK_SET 0
|
||||
#define SEEK_CUR 1
|
||||
#define SEEK_END 2
|
||||
|
||||
#define MAP_SHARED 0x01
|
||||
#define MAP_PRIVATE 0x02
|
||||
#define MAP_FIXED 0x10
|
||||
#define MAP_ANONYMOUS 0x20
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
|
||||
#define PROT_READ 0x1
|
||||
#define PROT_WRITE 0x2
|
||||
#define PROT_EXEC 0x4
|
||||
#define PROT_NONE 0x0
|
||||
|
||||
#define F_DUPFD 0
|
||||
#define F_GETFD 1
|
||||
#define F_SETFD 2
|
||||
#define F_GETFL 3
|
||||
#define F_SETFL 4
|
||||
|
||||
#define FD_CLOEXEC 1
|
||||
|
||||
/* c_cc characters */
|
||||
#define VINTR 0
|
||||
#define VQUIT 1
|
||||
#define VERASE 2
|
||||
#define VKILL 3
|
||||
#define VEOF 4
|
||||
#define VTIME 5
|
||||
#define VMIN 6
|
||||
#define VSWTC 7
|
||||
#define VSTART 8
|
||||
#define VSTOP 9
|
||||
#define VSUSP 10
|
||||
#define VEOL 11
|
||||
#define VREPRINT 12
|
||||
#define VDISCARD 13
|
||||
#define VWERASE 14
|
||||
#define VLNEXT 15
|
||||
#define VEOL2 16
|
||||
|
||||
/* c_iflag bits */
|
||||
#define IGNBRK 0000001
|
||||
#define BRKINT 0000002
|
||||
#define IGNPAR 0000004
|
||||
#define PARMRK 0000010
|
||||
#define INPCK 0000020
|
||||
#define ISTRIP 0000040
|
||||
#define INLCR 0000100
|
||||
#define IGNCR 0000200
|
||||
#define ICRNL 0000400
|
||||
#define IUCLC 0001000
|
||||
#define IXON 0002000
|
||||
#define IXANY 0004000
|
||||
#define IXOFF 0010000
|
||||
#define IMAXBEL 0020000
|
||||
#define IUTF8 0040000
|
||||
|
||||
/* c_oflag bits */
|
||||
#define OPOST 0000001
|
||||
#define OLCUC 0000002
|
||||
#define ONLCR 0000004
|
||||
#define OCRNL 0000010
|
||||
#define ONOCR 0000020
|
||||
#define ONLRET 0000040
|
||||
#define OFILL 0000100
|
||||
#define OFDEL 0000200
|
||||
#if defined __USE_MISC || defined __USE_XOPEN
|
||||
# define NLDLY 0000400
|
||||
# define NL0 0000000
|
||||
# define NL1 0000400
|
||||
# define CRDLY 0003000
|
||||
# define CR0 0000000
|
||||
# define CR1 0001000
|
||||
# define CR2 0002000
|
||||
# define CR3 0003000
|
||||
# define TABDLY 0014000
|
||||
# define TAB0 0000000
|
||||
# define TAB1 0004000
|
||||
# define TAB2 0010000
|
||||
# define TAB3 0014000
|
||||
# define BSDLY 0020000
|
||||
# define BS0 0000000
|
||||
# define BS1 0020000
|
||||
# define FFDLY 0100000
|
||||
# define FF0 0000000
|
||||
# define FF1 0100000
|
||||
#endif
|
||||
|
||||
#define VTDLY 0040000
|
||||
#define VT0 0000000
|
||||
#define VT1 0040000
|
||||
|
||||
#ifdef __USE_MISC
|
||||
# define XTABS 0014000
|
||||
#endif
|
||||
|
||||
/* c_cflag bit meaning */
|
||||
#ifdef __USE_MISC
|
||||
# define CBAUD 0010017
|
||||
#endif
|
||||
#define B0 0000000 /* hang up */
|
||||
#define B50 0000001
|
||||
#define B75 0000002
|
||||
#define B110 0000003
|
||||
#define B134 0000004
|
||||
#define B150 0000005
|
||||
#define B200 0000006
|
||||
#define B300 0000007
|
||||
#define B600 0000010
|
||||
#define B1200 0000011
|
||||
#define B1800 0000012
|
||||
#define B2400 0000013
|
||||
#define B4800 0000014
|
||||
#define B9600 0000015
|
||||
#define B19200 0000016
|
||||
#define B38400 0000017
|
||||
#ifdef __USE_MISC
|
||||
# define EXTA B19200
|
||||
# define EXTB B38400
|
||||
#endif
|
||||
#define CSIZE 0000060
|
||||
#define CS5 0000000
|
||||
#define CS6 0000020
|
||||
#define CS7 0000040
|
||||
#define CS8 0000060
|
||||
#define CSTOPB 0000100
|
||||
#define CREAD 0000200
|
||||
#define PARENB 0000400
|
||||
#define PARODD 0001000
|
||||
#define HUPCL 0002000
|
||||
#define CLOCAL 0004000
|
||||
#ifdef __USE_MISC
|
||||
# define CBAUDEX 0010000
|
||||
#endif
|
||||
#define B57600 0010001
|
||||
#define B115200 0010002
|
||||
#define B230400 0010003
|
||||
#define B460800 0010004
|
||||
#define B500000 0010005
|
||||
#define B576000 0010006
|
||||
#define B921600 0010007
|
||||
#define B1000000 0010010
|
||||
#define B1152000 0010011
|
||||
#define B1500000 0010012
|
||||
#define B2000000 0010013
|
||||
#define B2500000 0010014
|
||||
#define B3000000 0010015
|
||||
#define B3500000 0010016
|
||||
#define B4000000 0010017
|
||||
#define __MAX_BAUD B4000000
|
||||
#ifdef __USE_MISC
|
||||
# define CIBAUD 002003600000 /* input baud rate (not used) */
|
||||
# define CMSPAR 010000000000 /* mark or space (stick) parity */
|
||||
# define CRTSCTS 020000000000 /* flow control */
|
||||
#endif
|
||||
|
||||
/* c_lflag bits */
|
||||
#define ISIG 0000001
|
||||
#define ICANON 0000002
|
||||
#if defined __USE_MISC || (defined __USE_XOPEN && !defined __USE_XOPEN2K)
|
||||
# define XCASE 0000004
|
||||
#endif
|
||||
#define ECHO 0000010
|
||||
#define ECHOE 0000020
|
||||
#define ECHOK 0000040
|
||||
#define ECHONL 0000100
|
||||
#define NOFLSH 0000200
|
||||
#define TOSTOP 0000400
|
||||
#ifdef __USE_MISC
|
||||
# define ECHOCTL 0001000
|
||||
# define ECHOPRT 0002000
|
||||
# define ECHOKE 0004000
|
||||
# define FLUSHO 0010000
|
||||
# define PENDIN 0040000
|
||||
#endif
|
||||
#define IEXTEN 0100000
|
||||
#ifdef __USE_MISC
|
||||
# define EXTPROC 0200000
|
||||
#endif
|
||||
|
||||
/* tcflow() and TCXONC use these */
|
||||
#define TCOOFF 0
|
||||
#define TCOON 1
|
||||
#define TCIOFF 2
|
||||
#define TCION 3
|
||||
|
||||
/* tcflush() and TCFLSH use these */
|
||||
#define TCIFLUSH 0
|
||||
#define TCOFLUSH 1
|
||||
#define TCIOFLUSH 2
|
||||
|
||||
/* tcsetattr uses these */
|
||||
#define TCSANOW 0
|
||||
#define TCSADRAIN 1
|
||||
#define TCSAFLUSH 2
|
||||
|
||||
struct winsize {
|
||||
unsigned short ws_row;
|
||||
unsigned short ws_col;
|
||||
};
|
||||
|
||||
typedef dword dev_t;
|
||||
typedef dword ino_t;
|
||||
typedef dword mode_t;
|
||||
typedef dword nlink_t;
|
||||
typedef dword uid_t;
|
||||
typedef dword gid_t;
|
||||
typedef dword clock_t;
|
||||
|
||||
struct tms {
|
||||
clock_t tms_utime;
|
||||
clock_t tms_stime;
|
||||
clock_t tms_cutime;
|
||||
clock_t tms_cstime;
|
||||
};
|
||||
|
||||
typedef void (*__sighandler_t)(int);
|
||||
typedef __sighandler_t sighandler_t;
|
||||
|
||||
typedef dword sigset_t;
|
||||
typedef void siginfo_t;
|
||||
|
||||
struct sigaction {
|
||||
union {
|
||||
void (*sa_handler)(int);
|
||||
void (*sa_sigaction)(int, siginfo_t*, void*);
|
||||
};
|
||||
sigset_t sa_mask;
|
||||
int sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
};
|
||||
|
||||
#define SA_NOCLDSTOP 1
|
||||
#define SA_NOCLDWAIT 2
|
||||
#define SA_SIGINFO 4
|
||||
|
||||
#define SIG_BLOCK 0
|
||||
#define SIG_UNBLOCK 1
|
||||
#define SIG_SETMASK 2
|
||||
|
||||
// FIXME: Support 64-bit offsets!
|
||||
typedef signed_dword off_t;
|
||||
typedef unsigned int time_t;
|
||||
|
||||
struct utimbuf {
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
|
||||
typedef dword blksize_t;
|
||||
typedef dword blkcnt_t;
|
||||
|
||||
#define NCCS 32
|
||||
|
||||
typedef uint32_t tcflag_t;
|
||||
typedef uint8_t cc_t;
|
||||
|
||||
struct termios {
|
||||
tcflag_t c_iflag;
|
||||
tcflag_t c_oflag;
|
||||
tcflag_t c_cflag;
|
||||
tcflag_t c_lflag;
|
||||
cc_t c_cc[NCCS];
|
||||
};
|
||||
|
||||
struct stat {
|
||||
dev_t st_dev; /* ID of device containing file */
|
||||
ino_t st_ino; /* inode number */
|
||||
mode_t st_mode; /* protection */
|
||||
nlink_t st_nlink; /* number of hard links */
|
||||
uid_t st_uid; /* user ID of owner */
|
||||
gid_t st_gid; /* group ID of owner */
|
||||
dev_t st_rdev; /* device ID (if special file) */
|
||||
off_t st_size; /* total size, in bytes */
|
||||
blksize_t st_blksize; /* blocksize for file system I/O */
|
||||
blkcnt_t st_blocks; /* number of 512B blocks allocated */
|
||||
time_t st_atime; /* time of last access */
|
||||
time_t st_mtime; /* time of last modification */
|
||||
time_t st_ctime; /* time of last status change */
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
425
Kernel/VirtualFileSystem.cpp
Normal file
425
Kernel/VirtualFileSystem.cpp
Normal file
|
@ -0,0 +1,425 @@
|
|||
#include "VirtualFileSystem.h"
|
||||
#include "FileDescriptor.h"
|
||||
#include "FileSystem.h"
|
||||
#include <AK/FileSystemPath.h>
|
||||
#include <AK/StringBuilder.h>
|
||||
#include <AK/kmalloc.h>
|
||||
#include <AK/kstdio.h>
|
||||
#include <AK/ktime.h>
|
||||
#include "CharacterDevice.h"
|
||||
#include <LibC/errno_numbers.h>
|
||||
|
||||
//#define VFS_DEBUG
|
||||
|
||||
static VFS* s_the;
|
||||
|
||||
VFS& VFS::the()
|
||||
{
|
||||
ASSERT(s_the);
|
||||
return *s_the;
|
||||
}
|
||||
|
||||
void VFS::initialize_globals()
|
||||
{
|
||||
s_the = nullptr;
|
||||
FS::initialize_globals();
|
||||
}
|
||||
|
||||
VFS::VFS()
|
||||
{
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("VFS: Constructing VFS\n");
|
||||
#endif
|
||||
s_the = this;
|
||||
}
|
||||
|
||||
VFS::~VFS()
|
||||
{
|
||||
}
|
||||
|
||||
InodeIdentifier VFS::root_inode_id() const
|
||||
{
|
||||
ASSERT(m_root_inode);
|
||||
return m_root_inode->identifier();
|
||||
}
|
||||
|
||||
bool VFS::mount(RetainPtr<FS>&& fileSystem, const String& path)
|
||||
{
|
||||
ASSERT(fileSystem);
|
||||
int error;
|
||||
auto inode = resolve_path(path, root_inode_id(), error);
|
||||
if (!inode.is_valid()) {
|
||||
kprintf("VFS: mount can't resolve mount point '%s'\n", path.characters());
|
||||
return false;
|
||||
}
|
||||
|
||||
kprintf("VFS: mounting %s{%p} at %s (inode: %u)\n", fileSystem->class_name(), fileSystem.ptr(), path.characters(), inode.index());
|
||||
// FIXME: check that this is not already a mount point
|
||||
auto mount = make<Mount>(inode, move(fileSystem));
|
||||
m_mounts.append(move(mount));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool VFS::mount_root(RetainPtr<FS>&& fileSystem)
|
||||
{
|
||||
if (m_root_inode) {
|
||||
kprintf("VFS: mount_root can't mount another root\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
auto mount = make<Mount>(InodeIdentifier(), move(fileSystem));
|
||||
|
||||
auto root_inode_id = mount->guest().fs()->root_inode();
|
||||
auto root_inode = mount->guest().fs()->get_inode(root_inode_id);
|
||||
if (!root_inode->is_directory()) {
|
||||
kprintf("VFS: root inode (%02u:%08u) for / is not a directory :(\n", root_inode_id.fsid(), root_inode_id.index());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_root_inode = move(root_inode);
|
||||
|
||||
kprintf("VFS: mounted root on %s{%p}\n",
|
||||
m_root_inode->fs().class_name(),
|
||||
&m_root_inode->fs());
|
||||
|
||||
m_mounts.append(move(mount));
|
||||
return true;
|
||||
}
|
||||
|
||||
auto VFS::find_mount_for_host(InodeIdentifier inode) -> Mount*
|
||||
{
|
||||
for (auto& mount : m_mounts) {
|
||||
if (mount->host() == inode)
|
||||
return mount.ptr();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto VFS::find_mount_for_guest(InodeIdentifier inode) -> Mount*
|
||||
{
|
||||
for (auto& mount : m_mounts) {
|
||||
if (mount->guest() == inode)
|
||||
return mount.ptr();
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool VFS::is_vfs_root(InodeIdentifier inode) const
|
||||
{
|
||||
return inode == root_inode_id();
|
||||
}
|
||||
|
||||
void VFS::traverse_directory_inode(Inode& dir_inode, Function<bool(const FS::DirectoryEntry&)> callback)
|
||||
{
|
||||
dir_inode.traverse_as_directory([&] (const FS::DirectoryEntry& entry) {
|
||||
InodeIdentifier resolvedInode;
|
||||
if (auto mount = find_mount_for_host(entry.inode))
|
||||
resolvedInode = mount->guest();
|
||||
else
|
||||
resolvedInode = entry.inode;
|
||||
|
||||
if (dir_inode.identifier().is_root_inode() && !is_vfs_root(dir_inode.identifier()) && !strcmp(entry.name, "..")) {
|
||||
auto mount = find_mount_for_guest(entry.inode);
|
||||
ASSERT(mount);
|
||||
resolvedInode = mount->host();
|
||||
}
|
||||
callback(FS::DirectoryEntry(entry.name, entry.name_length, resolvedInode, entry.fileType));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> VFS::open(RetainPtr<CharacterDevice>&& device, int& error, int options)
|
||||
{
|
||||
// FIXME: Respect options.
|
||||
(void) options;
|
||||
(void) error;
|
||||
return FileDescriptor::create(move(device));
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base)
|
||||
{
|
||||
auto inode_id = resolve_path(path, base, error, options);
|
||||
auto inode = get_inode(inode_id);
|
||||
if (!inode) {
|
||||
if (options & O_CREAT)
|
||||
return create(path, error, options, mode, base);
|
||||
return nullptr;
|
||||
}
|
||||
auto metadata = inode->metadata();
|
||||
if (metadata.isCharacterDevice()) {
|
||||
auto it = m_character_devices.find(encodedDevice(metadata.majorDevice, metadata.minorDevice));
|
||||
if (it == m_character_devices.end()) {
|
||||
kprintf("VFS::open: no such character device %u,%u\n", metadata.majorDevice, metadata.minorDevice);
|
||||
return nullptr;
|
||||
}
|
||||
return (*it).value->open(error, options);
|
||||
}
|
||||
return FileDescriptor::create(move(inode));
|
||||
}
|
||||
|
||||
RetainPtr<FileDescriptor> VFS::create(const String& path, int& error, int options, mode_t mode, InodeIdentifier base)
|
||||
{
|
||||
(void) options;
|
||||
error = -EWHYTHO;
|
||||
|
||||
if (!isSocket(mode) && !isFIFO(mode) && !isBlockDevice(mode) && !isCharacterDevice(mode)) {
|
||||
// Turn it into a regular file. (This feels rather hackish.)
|
||||
mode |= 0100000;
|
||||
}
|
||||
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
if (!p.is_valid()) {
|
||||
error = -EINVAL;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
InodeIdentifier parent_dir;
|
||||
auto existing_file = resolve_path(path, base, error, 0, &parent_dir);
|
||||
if (existing_file.is_valid()) {
|
||||
error = -EEXIST;
|
||||
return nullptr;
|
||||
}
|
||||
if (!parent_dir.is_valid()) {
|
||||
error = -ENOENT;
|
||||
return nullptr;
|
||||
}
|
||||
if (error != -ENOENT) {
|
||||
return nullptr;
|
||||
}
|
||||
dbgprintf("VFS::create_file: '%s' in %u:%u\n", p.basename().characters(), parent_dir.fsid(), parent_dir.index());
|
||||
auto new_file = parent_dir.fs()->create_inode(parent_dir, p.basename(), mode, 0, error);
|
||||
if (!new_file)
|
||||
return nullptr;
|
||||
|
||||
error = 0;
|
||||
return FileDescriptor::create(move(new_file));
|
||||
}
|
||||
|
||||
bool VFS::mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error)
|
||||
{
|
||||
error = -EWHYTHO;
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
if (!p.is_valid()) {
|
||||
error = -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
InodeIdentifier parent_dir;
|
||||
auto existing_dir = resolve_path(path, base, error, 0, &parent_dir);
|
||||
if (existing_dir.is_valid()) {
|
||||
error = -EEXIST;
|
||||
return false;
|
||||
}
|
||||
if (!parent_dir.is_valid()) {
|
||||
error = -ENOENT;
|
||||
return false;
|
||||
}
|
||||
if (error != -ENOENT) {
|
||||
return false;
|
||||
}
|
||||
dbgprintf("VFS::mkdir: '%s' in %u:%u\n", p.basename().characters(), parent_dir.fsid(), parent_dir.index());
|
||||
auto new_dir = base.fs()->create_directory(parent_dir, p.basename(), mode, error);
|
||||
if (new_dir) {
|
||||
error = 0;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool VFS::unlink(const String& path, Inode& base, int& error)
|
||||
{
|
||||
error = -EWHYTHO;
|
||||
// FIXME: This won't work nicely across mount boundaries.
|
||||
FileSystemPath p(path);
|
||||
if (!p.is_valid()) {
|
||||
error = -EINVAL;
|
||||
return false;
|
||||
}
|
||||
|
||||
InodeIdentifier parent_dir;
|
||||
auto inode_id = resolve_path(path, base.identifier(), error, 0, &parent_dir);
|
||||
if (!inode_id.is_valid()) {
|
||||
error = -ENOENT;
|
||||
return false;
|
||||
}
|
||||
|
||||
auto parent_inode = get_inode(parent_dir);
|
||||
// FIXME: The reverse_lookup here can definitely be avoided.
|
||||
if (!parent_inode->remove_child(parent_inode->reverse_lookup(inode_id), error))
|
||||
return false;
|
||||
|
||||
error = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
InodeIdentifier VFS::resolve_symbolic_link(InodeIdentifier base, Inode& symlink_inode, int& error)
|
||||
{
|
||||
auto symlink_contents = symlink_inode.read_entire();
|
||||
if (!symlink_contents)
|
||||
return { };
|
||||
auto linkee = String((const char*)symlink_contents.pointer(), symlink_contents.size());
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("linkee (%s)(%u) from %u:%u\n", linkee.characters(), linkee.length(), base.fsid(), base.index());
|
||||
#endif
|
||||
return resolve_path(linkee, base, error);
|
||||
}
|
||||
|
||||
RetainPtr<Inode> VFS::get_inode(InodeIdentifier inode_id)
|
||||
{
|
||||
if (!inode_id.is_valid())
|
||||
return nullptr;
|
||||
return inode_id.fs()->get_inode(inode_id);
|
||||
}
|
||||
|
||||
String VFS::absolute_path(Inode& core_inode)
|
||||
{
|
||||
int error;
|
||||
Vector<InodeIdentifier> lineage;
|
||||
RetainPtr<Inode> inode = &core_inode;
|
||||
while (inode->identifier() != root_inode_id()) {
|
||||
if (auto* mount = find_mount_for_guest(inode->identifier()))
|
||||
lineage.append(mount->host());
|
||||
else
|
||||
lineage.append(inode->identifier());
|
||||
|
||||
InodeIdentifier parent_id;
|
||||
if (inode->is_directory()) {
|
||||
parent_id = resolve_path("..", inode->identifier(), error);
|
||||
} else {
|
||||
parent_id = inode->parent()->identifier();
|
||||
}
|
||||
ASSERT(parent_id.is_valid());
|
||||
inode = get_inode(parent_id);
|
||||
}
|
||||
if (lineage.is_empty())
|
||||
return "/";
|
||||
lineage.append(root_inode_id());
|
||||
StringBuilder builder;
|
||||
for (size_t i = lineage.size() - 1; i >= 1; --i) {
|
||||
auto& child = lineage[i - 1];
|
||||
auto parent = lineage[i];
|
||||
if (auto* mount = find_mount_for_host(parent))
|
||||
parent = mount->guest();
|
||||
builder.append('/');
|
||||
auto parent_inode = get_inode(parent);
|
||||
builder.append(parent_inode->reverse_lookup(child));
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
InodeIdentifier VFS::resolve_path(const String& path, InodeIdentifier base, int& error, int options, InodeIdentifier* deepest_dir)
|
||||
{
|
||||
if (path.is_empty()) {
|
||||
error = -EINVAL;
|
||||
return { };
|
||||
}
|
||||
|
||||
auto parts = path.split('/');
|
||||
InodeIdentifier crumb_id;
|
||||
|
||||
if (path[0] == '/')
|
||||
crumb_id = root_inode_id();
|
||||
else
|
||||
crumb_id = base.is_valid() ? base : root_inode_id();
|
||||
|
||||
if (deepest_dir)
|
||||
*deepest_dir = crumb_id;
|
||||
|
||||
for (unsigned i = 0; i < parts.size(); ++i) {
|
||||
bool inode_was_root_at_head_of_loop = crumb_id.is_root_inode();
|
||||
auto& part = parts[i];
|
||||
if (part.is_empty())
|
||||
break;
|
||||
auto crumb_inode = get_inode(crumb_id);
|
||||
if (!crumb_inode) {
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("invalid metadata\n");
|
||||
#endif
|
||||
error = -EIO;
|
||||
return { };
|
||||
}
|
||||
auto metadata = crumb_inode->metadata();
|
||||
if (!metadata.isDirectory()) {
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("parent of <%s> not directory, it's inode %u:%u / %u:%u, mode: %u, size: %u\n", part.characters(), inode.fsid(), inode.index(), metadata.inode.fsid(), metadata.inode.index(), metadata.mode, metadata.size);
|
||||
#endif
|
||||
error = -ENOTDIR;
|
||||
return { };
|
||||
}
|
||||
auto parent = crumb_id;
|
||||
crumb_id = crumb_inode->lookup(part);
|
||||
if (!crumb_id.is_valid()) {
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("child <%s>(%u) not found in directory, %02u:%08u\n", part.characters(), part.length(), parent.fsid(), parent.index());
|
||||
#endif
|
||||
error = -ENOENT;
|
||||
return { };
|
||||
}
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf("<%s> %u:%u\n", part.characters(), inode.fsid(), inode.index());
|
||||
#endif
|
||||
if (auto mount = find_mount_for_host(crumb_id)) {
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf(" -- is host\n");
|
||||
#endif
|
||||
crumb_id = mount->guest();
|
||||
}
|
||||
if (inode_was_root_at_head_of_loop && crumb_id.is_root_inode() && !is_vfs_root(crumb_id) && part == "..") {
|
||||
#ifdef VFS_DEBUG
|
||||
kprintf(" -- is guest\n");
|
||||
#endif
|
||||
auto mount = find_mount_for_guest(crumb_id);
|
||||
auto dir_inode = get_inode(mount->host());
|
||||
crumb_id = dir_inode->lookup("..");
|
||||
}
|
||||
crumb_inode = get_inode(crumb_id);
|
||||
metadata = crumb_inode->metadata();
|
||||
if (metadata.isDirectory()) {
|
||||
if (deepest_dir)
|
||||
*deepest_dir = crumb_id;
|
||||
}
|
||||
if (metadata.isSymbolicLink()) {
|
||||
if (i == parts.size() - 1) {
|
||||
if (options & O_NOFOLLOW) {
|
||||
error = -ELOOP;
|
||||
return { };
|
||||
}
|
||||
if (options & O_NOFOLLOW_NOERROR)
|
||||
return crumb_id;
|
||||
}
|
||||
crumb_id = resolve_symbolic_link(parent, *crumb_inode, error);
|
||||
if (!crumb_id.is_valid()) {
|
||||
kprintf("Symbolic link resolution failed :(\n");
|
||||
return { };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return crumb_id;
|
||||
}
|
||||
|
||||
VFS::Mount::Mount(InodeIdentifier host, RetainPtr<FS>&& guest_fs)
|
||||
: m_host(host)
|
||||
, m_guest(guest_fs->root_inode())
|
||||
, m_guest_fs(move(guest_fs))
|
||||
{
|
||||
}
|
||||
|
||||
void VFS::register_character_device(CharacterDevice& device)
|
||||
{
|
||||
m_character_devices.set(encodedDevice(device.major(), device.minor()), &device);
|
||||
}
|
||||
|
||||
void VFS::for_each_mount(Function<void(const Mount&)> callback) const
|
||||
{
|
||||
for (auto& mount : m_mounts) {
|
||||
callback(*mount);
|
||||
}
|
||||
}
|
||||
|
||||
void VFS::sync()
|
||||
{
|
||||
FS::sync();
|
||||
}
|
103
Kernel/VirtualFileSystem.h
Normal file
103
Kernel/VirtualFileSystem.h
Normal file
|
@ -0,0 +1,103 @@
|
|||
#pragma once
|
||||
|
||||
#include <AK/HashMap.h>
|
||||
#include <AK/OwnPtr.h>
|
||||
#include <AK/RetainPtr.h>
|
||||
#include <AK/AKString.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <AK/Function.h>
|
||||
#include "InodeIdentifier.h"
|
||||
#include "InodeMetadata.h"
|
||||
#include "Limits.h"
|
||||
#include "FileSystem.h"
|
||||
|
||||
#define O_RDONLY 0
|
||||
#define O_WRONLY 1
|
||||
#define O_RDWR 2
|
||||
#define O_CREAT 0100
|
||||
#define O_EXCL 0200
|
||||
#define O_NOCTTY 0400
|
||||
#define O_TRUNC 01000
|
||||
#define O_APPEND 02000
|
||||
#define O_NONBLOCK 04000
|
||||
#define O_DIRECTORY 00200000
|
||||
#define O_NOFOLLOW 00400000
|
||||
#define O_CLOEXEC 02000000
|
||||
#define O_NOFOLLOW_NOERROR 0x4000000
|
||||
|
||||
class CharacterDevice;
|
||||
class FileDescriptor;
|
||||
|
||||
inline constexpr dword encodedDevice(unsigned major, unsigned minor)
|
||||
{
|
||||
return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12);
|
||||
}
|
||||
|
||||
class VFS;
|
||||
|
||||
class VFS {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
static void initialize_globals();
|
||||
|
||||
class Mount {
|
||||
public:
|
||||
Mount(InodeIdentifier host, RetainPtr<FS>&&);
|
||||
|
||||
InodeIdentifier host() const { return m_host; }
|
||||
InodeIdentifier guest() const { return m_guest; }
|
||||
|
||||
const FS& guest_fs() const { return *m_guest_fs; }
|
||||
|
||||
private:
|
||||
InodeIdentifier m_host;
|
||||
InodeIdentifier m_guest;
|
||||
RetainPtr<FS> m_guest_fs;
|
||||
};
|
||||
|
||||
static VFS& the() PURE;
|
||||
|
||||
VFS();
|
||||
~VFS();
|
||||
|
||||
bool mount_root(RetainPtr<FS>&&);
|
||||
bool mount(RetainPtr<FS>&&, const String& path);
|
||||
|
||||
RetainPtr<FileDescriptor> open(RetainPtr<CharacterDevice>&&, int& error, int options);
|
||||
RetainPtr<FileDescriptor> open(const String& path, int& error, int options, mode_t mode, InodeIdentifier base = InodeIdentifier());
|
||||
RetainPtr<FileDescriptor> create(const String& path, int& error, int options, mode_t mode, InodeIdentifier base);
|
||||
bool mkdir(const String& path, mode_t mode, InodeIdentifier base, int& error);
|
||||
bool unlink(const String& path, Inode& base, int& error);
|
||||
|
||||
void register_character_device(CharacterDevice&);
|
||||
|
||||
size_t mount_count() const { return m_mounts.size(); }
|
||||
void for_each_mount(Function<void(const Mount&)>) const;
|
||||
|
||||
String absolute_path(Inode&);
|
||||
|
||||
InodeIdentifier root_inode_id() const;
|
||||
Inode* root_inode() { return m_root_inode.ptr(); }
|
||||
const Inode* root_inode() const { return m_root_inode.ptr(); }
|
||||
|
||||
void sync();
|
||||
|
||||
private:
|
||||
friend class FileDescriptor;
|
||||
|
||||
RetainPtr<Inode> get_inode(InodeIdentifier);
|
||||
|
||||
bool is_vfs_root(InodeIdentifier) const;
|
||||
|
||||
void traverse_directory_inode(Inode&, Function<bool(const FS::DirectoryEntry&)>);
|
||||
InodeIdentifier resolve_path(const String& path, InodeIdentifier base, int& error, int options = 0, InodeIdentifier* deepest_dir = nullptr);
|
||||
InodeIdentifier resolve_symbolic_link(InodeIdentifier base, Inode& symlink_inode, int& error);
|
||||
|
||||
Mount* find_mount_for_host(InodeIdentifier);
|
||||
Mount* find_mount_for_guest(InodeIdentifier);
|
||||
|
||||
RetainPtr<Inode> m_root_inode;
|
||||
Vector<OwnPtr<Mount>> m_mounts;
|
||||
HashMap<dword, CharacterDevice*> m_character_devices;
|
||||
};
|
||||
|
31
Kernel/ZeroDevice.cpp
Normal file
31
Kernel/ZeroDevice.cpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#include "ZeroDevice.h"
|
||||
#include "Limits.h"
|
||||
#include <AK/StdLibExtras.h>
|
||||
#include <AK/kstdio.h>
|
||||
|
||||
ZeroDevice::ZeroDevice()
|
||||
: CharacterDevice(1, 5)
|
||||
{
|
||||
}
|
||||
|
||||
ZeroDevice::~ZeroDevice()
|
||||
{
|
||||
}
|
||||
|
||||
bool ZeroDevice::can_read(Process&) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
ssize_t ZeroDevice::read(Process&, byte* buffer, size_t bufferSize)
|
||||
{
|
||||
size_t count = min(GoodBufferSize, bufferSize);
|
||||
memset(buffer, 0, count);
|
||||
return count;
|
||||
}
|
||||
|
||||
ssize_t ZeroDevice::write(Process&, const byte*, size_t bufferSize)
|
||||
{
|
||||
return min(GoodBufferSize, bufferSize);
|
||||
}
|
||||
|
19
Kernel/ZeroDevice.h
Normal file
19
Kernel/ZeroDevice.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "CharacterDevice.h"
|
||||
|
||||
class ZeroDevice final : public CharacterDevice {
|
||||
AK_MAKE_ETERNAL
|
||||
public:
|
||||
ZeroDevice();
|
||||
virtual ~ZeroDevice() override;
|
||||
|
||||
private:
|
||||
// ^CharacterDevice
|
||||
virtual ssize_t read(Process&, byte* buffer, size_t bufferSize) override;
|
||||
virtual ssize_t write(Process&, const byte* buffer, size_t bufferSize) override;
|
||||
virtual bool can_read(Process&) const override;
|
||||
virtual bool can_write(Process&) const override { return true; }
|
||||
virtual const char* class_name() const override { return "ZeroDevice"; }
|
||||
};
|
||||
|
750
Kernel/ext2_fs.h
Normal file
750
Kernel/ext2_fs.h
Normal file
|
@ -0,0 +1,750 @@
|
|||
/*
|
||||
* linux/include/linux/ext2_fs.h
|
||||
*
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
*
|
||||
* from
|
||||
*
|
||||
* linux/include/linux/minix_fs.h
|
||||
*
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*/
|
||||
|
||||
#ifndef _LINUX_EXT2_FS_H
|
||||
#define _LINUX_EXT2_FS_H
|
||||
|
||||
#include "ext2_types.h" /* Changed from linux/types.h */
|
||||
|
||||
/*
|
||||
* The second extended filesystem constants/structures
|
||||
*/
|
||||
|
||||
/*
|
||||
* Define EXT2FS_DEBUG to produce debug messages
|
||||
*/
|
||||
#undef EXT2FS_DEBUG
|
||||
|
||||
/*
|
||||
* Define EXT2_PREALLOCATE to preallocate data blocks for expanding files
|
||||
*/
|
||||
#define EXT2_PREALLOCATE
|
||||
#define EXT2_DEFAULT_PREALLOC_BLOCKS 8
|
||||
|
||||
/*
|
||||
* The second extended file system version
|
||||
*/
|
||||
#define EXT2FS_DATE "95/08/09"
|
||||
#define EXT2FS_VERSION "0.5b"
|
||||
|
||||
/*
|
||||
* Special inode numbers
|
||||
*/
|
||||
#define EXT2_BAD_INO 1 /* Bad blocks inode */
|
||||
#define EXT2_ROOT_INO 2 /* Root inode */
|
||||
#define EXT2_ACL_IDX_INO 3 /* ACL inode */
|
||||
#define EXT2_ACL_DATA_INO 4 /* ACL inode */
|
||||
#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */
|
||||
#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */
|
||||
#define EXT2_RESIZE_INO 7 /* Reserved group descriptors inode */
|
||||
#define EXT2_JOURNAL_INO 8 /* Journal inode */
|
||||
|
||||
/* First non-reserved inode for old ext2 filesystems */
|
||||
#define EXT2_GOOD_OLD_FIRST_INO 11
|
||||
|
||||
/*
|
||||
* The second extended file system magic number
|
||||
*/
|
||||
#define EXT2_SUPER_MAGIC 0xEF53
|
||||
|
||||
#ifdef __KERNEL__
|
||||
#define EXT2_SB(sb) (&((sb)->u.ext2_sb))
|
||||
#else
|
||||
/* Assume that user mode programs are passing in an ext2fs superblock, not
|
||||
* a kernel struct super_block. This will allow us to call the feature-test
|
||||
* macros from user land. */
|
||||
#define EXT2_SB(sb) (sb)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Maximal count of links to a file
|
||||
*/
|
||||
#define EXT2_LINK_MAX 65000
|
||||
|
||||
/*
|
||||
* Macro-instructions used to manage several block sizes
|
||||
*/
|
||||
#define EXT2_MIN_BLOCK_LOG_SIZE 10 /* 1024 */
|
||||
#define EXT2_MAX_BLOCK_LOG_SIZE 16 /* 65536 */
|
||||
#define EXT2_MIN_BLOCK_SIZE (1 << EXT2_MIN_BLOCK_LOG_SIZE)
|
||||
#define EXT2_MAX_BLOCK_SIZE (1 << EXT2_MAX_BLOCK_LOG_SIZE)
|
||||
#ifdef __KERNEL__
|
||||
#define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize)
|
||||
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits)
|
||||
#define EXT2_ADDR_PER_BLOCK_BITS(s) (EXT2_SB(s)->addr_per_block_bits)
|
||||
#define EXT2_INODE_SIZE(s) (EXT2_SB(s)->s_inode_size)
|
||||
#define EXT2_FIRST_INO(s) (EXT2_SB(s)->s_first_ino)
|
||||
#else
|
||||
#define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size)
|
||||
#define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10)
|
||||
#define EXT2_INODE_SIZE(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
|
||||
EXT2_GOOD_OLD_INODE_SIZE : (s)->s_inode_size)
|
||||
#define EXT2_FIRST_INO(s) (((s)->s_rev_level == EXT2_GOOD_OLD_REV) ? \
|
||||
EXT2_GOOD_OLD_FIRST_INO : (s)->s_first_ino)
|
||||
#endif
|
||||
#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof(__u32))
|
||||
|
||||
/*
|
||||
* Macro-instructions used to manage fragments
|
||||
*/
|
||||
#define EXT2_MIN_FRAG_SIZE EXT2_MIN_BLOCK_SIZE
|
||||
#define EXT2_MAX_FRAG_SIZE EXT2_MAX_BLOCK_SIZE
|
||||
#define EXT2_MIN_FRAG_LOG_SIZE EXT2_MIN_BLOCK_LOG_SIZE
|
||||
#ifdef __KERNEL__
|
||||
# define EXT2_FRAG_SIZE(s) (EXT2_SB(s)->s_frag_size)
|
||||
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_SB(s)->s_frags_per_block)
|
||||
#else
|
||||
# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size)
|
||||
# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* ACL structures
|
||||
*/
|
||||
struct ext2_acl_header /* Header of Access Control Lists */
|
||||
{
|
||||
__u32 aclh_size;
|
||||
__u32 aclh_file_count;
|
||||
__u32 aclh_acle_count;
|
||||
__u32 aclh_first_acle;
|
||||
};
|
||||
|
||||
struct ext2_acl_entry /* Access Control List Entry */
|
||||
{
|
||||
__u32 acle_size;
|
||||
__u16 acle_perms; /* Access permissions */
|
||||
__u16 acle_type; /* Type of entry */
|
||||
__u16 acle_tag; /* User or group identity */
|
||||
__u16 acle_pad1;
|
||||
__u32 acle_next; /* Pointer on next entry for the */
|
||||
/* same inode or on next free entry */
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of a blocks group descriptor
|
||||
*/
|
||||
struct ext2_group_desc
|
||||
{
|
||||
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||||
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||||
__u32 bg_inode_table; /* Inodes table block */
|
||||
__u16 bg_free_blocks_count; /* Free blocks count */
|
||||
__u16 bg_free_inodes_count; /* Free inodes count */
|
||||
__u16 bg_used_dirs_count; /* Directories count */
|
||||
__u16 bg_flags;
|
||||
__u32 bg_reserved[2];
|
||||
__u16 bg_itable_unused; /* Unused inodes count */
|
||||
__u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/
|
||||
};
|
||||
|
||||
struct ext4_group_desc
|
||||
{
|
||||
__u32 bg_block_bitmap; /* Blocks bitmap block */
|
||||
__u32 bg_inode_bitmap; /* Inodes bitmap block */
|
||||
__u32 bg_inode_table; /* Inodes table block */
|
||||
__u16 bg_free_blocks_count; /* Free blocks count */
|
||||
__u16 bg_free_inodes_count; /* Free inodes count */
|
||||
__u16 bg_used_dirs_count; /* Directories count */
|
||||
__u16 bg_flags;
|
||||
__u32 bg_reserved[2];
|
||||
__u16 bg_itable_unused; /* Unused inodes count */
|
||||
__u16 bg_checksum; /* crc16(s_uuid+grouo_num+group_desc)*/
|
||||
__u32 bg_block_bitmap_hi; /* Blocks bitmap block MSB */
|
||||
__u32 bg_inode_bitmap_hi; /* Inodes bitmap block MSB */
|
||||
__u32 bg_inode_table_hi; /* Inodes table block MSB */
|
||||
__u16 bg_free_blocks_count_hi;/* Free blocks count MSB */
|
||||
__u16 bg_free_inodes_count_hi;/* Free inodes count MSB */
|
||||
__u16 bg_used_dirs_count_hi; /* Directories count MSB */
|
||||
__u16 bg_pad;
|
||||
__u32 bg_reserved2[3];
|
||||
};
|
||||
|
||||
#define EXT2_BG_INODE_UNINIT 0x0001 /* Inode table/bitmap not initialized */
|
||||
#define EXT2_BG_BLOCK_UNINIT 0x0002 /* Block bitmap not initialized */
|
||||
#define EXT2_BG_INODE_ZEROED 0x0004 /* On-disk itable initialized to zero */
|
||||
|
||||
/*
|
||||
* Data structures used by the directory indexing feature
|
||||
*
|
||||
* Note: all of the multibyte integer fields are little endian.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note: dx_root_info is laid out so that if it should somehow get
|
||||
* overlaid by a dirent the two low bits of the hash version will be
|
||||
* zero. Therefore, the hash version mod 4 should never be 0.
|
||||
* Sincerely, the paranoia department.
|
||||
*/
|
||||
struct ext2_dx_root_info {
|
||||
__u32 reserved_zero;
|
||||
__u8 hash_version; /* 0 now, 1 at release */
|
||||
__u8 info_length; /* 8 */
|
||||
__u8 indirect_levels;
|
||||
__u8 unused_flags;
|
||||
};
|
||||
|
||||
#define EXT2_HASH_LEGACY 0
|
||||
#define EXT2_HASH_HALF_MD4 1
|
||||
#define EXT2_HASH_TEA 2
|
||||
#define EXT2_HASH_LEGACY_UNSIGNED 3 /* reserved for userspace lib */
|
||||
#define EXT2_HASH_HALF_MD4_UNSIGNED 4 /* reserved for userspace lib */
|
||||
#define EXT2_HASH_TEA_UNSIGNED 5 /* reserved for userspace lib */
|
||||
|
||||
#define EXT2_HASH_FLAG_INCOMPAT 0x1
|
||||
|
||||
struct ext2_dx_entry {
|
||||
__u32 hash;
|
||||
__u32 block;
|
||||
};
|
||||
|
||||
struct ext2_dx_countlimit {
|
||||
__u16 limit;
|
||||
__u16 count;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* Macro-instructions used to manage group descriptors
|
||||
*/
|
||||
#define EXT2_MIN_DESC_SIZE 32
|
||||
#define EXT2_MIN_DESC_SIZE_64BIT 64
|
||||
#define EXT2_MAX_DESC_SIZE EXT2_MIN_BLOCK_SIZE
|
||||
#define EXT2_DESC_SIZE(s) \
|
||||
((EXT2_SB(s)->s_feature_incompat & EXT4_FEATURE_INCOMPAT_64BIT) ? \
|
||||
(s)->s_desc_size : EXT2_MIN_DESC_SIZE)
|
||||
|
||||
#define EXT2_BLOCKS_PER_GROUP(s) (EXT2_SB(s)->s_blocks_per_group)
|
||||
#define EXT2_INODES_PER_GROUP(s) (EXT2_SB(s)->s_inodes_per_group)
|
||||
#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s)/EXT2_INODE_SIZE(s))
|
||||
/* limits imposed by 16-bit value gd_free_{blocks,inode}_count */
|
||||
#define EXT2_MAX_BLOCKS_PER_GROUP(s) ((1 << 16) - 8)
|
||||
#define EXT2_MAX_INODES_PER_GROUP(s) ((1 << 16) - EXT2_INODES_PER_BLOCK(s))
|
||||
#ifdef __KERNEL__
|
||||
#define EXT2_DESC_PER_BLOCK(s) (EXT2_SB(s)->s_desc_per_block)
|
||||
#define EXT2_DESC_PER_BLOCK_BITS(s) (EXT2_SB(s)->s_desc_per_block_bits)
|
||||
#else
|
||||
#define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_DESC_SIZE(s))
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Constants relative to the data blocks
|
||||
*/
|
||||
#define EXT2_NDIR_BLOCKS 12
|
||||
#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS
|
||||
#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1)
|
||||
#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1)
|
||||
#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1)
|
||||
|
||||
/*
|
||||
* Inode flags
|
||||
*/
|
||||
#define EXT2_SECRM_FL 0x00000001 /* Secure deletion */
|
||||
#define EXT2_UNRM_FL 0x00000002 /* Undelete */
|
||||
#define EXT2_COMPR_FL 0x00000004 /* Compress file */
|
||||
#define EXT2_SYNC_FL 0x00000008 /* Synchronous updates */
|
||||
#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
|
||||
#define EXT2_APPEND_FL 0x00000020 /* writes to file may only append */
|
||||
#define EXT2_NODUMP_FL 0x00000040 /* do not dump file */
|
||||
#define EXT2_NOATIME_FL 0x00000080 /* do not update atime */
|
||||
/* Reserved for compression usage... */
|
||||
#define EXT2_DIRTY_FL 0x00000100
|
||||
#define EXT2_COMPRBLK_FL 0x00000200 /* One or more compressed clusters */
|
||||
#define EXT2_NOCOMPR_FL 0x00000400 /* Access raw compressed data */
|
||||
#define EXT2_ECOMPR_FL 0x00000800 /* Compression error */
|
||||
/* End compression flags --- maybe not all used */
|
||||
#define EXT2_BTREE_FL 0x00001000 /* btree format dir */
|
||||
#define EXT2_INDEX_FL 0x00001000 /* hash-indexed directory */
|
||||
#define EXT2_IMAGIC_FL 0x00002000
|
||||
#define EXT3_JOURNAL_DATA_FL 0x00004000 /* file data should be journaled */
|
||||
#define EXT2_NOTAIL_FL 0x00008000 /* file tail should not be merged */
|
||||
#define EXT2_DIRSYNC_FL 0x00010000 /* Synchronous directory modifications */
|
||||
#define EXT2_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/
|
||||
#define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */
|
||||
#define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */
|
||||
#define EXT2_RESERVED_FL 0x80000000 /* reserved for ext2 lib */
|
||||
|
||||
#define EXT2_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */
|
||||
#define EXT2_FL_USER_MODIFIABLE 0x000080FF /* User modifiable flags */
|
||||
|
||||
/*
|
||||
* ioctl commands
|
||||
*/
|
||||
|
||||
/* Used for online resize */
|
||||
struct ext2_new_group_input {
|
||||
__u32 group; /* Group number for this data */
|
||||
__u32 block_bitmap; /* Absolute block number of block bitmap */
|
||||
__u32 inode_bitmap; /* Absolute block number of inode bitmap */
|
||||
__u32 inode_table; /* Absolute block number of inode table start */
|
||||
__u32 blocks_count; /* Total number of blocks in this group */
|
||||
__u16 reserved_blocks; /* Number of reserved blocks in this group */
|
||||
__u16 unused; /* Number of reserved GDT blocks in group */
|
||||
};
|
||||
|
||||
struct ext4_new_group_input {
|
||||
__u32 group; /* Group number for this data */
|
||||
__u64 block_bitmap; /* Absolute block number of block bitmap */
|
||||
__u64 inode_bitmap; /* Absolute block number of inode bitmap */
|
||||
__u64 inode_table; /* Absolute block number of inode table start */
|
||||
__u32 blocks_count; /* Total number of blocks in this group */
|
||||
__u16 reserved_blocks; /* Number of reserved blocks in this group */
|
||||
__u16 unused;
|
||||
};
|
||||
|
||||
#ifdef __GNU__ /* Needed for the Hurd */
|
||||
#define _IOT_ext2_new_group_input _IOT (_IOTS(__u32), 5, _IOTS(__u16), 2, 0, 0)
|
||||
#endif
|
||||
|
||||
#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
|
||||
#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
|
||||
#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
|
||||
#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
|
||||
#define EXT2_IOC_GETVERSION_NEW _IOR('f', 3, long)
|
||||
#define EXT2_IOC_SETVERSION_NEW _IOW('f', 4, long)
|
||||
#define EXT2_IOC_GROUP_EXTEND _IOW('f', 7, unsigned long)
|
||||
#define EXT2_IOC_GROUP_ADD _IOW('f', 8,struct ext2_new_group_input)
|
||||
#define EXT4_IOC_GROUP_ADD _IOW('f', 8,struct ext4_new_group_input)
|
||||
|
||||
/*
|
||||
* Structure of an inode on the disk
|
||||
*/
|
||||
struct ext2_inode {
|
||||
__u16 i_mode; /* File mode */
|
||||
__u16 i_uid; /* Low 16 bits of Owner Uid */
|
||||
__u32 i_size; /* Size in bytes */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* Inode change time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* Deletion Time */
|
||||
__u16 i_gid; /* Low 16 bits of Group Id */
|
||||
__u16 i_links_count; /* Links count */
|
||||
__u32 i_blocks; /* Blocks count */
|
||||
__u32 i_flags; /* File flags */
|
||||
union {
|
||||
struct {
|
||||
__u32 l_i_version; /* was l_i_reserved1 */
|
||||
} linux1;
|
||||
struct {
|
||||
__u32 h_i_translator;
|
||||
} hurd1;
|
||||
} osd1; /* OS dependent 1 */
|
||||
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||||
__u32 i_generation; /* File version (for NFS) */
|
||||
__u32 i_file_acl; /* File ACL */
|
||||
__u32 i_dir_acl; /* Directory ACL */
|
||||
__u32 i_faddr; /* Fragment address */
|
||||
union {
|
||||
struct {
|
||||
__u16 l_i_blocks_hi;
|
||||
__u16 l_i_file_acl_high;
|
||||
__u16 l_i_uid_high; /* these 2 fields */
|
||||
__u16 l_i_gid_high; /* were reserved2[0] */
|
||||
__u32 l_i_reserved2;
|
||||
} linux2;
|
||||
struct {
|
||||
__u8 h_i_frag; /* Fragment number */
|
||||
__u8 h_i_fsize; /* Fragment size */
|
||||
__u16 h_i_mode_high;
|
||||
__u16 h_i_uid_high;
|
||||
__u16 h_i_gid_high;
|
||||
__u32 h_i_author;
|
||||
} hurd2;
|
||||
} osd2; /* OS dependent 2 */
|
||||
};
|
||||
|
||||
/*
|
||||
* Permanent part of an large inode on the disk
|
||||
*/
|
||||
struct ext2_inode_large {
|
||||
__u16 i_mode; /* File mode */
|
||||
__u16 i_uid; /* Low 16 bits of Owner Uid */
|
||||
__u32 i_size; /* Size in bytes */
|
||||
__u32 i_atime; /* Access time */
|
||||
__u32 i_ctime; /* Inode Change time */
|
||||
__u32 i_mtime; /* Modification time */
|
||||
__u32 i_dtime; /* Deletion Time */
|
||||
__u16 i_gid; /* Low 16 bits of Group Id */
|
||||
__u16 i_links_count; /* Links count */
|
||||
__u32 i_blocks; /* Blocks count */
|
||||
__u32 i_flags; /* File flags */
|
||||
union {
|
||||
struct {
|
||||
__u32 l_i_version; /* was l_i_reserved1 */
|
||||
} linux1;
|
||||
struct {
|
||||
__u32 h_i_translator;
|
||||
} hurd1;
|
||||
} osd1; /* OS dependent 1 */
|
||||
__u32 i_block[EXT2_N_BLOCKS];/* Pointers to blocks */
|
||||
__u32 i_generation; /* File version (for NFS) */
|
||||
__u32 i_file_acl; /* File ACL */
|
||||
__u32 i_dir_acl; /* Directory ACL */
|
||||
__u32 i_faddr; /* Fragment address */
|
||||
union {
|
||||
struct {
|
||||
__u16 l_i_blocks_hi;
|
||||
__u16 l_i_file_acl_high;
|
||||
__u16 l_i_uid_high; /* these 2 fields */
|
||||
__u16 l_i_gid_high; /* were reserved2[0] */
|
||||
__u32 l_i_reserved2;
|
||||
} linux2;
|
||||
struct {
|
||||
__u8 h_i_frag; /* Fragment number */
|
||||
__u8 h_i_fsize; /* Fragment size */
|
||||
__u16 h_i_mode_high;
|
||||
__u16 h_i_uid_high;
|
||||
__u16 h_i_gid_high;
|
||||
__u32 h_i_author;
|
||||
} hurd2;
|
||||
} osd2; /* OS dependent 2 */
|
||||
__u16 i_extra_isize;
|
||||
__u16 i_pad1;
|
||||
__u32 i_ctime_extra; /* extra Change time (nsec << 2 | epoch) */
|
||||
__u32 i_mtime_extra; /* extra Modification time (nsec << 2 | epoch) */
|
||||
__u32 i_atime_extra; /* extra Access time (nsec << 2 | epoch) */
|
||||
__u32 i_crtime; /* File creation time */
|
||||
__u32 i_crtime_extra; /* extra File creation time (nsec << 2 | epoch)*/
|
||||
__u32 i_version_hi; /* high 32 bits for 64-bit version */
|
||||
};
|
||||
|
||||
#define i_size_high i_dir_acl
|
||||
|
||||
#if defined(__KERNEL__) || defined(__linux__)
|
||||
#define i_reserved1 osd1.linux1.l_i_reserved1
|
||||
#define i_frag osd2.linux2.l_i_frag
|
||||
#define i_fsize osd2.linux2.l_i_fsize
|
||||
#define i_uid_low i_uid
|
||||
#define i_gid_low i_gid
|
||||
#define i_uid_high osd2.linux2.l_i_uid_high
|
||||
#define i_gid_high osd2.linux2.l_i_gid_high
|
||||
#define i_reserved2 osd2.linux2.l_i_reserved2
|
||||
#else
|
||||
#if defined(__GNU__)
|
||||
|
||||
#define i_translator osd1.hurd1.h_i_translator
|
||||
#define i_frag osd2.hurd2.h_i_frag;
|
||||
#define i_fsize osd2.hurd2.h_i_fsize;
|
||||
#define i_uid_high osd2.hurd2.h_i_uid_high
|
||||
#define i_gid_high osd2.hurd2.h_i_gid_high
|
||||
#define i_author osd2.hurd2.h_i_author
|
||||
|
||||
#endif /* __GNU__ */
|
||||
#endif /* defined(__KERNEL__) || defined(__linux__) */
|
||||
|
||||
#define inode_uid(inode) ((inode).i_uid | (inode).osd2.linux2.l_i_uid_high << 16)
|
||||
#define inode_gid(inode) ((inode).i_gid | (inode).osd2.linux2.l_i_gid_high << 16)
|
||||
#define ext2fs_set_i_uid_high(inode,x) ((inode).osd2.linux2.l_i_uid_high = (x))
|
||||
#define ext2fs_set_i_gid_high(inode,x) ((inode).osd2.linux2.l_i_gid_high = (x))
|
||||
|
||||
/*
|
||||
* File system states
|
||||
*/
|
||||
#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */
|
||||
#define EXT2_ERROR_FS 0x0002 /* Errors detected */
|
||||
#define EXT3_ORPHAN_FS 0x0004 /* Orphans being recovered */
|
||||
|
||||
/*
|
||||
* Misc. filesystem flags
|
||||
*/
|
||||
#define EXT2_FLAGS_SIGNED_HASH 0x0001 /* Signed dirhash in use */
|
||||
#define EXT2_FLAGS_UNSIGNED_HASH 0x0002 /* Unsigned dirhash in use */
|
||||
#define EXT2_FLAGS_TEST_FILESYS 0x0004 /* OK for use on development code */
|
||||
|
||||
/*
|
||||
* Mount flags
|
||||
*/
|
||||
#define EXT2_MOUNT_CHECK 0x0001 /* Do mount-time checks */
|
||||
#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */
|
||||
#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */
|
||||
#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */
|
||||
#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */
|
||||
#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */
|
||||
#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */
|
||||
#define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */
|
||||
|
||||
#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt
|
||||
#define set_opt(o, opt) o |= EXT2_MOUNT_##opt
|
||||
#define test_opt(sb, opt) (EXT2_SB(sb)->s_mount_opt & \
|
||||
EXT2_MOUNT_##opt)
|
||||
/*
|
||||
* Maximal mount counts between two filesystem checks
|
||||
*/
|
||||
#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */
|
||||
#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */
|
||||
|
||||
/*
|
||||
* Behaviour when detecting errors
|
||||
*/
|
||||
#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */
|
||||
#define EXT2_ERRORS_RO 2 /* Remount fs read-only */
|
||||
#define EXT2_ERRORS_PANIC 3 /* Panic */
|
||||
#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE
|
||||
|
||||
/*
|
||||
* Structure of the super block
|
||||
*/
|
||||
struct ext2_super_block {
|
||||
__u32 s_inodes_count; /* Inodes count */
|
||||
__u32 s_blocks_count; /* Blocks count */
|
||||
__u32 s_r_blocks_count; /* Reserved blocks count */
|
||||
__u32 s_free_blocks_count; /* Free blocks count */
|
||||
__u32 s_free_inodes_count; /* Free inodes count */
|
||||
__u32 s_first_data_block; /* First Data Block */
|
||||
__u32 s_log_block_size; /* Block size */
|
||||
__s32 s_log_frag_size; /* Fragment size */
|
||||
__u32 s_blocks_per_group; /* # Blocks per group */
|
||||
__u32 s_frags_per_group; /* # Fragments per group */
|
||||
__u32 s_inodes_per_group; /* # Inodes per group */
|
||||
__u32 s_mtime; /* Mount time */
|
||||
__u32 s_wtime; /* Write time */
|
||||
__u16 s_mnt_count; /* Mount count */
|
||||
__s16 s_max_mnt_count; /* Maximal mount count */
|
||||
__u16 s_magic; /* Magic signature */
|
||||
__u16 s_state; /* File system state */
|
||||
__u16 s_errors; /* Behaviour when detecting errors */
|
||||
__u16 s_minor_rev_level; /* minor revision level */
|
||||
__u32 s_lastcheck; /* time of last check */
|
||||
__u32 s_checkinterval; /* max. time between checks */
|
||||
__u32 s_creator_os; /* OS */
|
||||
__u32 s_rev_level; /* Revision level */
|
||||
__u16 s_def_resuid; /* Default uid for reserved blocks */
|
||||
__u16 s_def_resgid; /* Default gid for reserved blocks */
|
||||
/*
|
||||
* These fields are for EXT2_DYNAMIC_REV superblocks only.
|
||||
*
|
||||
* Note: the difference between the compatible feature set and
|
||||
* the incompatible feature set is that if there is a bit set
|
||||
* in the incompatible feature set that the kernel doesn't
|
||||
* know about, it should refuse to mount the filesystem.
|
||||
*
|
||||
* e2fsck's requirements are more strict; if it doesn't know
|
||||
* about a feature in either the compatible or incompatible
|
||||
* feature set, it must abort and not try to meddle with
|
||||
* things it doesn't understand...
|
||||
*/
|
||||
__u32 s_first_ino; /* First non-reserved inode */
|
||||
__u16 s_inode_size; /* size of inode structure */
|
||||
__u16 s_block_group_nr; /* block group # of this superblock */
|
||||
__u32 s_feature_compat; /* compatible feature set */
|
||||
__u32 s_feature_incompat; /* incompatible feature set */
|
||||
__u32 s_feature_ro_compat; /* readonly-compatible feature set */
|
||||
__u8 s_uuid[16]; /* 128-bit uuid for volume */
|
||||
char s_volume_name[16]; /* volume name */
|
||||
char s_last_mounted[64]; /* directory where last mounted */
|
||||
__u32 s_algorithm_usage_bitmap; /* For compression */
|
||||
/*
|
||||
* Performance hints. Directory preallocation should only
|
||||
* happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on.
|
||||
*/
|
||||
__u8 s_prealloc_blocks; /* Nr of blocks to try to preallocate*/
|
||||
__u8 s_prealloc_dir_blocks; /* Nr to preallocate for dirs */
|
||||
__u16 s_reserved_gdt_blocks; /* Per group table for online growth */
|
||||
/*
|
||||
* Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set.
|
||||
*/
|
||||
__u8 s_journal_uuid[16]; /* uuid of journal superblock */
|
||||
__u32 s_journal_inum; /* inode number of journal file */
|
||||
__u32 s_journal_dev; /* device number of journal file */
|
||||
__u32 s_last_orphan; /* start of list of inodes to delete */
|
||||
__u32 s_hash_seed[4]; /* HTREE hash seed */
|
||||
__u8 s_def_hash_version; /* Default hash version to use */
|
||||
__u8 s_jnl_backup_type; /* Default type of journal backup */
|
||||
__u16 s_desc_size; /* Group desc. size: INCOMPAT_64BIT */
|
||||
__u32 s_default_mount_opts;
|
||||
__u32 s_first_meta_bg; /* First metablock group */
|
||||
__u32 s_mkfs_time; /* When the filesystem was created */
|
||||
__u32 s_jnl_blocks[17]; /* Backup of the journal inode */
|
||||
__u32 s_blocks_count_hi; /* Blocks count high 32bits */
|
||||
__u32 s_r_blocks_count_hi; /* Reserved blocks count high 32 bits*/
|
||||
__u32 s_free_blocks_hi; /* Free blocks count */
|
||||
__u16 s_min_extra_isize; /* All inodes have at least # bytes */
|
||||
__u16 s_want_extra_isize; /* New inodes should reserve # bytes */
|
||||
__u32 s_flags; /* Miscellaneous flags */
|
||||
__u16 s_raid_stride; /* RAID stride */
|
||||
__u16 s_mmp_interval; /* # seconds to wait in MMP checking */
|
||||
__u64 s_mmp_block; /* Block for multi-mount protection */
|
||||
__u32 s_raid_stripe_width; /* blocks on all data disks (N*stride)*/
|
||||
__u8 s_log_groups_per_flex; /* FLEX_BG group size */
|
||||
__u8 s_reserved_char_pad;
|
||||
__u16 s_reserved_pad; /* Padding to next 32bits */
|
||||
__u32 s_reserved[162]; /* Padding to the end of the block */
|
||||
};
|
||||
|
||||
/*
|
||||
* Codes for operating systems
|
||||
*/
|
||||
#define EXT2_OS_LINUX 0
|
||||
#define EXT2_OS_HURD 1
|
||||
#define EXT2_OBSO_OS_MASIX 2
|
||||
#define EXT2_OS_FREEBSD 3
|
||||
#define EXT2_OS_LITES 4
|
||||
|
||||
/*
|
||||
* Revision levels
|
||||
*/
|
||||
#define EXT2_GOOD_OLD_REV 0 /* The good old (original) format */
|
||||
#define EXT2_DYNAMIC_REV 1 /* V2 format w/ dynamic inode sizes */
|
||||
|
||||
#define EXT2_CURRENT_REV EXT2_GOOD_OLD_REV
|
||||
#define EXT2_MAX_SUPP_REV EXT2_DYNAMIC_REV
|
||||
|
||||
#define EXT2_GOOD_OLD_INODE_SIZE 128
|
||||
|
||||
/*
|
||||
* Journal inode backup types
|
||||
*/
|
||||
#define EXT3_JNL_BACKUP_BLOCKS 1
|
||||
|
||||
/*
|
||||
* Feature set definitions
|
||||
*/
|
||||
|
||||
#define EXT2_HAS_COMPAT_FEATURE(sb,mask) \
|
||||
( EXT2_SB(sb)->s_feature_compat & (mask) )
|
||||
#define EXT2_HAS_RO_COMPAT_FEATURE(sb,mask) \
|
||||
( EXT2_SB(sb)->s_feature_ro_compat & (mask) )
|
||||
#define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \
|
||||
( EXT2_SB(sb)->s_feature_incompat & (mask) )
|
||||
|
||||
#define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001
|
||||
#define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002
|
||||
#define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004
|
||||
#define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008
|
||||
#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010
|
||||
#define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020
|
||||
#define EXT2_FEATURE_COMPAT_LAZY_BG 0x0040
|
||||
|
||||
#define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001
|
||||
#define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002
|
||||
/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */
|
||||
#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008
|
||||
#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010
|
||||
#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020
|
||||
#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040
|
||||
|
||||
#define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001
|
||||
#define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002
|
||||
#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */
|
||||
#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */
|
||||
#define EXT2_FEATURE_INCOMPAT_META_BG 0x0010
|
||||
#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040
|
||||
#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080
|
||||
#define EXT4_FEATURE_INCOMPAT_MMP 0x0100
|
||||
#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200
|
||||
|
||||
|
||||
#define EXT2_FEATURE_COMPAT_SUPP 0
|
||||
#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE)
|
||||
#define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \
|
||||
EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \
|
||||
EXT4_FEATURE_RO_COMPAT_DIR_NLINK| \
|
||||
EXT2_FEATURE_RO_COMPAT_BTREE_DIR)
|
||||
|
||||
/*
|
||||
* Default values for user and/or group using reserved blocks
|
||||
*/
|
||||
#define EXT2_DEF_RESUID 0
|
||||
#define EXT2_DEF_RESGID 0
|
||||
|
||||
/*
|
||||
* Default mount options
|
||||
*/
|
||||
#define EXT2_DEFM_DEBUG 0x0001
|
||||
#define EXT2_DEFM_BSDGROUPS 0x0002
|
||||
#define EXT2_DEFM_XATTR_USER 0x0004
|
||||
#define EXT2_DEFM_ACL 0x0008
|
||||
#define EXT2_DEFM_UID16 0x0010
|
||||
#define EXT3_DEFM_JMODE 0x0060
|
||||
#define EXT3_DEFM_JMODE_DATA 0x0020
|
||||
#define EXT3_DEFM_JMODE_ORDERED 0x0040
|
||||
#define EXT3_DEFM_JMODE_WBACK 0x0060
|
||||
|
||||
/*
|
||||
* Structure of a directory entry
|
||||
*/
|
||||
#define EXT2_NAME_LEN 255
|
||||
|
||||
struct ext2_dir_entry {
|
||||
__u32 inode; /* Inode number */
|
||||
__u16 rec_len; /* Directory entry length */
|
||||
__u16 name_len; /* Name length */
|
||||
char name[EXT2_NAME_LEN]; /* File name */
|
||||
};
|
||||
|
||||
/*
|
||||
* The new version of the directory entry. Since EXT2 structures are
|
||||
* stored in intel byte order, and the name_len field could never be
|
||||
* bigger than 255 chars, it's safe to reclaim the extra byte for the
|
||||
* file_type field.
|
||||
*/
|
||||
struct ext2_dir_entry_2 {
|
||||
__u32 inode; /* Inode number */
|
||||
__u16 rec_len; /* Directory entry length */
|
||||
__u8 name_len; /* Name length */
|
||||
__u8 file_type;
|
||||
char name[EXT2_NAME_LEN]; /* File name */
|
||||
};
|
||||
|
||||
/*
|
||||
* Ext2 directory file types. Only the low 3 bits are used. The
|
||||
* other bits are reserved for now.
|
||||
*/
|
||||
#define EXT2_FT_UNKNOWN 0
|
||||
#define EXT2_FT_REG_FILE 1
|
||||
#define EXT2_FT_DIR 2
|
||||
#define EXT2_FT_CHRDEV 3
|
||||
#define EXT2_FT_BLKDEV 4
|
||||
#define EXT2_FT_FIFO 5
|
||||
#define EXT2_FT_SOCK 6
|
||||
#define EXT2_FT_SYMLINK 7
|
||||
|
||||
#define EXT2_FT_MAX 8
|
||||
|
||||
/*
|
||||
* EXT2_DIR_PAD defines the directory entries boundaries
|
||||
*
|
||||
* NOTE: It must be a multiple of 4
|
||||
*/
|
||||
#define EXT2_DIR_PAD 4
|
||||
#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1)
|
||||
#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \
|
||||
~EXT2_DIR_ROUND)
|
||||
|
||||
/*
|
||||
* This structure will be used for multiple mount protection. It will be
|
||||
* written into the block number saved in the s_mmp_block field in the
|
||||
* superblock.
|
||||
*/
|
||||
#define EXT2_MMP_MAGIC 0x004D4D50 /* ASCII for MMP */
|
||||
#define EXT2_MMP_CLEAN 0xFF4D4D50 /* Value of mmp_seq for clean unmount */
|
||||
#define EXT2_MMP_FSCK_ON 0xE24D4D50 /* Value of mmp_seq when being fscked */
|
||||
|
||||
struct mmp_struct {
|
||||
__u32 mmp_magic;
|
||||
__u32 mmp_seq;
|
||||
__u64 mmp_time;
|
||||
char mmp_nodename[64];
|
||||
char mmp_bdevname[32];
|
||||
__u16 mmp_interval;
|
||||
__u16 mmp_pad1;
|
||||
__u32 mmp_pad2;
|
||||
};
|
||||
|
||||
/*
|
||||
* Interval in number of seconds to update the MMP sequence number.
|
||||
*/
|
||||
#define EXT2_MMP_DEF_INTERVAL 5
|
||||
|
||||
#endif /* _LINUX_EXT2_FS_H */
|
145
Kernel/ext2_types.h
Normal file
145
Kernel/ext2_types.h
Normal file
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* If linux/types.h is already been included, assume it has defined
|
||||
* everything we need. (cross fingers) Other header files may have
|
||||
* also defined the types that we need.
|
||||
*/
|
||||
#if (!defined(_LINUX_TYPES_H) && !defined(_BLKID_TYPES_H) && \
|
||||
!defined(_EXT2_TYPES_H))
|
||||
#define _EXT2_TYPES_H
|
||||
|
||||
#define __S8_TYPEDEF __signed__ char
|
||||
#define __U8_TYPEDEF unsigned char
|
||||
#define __S16_TYPEDEF __signed__ short
|
||||
#define __U16_TYPEDEF unsigned short
|
||||
#define __S32_TYPEDEF __signed__ int
|
||||
#define __U32_TYPEDEF unsigned int
|
||||
#define __S64_TYPEDEF __signed__ long long
|
||||
#define __U64_TYPEDEF unsigned long long
|
||||
|
||||
#ifdef __U8_TYPEDEF
|
||||
typedef __U8_TYPEDEF __u8;
|
||||
#else
|
||||
typedef unsigned char __u8;
|
||||
#endif
|
||||
|
||||
#ifdef __S8_TYPEDEF
|
||||
typedef __S8_TYPEDEF __s8;
|
||||
#else
|
||||
typedef signed char __s8;
|
||||
#endif
|
||||
|
||||
#ifdef __U16_TYPEDEF
|
||||
typedef __U16_TYPEDEF __u16;
|
||||
#else
|
||||
#if (4 == 2)
|
||||
typedef unsigned int __u16;
|
||||
#else
|
||||
#if (2 == 2)
|
||||
typedef unsigned short __u16;
|
||||
#else
|
||||
?==error: undefined 16 bit type
|
||||
#endif /* SIZEOF_SHORT == 2 */
|
||||
#endif /* SIZEOF_INT == 2 */
|
||||
#endif /* __U16_TYPEDEF */
|
||||
|
||||
#ifdef __S16_TYPEDEF
|
||||
typedef __S16_TYPEDEF __s16;
|
||||
#else
|
||||
#if (4 == 2)
|
||||
typedef int __s16;
|
||||
#else
|
||||
#if (2 == 2)
|
||||
typedef short __s16;
|
||||
#else
|
||||
?==error: undefined 16 bit type
|
||||
#endif /* SIZEOF_SHORT == 2 */
|
||||
#endif /* SIZEOF_INT == 2 */
|
||||
#endif /* __S16_TYPEDEF */
|
||||
|
||||
|
||||
#ifdef __U32_TYPEDEF
|
||||
typedef __U32_TYPEDEF __u32;
|
||||
#else
|
||||
#if (4 == 4)
|
||||
typedef unsigned int __u32;
|
||||
#else
|
||||
#if (4 == 4)
|
||||
typedef unsigned long __u32;
|
||||
#else
|
||||
#if (2 == 4)
|
||||
typedef unsigned short __u32;
|
||||
#else
|
||||
?== error: undefined 32 bit type
|
||||
#endif /* SIZEOF_SHORT == 4 */
|
||||
#endif /* SIZEOF_LONG == 4 */
|
||||
#endif /* SIZEOF_INT == 4 */
|
||||
#endif /* __U32_TYPEDEF */
|
||||
|
||||
#ifdef __S32_TYPEDEF
|
||||
typedef __S32_TYPEDEF __s32;
|
||||
#else
|
||||
#if (4 == 4)
|
||||
typedef int __s32;
|
||||
#else
|
||||
#if (4 == 4)
|
||||
typedef long __s32;
|
||||
#else
|
||||
#if (2 == 4)
|
||||
typedef short __s32;
|
||||
#else
|
||||
?== error: undefined 32 bit type
|
||||
#endif /* SIZEOF_SHORT == 4 */
|
||||
#endif /* SIZEOF_LONG == 4 */
|
||||
#endif /* SIZEOF_INT == 4 */
|
||||
#endif /* __S32_TYPEDEF */
|
||||
|
||||
#ifdef __U64_TYPEDEF
|
||||
typedef __U64_TYPEDEF __u64;
|
||||
#else
|
||||
#if (4 == 8)
|
||||
typedef unsigned int __u64;
|
||||
#else
|
||||
#if (4 == 8)
|
||||
typedef unsigned long __u64;
|
||||
#else
|
||||
#if (8 == 8)
|
||||
typedef unsigned long long __u64;
|
||||
#endif /* SIZEOF_LONG_LONG == 8 */
|
||||
#endif /* SIZEOF_LONG == 8 */
|
||||
#endif /* SIZEOF_INT == 8 */
|
||||
#endif /* __U64_TYPEDEF */
|
||||
|
||||
#ifdef __S64_TYPEDEF
|
||||
typedef __S64_TYPEDEF __s64;
|
||||
#else
|
||||
#if (4 == 8)
|
||||
typedef int __s64;
|
||||
#else
|
||||
#if (4 == 8)
|
||||
typedef long __s64;
|
||||
#else
|
||||
#if (8 == 8)
|
||||
#if defined(__GNUC__)
|
||||
typedef __signed__ long long __s64;
|
||||
#else
|
||||
typedef signed long long __s64;
|
||||
#endif /* __GNUC__ */
|
||||
#endif /* SIZEOF_LONG_LONG == 8 */
|
||||
#endif /* SIZEOF_LONG == 8 */
|
||||
#endif /* SIZEOF_INT == 8 */
|
||||
#endif /* __S64_TYPEDEF */
|
||||
|
||||
#undef __S8_TYPEDEF
|
||||
#undef __U8_TYPEDEF
|
||||
#undef __S16_TYPEDEF
|
||||
#undef __U16_TYPEDEF
|
||||
#undef __S32_TYPEDEF
|
||||
#undef __U32_TYPEDEF
|
||||
#undef __S64_TYPEDEF
|
||||
#undef __U64_TYPEDEF
|
||||
|
||||
#endif /* _*_TYPES_H */
|
||||
|
||||
/* These defines are needed for the public ext2fs.h header file */
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#undef WORDS_BIGENDIAN
|
|
@ -9,12 +9,12 @@
|
|||
#include "CMOS.h"
|
||||
#include "IDEDiskDevice.h"
|
||||
#include "KSyms.h"
|
||||
#include <VirtualFileSystem/NullDevice.h>
|
||||
#include <VirtualFileSystem/ZeroDevice.h>
|
||||
#include <VirtualFileSystem/FullDevice.h>
|
||||
#include <VirtualFileSystem/RandomDevice.h>
|
||||
#include <VirtualFileSystem/Ext2FileSystem.h>
|
||||
#include <VirtualFileSystem/VirtualFileSystem.h>
|
||||
#include <Kernel/NullDevice.h>
|
||||
#include <Kernel/ZeroDevice.h>
|
||||
#include <Kernel/FullDevice.h>
|
||||
#include <Kernel/RandomDevice.h>
|
||||
#include <Kernel/Ext2FileSystem.h>
|
||||
#include <Kernel/VirtualFileSystem.h>
|
||||
#include "GUIEventDevice.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "ProcFileSystem.h"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue