Kernel/LibC: Implement {,f}statvfs
This commit is contained in:
parent
ad1f175a39
commit
a10ca47657
|
@ -11,6 +11,18 @@ namespace Kernel
|
|||
class Ext2FS final : public FileSystem
|
||||
{
|
||||
public:
|
||||
virtual unsigned long bsize() const override;
|
||||
virtual unsigned long frsize() const override;
|
||||
virtual fsblkcnt_t blocks() const override;
|
||||
virtual fsblkcnt_t bfree() const override;
|
||||
virtual fsblkcnt_t bavail() const override;
|
||||
virtual fsfilcnt_t files() const override;
|
||||
virtual fsfilcnt_t ffree() const override;
|
||||
virtual fsfilcnt_t favail() const override;
|
||||
virtual unsigned long fsid() const override;
|
||||
virtual unsigned long flag() const override;
|
||||
virtual unsigned long namemax() const override;
|
||||
|
||||
class BlockBufferWrapper
|
||||
{
|
||||
BAN_NON_COPYABLE(BlockBufferWrapper);
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace Kernel
|
|||
virtual dev_t dev() const override { return 0; }
|
||||
virtual dev_t rdev() const override { return 0; }
|
||||
|
||||
virtual const FileSystem* filesystem() const override;
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode_impl(BAN::StringView) override;
|
||||
virtual BAN::ErrorOr<size_t> list_next_inodes_impl(off_t, struct dirent*, size_t) override;
|
||||
|
|
|
@ -20,6 +20,18 @@ namespace Kernel
|
|||
};
|
||||
|
||||
public:
|
||||
virtual unsigned long bsize() const override;
|
||||
virtual unsigned long frsize() const override;
|
||||
virtual fsblkcnt_t blocks() const override;
|
||||
virtual fsblkcnt_t bfree() const override;
|
||||
virtual fsblkcnt_t bavail() const override;
|
||||
virtual fsfilcnt_t files() const override;
|
||||
virtual fsfilcnt_t ffree() const override;
|
||||
virtual fsfilcnt_t favail() const override;
|
||||
virtual unsigned long fsid() const override;
|
||||
virtual unsigned long flag() const override;
|
||||
virtual unsigned long namemax() const override;
|
||||
|
||||
static BAN::ErrorOr<bool> probe(BAN::RefPtr<BlockDevice>);
|
||||
static BAN::ErrorOr<BAN::RefPtr<FATFS>> create(BAN::RefPtr<BlockDevice>);
|
||||
|
||||
|
@ -45,13 +57,15 @@ namespace Kernel
|
|||
|
||||
// TODO: These probably should be constant variables
|
||||
uint32_t root_sector_count() const { return BAN::Math::div_round_up<uint32_t>(m_bpb.root_entry_count * 32, m_bpb.bytes_per_sector); }
|
||||
uint32_t fat_sector_count() const { return m_bpb.fat_size16 ? m_bpb.fat_size16 : m_bpb.ext_32.fat_size32; }
|
||||
uint32_t fat_size() const { return m_bpb.fat_size16 ? m_bpb.fat_size16 : m_bpb.ext_32.fat_size32; }
|
||||
uint32_t total_sector_count() const { return m_bpb.total_sectors16 ? m_bpb.total_sectors16 : m_bpb.total_sectors32; }
|
||||
uint32_t data_sector_count() const { return total_sector_count() - (m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count()) + root_sector_count()); }
|
||||
uint32_t data_sector_count() const { return total_sector_count() - (m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size()) + root_sector_count()); }
|
||||
uint32_t cluster_count() const { return data_sector_count() / m_bpb.sectors_per_cluster; }
|
||||
uint32_t first_data_sector() const { return m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count()) + root_sector_count(); }
|
||||
uint32_t first_data_sector() const { return m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size()) + root_sector_count(); }
|
||||
uint32_t first_fat_sector() const { return m_bpb.reserved_sector_count; }
|
||||
|
||||
uint8_t bits_per_fat_entry() const { return static_cast<uint8_t>(m_type); }
|
||||
|
||||
private:
|
||||
BAN::RefPtr<BlockDevice> m_block_device;
|
||||
BAN::RefPtr<FATInode> m_root_inode;
|
||||
|
|
|
@ -29,6 +29,8 @@ namespace Kernel
|
|||
virtual dev_t dev() const override { return 0; }
|
||||
virtual dev_t rdev() const override { return 0; }
|
||||
|
||||
virtual const FileSystem* filesystem() const override;
|
||||
|
||||
const FAT::DirectoryEntry& entry() const { return m_entry; }
|
||||
|
||||
protected:
|
||||
|
|
|
@ -9,6 +9,18 @@ namespace Kernel
|
|||
class FileSystem : public BAN::RefCounted<FileSystem>
|
||||
{
|
||||
public:
|
||||
virtual unsigned long bsize() const = 0;
|
||||
virtual unsigned long frsize() const = 0;
|
||||
virtual fsblkcnt_t blocks() const = 0;
|
||||
virtual fsblkcnt_t bfree() const = 0;
|
||||
virtual fsblkcnt_t bavail() const = 0;
|
||||
virtual fsfilcnt_t files() const = 0;
|
||||
virtual fsfilcnt_t ffree() const = 0;
|
||||
virtual fsfilcnt_t favail() const = 0;
|
||||
virtual unsigned long fsid() const = 0;
|
||||
virtual unsigned long flag() const = 0;
|
||||
virtual unsigned long namemax() const = 0;
|
||||
|
||||
virtual ~FileSystem() {}
|
||||
|
||||
static BAN::ErrorOr<BAN::RefPtr<FileSystem>> from_block_device(BAN::RefPtr<BlockDevice>);
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class FileSystem;
|
||||
|
||||
class FileBackedRegion;
|
||||
class SharedFileData;
|
||||
|
||||
|
@ -86,6 +88,8 @@ namespace Kernel
|
|||
virtual bool is_pipe() const { return false; }
|
||||
virtual bool is_tty() const { return false; }
|
||||
|
||||
virtual const FileSystem* filesystem() const = 0;
|
||||
|
||||
// Directory API
|
||||
BAN::ErrorOr<BAN::RefPtr<Inode>> find_inode(BAN::StringView);
|
||||
BAN::ErrorOr<size_t> list_next_inodes(off_t, struct dirent* list, size_t list_size);
|
||||
|
|
|
@ -30,6 +30,8 @@ namespace Kernel
|
|||
virtual dev_t dev() const override { return 0; } // FIXME
|
||||
virtual dev_t rdev() const override { return 0; } // FIXME
|
||||
|
||||
virtual const FileSystem* filesystem() const override { return nullptr; }
|
||||
|
||||
protected:
|
||||
virtual BAN::ErrorOr<size_t> read_impl(off_t, BAN::ByteSpan) override;
|
||||
virtual BAN::ErrorOr<size_t> write_impl(off_t, BAN::ConstByteSpan) override;
|
||||
|
|
|
@ -44,6 +44,8 @@ namespace Kernel
|
|||
dev_t dev() const final override { ASSERT_NOT_REACHED(); }
|
||||
dev_t rdev() const final override { ASSERT_NOT_REACHED(); }
|
||||
|
||||
const FileSystem* filesystem() const final override { return nullptr; }
|
||||
|
||||
protected:
|
||||
Socket(const Info& info)
|
||||
: m_info(info)
|
||||
|
|
|
@ -40,6 +40,19 @@ namespace Kernel
|
|||
static constexpr size_t no_page_limit = SIZE_MAX;
|
||||
|
||||
public:
|
||||
// FIXME: basically all of these :)
|
||||
virtual unsigned long bsize() const override { return PAGE_SIZE; }
|
||||
virtual unsigned long frsize() const override { return PAGE_SIZE; }
|
||||
virtual fsblkcnt_t blocks() const override { return m_max_pages; }
|
||||
virtual fsblkcnt_t bfree() const override { return m_max_pages - m_used_pages; }
|
||||
virtual fsblkcnt_t bavail() const override { return m_max_pages - m_used_pages; }
|
||||
virtual fsfilcnt_t files() const override { return PAGE_SIZE * blocks() / sizeof(TmpDirectoryEntry); }
|
||||
virtual fsfilcnt_t ffree() const override { return PAGE_SIZE * bfree() / sizeof(TmpDirectoryEntry); }
|
||||
virtual fsfilcnt_t favail() const override { return PAGE_SIZE * bavail() / sizeof(TmpDirectoryEntry); }
|
||||
virtual unsigned long fsid() const override { return reinterpret_cast<uintptr_t>(this); }
|
||||
virtual unsigned long flag() const override { return 0; }
|
||||
virtual unsigned long namemax() const override { return PAGE_SIZE; }
|
||||
|
||||
static BAN::ErrorOr<TmpFileSystem*> create(size_t max_pages, mode_t, uid_t, gid_t);
|
||||
~TmpFileSystem();
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ namespace Kernel
|
|||
static BAN::ErrorOr<BAN::RefPtr<TmpInode>> create_from_existing(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
~TmpInode();
|
||||
|
||||
virtual const FileSystem* filesystem() const override;
|
||||
|
||||
protected:
|
||||
TmpInode(TmpFileSystem&, ino_t, const TmpInodeInfo&);
|
||||
|
||||
|
|
|
@ -8,9 +8,22 @@
|
|||
namespace Kernel
|
||||
{
|
||||
|
||||
class VirtualFileSystem : public FileSystem
|
||||
class VirtualFileSystem final : public FileSystem
|
||||
{
|
||||
public:
|
||||
virtual unsigned long bsize() const override { return 0; }
|
||||
virtual unsigned long frsize() const override { return 0; }
|
||||
virtual fsblkcnt_t blocks() const override { return 0; }
|
||||
virtual fsblkcnt_t bfree() const override { return 0; }
|
||||
virtual fsblkcnt_t bavail() const override { return 0; }
|
||||
virtual fsfilcnt_t files() const override { return 0; }
|
||||
virtual fsfilcnt_t ffree() const override { return 0; }
|
||||
virtual fsfilcnt_t favail() const override { return 0; }
|
||||
virtual unsigned long fsid() const override { return 0; }
|
||||
virtual unsigned long flag() const override { return 0; }
|
||||
virtual unsigned long namemax() const override { return 0; }
|
||||
|
||||
|
||||
static void initialize(BAN::StringView);
|
||||
static VirtualFileSystem& get();
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <sys/mman.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/time.h>
|
||||
#include <termios.h>
|
||||
|
||||
|
@ -147,6 +148,7 @@ namespace Kernel
|
|||
BAN::ErrorOr<long> sys_fsync(int fd);
|
||||
|
||||
BAN::ErrorOr<long> sys_fstatat(int fd, const char* path, struct stat* buf, int flag);
|
||||
BAN::ErrorOr<long> sys_fstatvfsat(int fd, const char* path, struct statvfs* buf);
|
||||
|
||||
BAN::ErrorOr<long> sys_realpath(const char* path, char* buffer);
|
||||
|
||||
|
|
|
@ -32,6 +32,18 @@ namespace Kernel
|
|||
return superblock.magic == Ext2::Enum::SUPER_MAGIC;
|
||||
}
|
||||
|
||||
unsigned long Ext2FS::bsize() const { return block_size(); }
|
||||
unsigned long Ext2FS::frsize() const { return block_size(); }
|
||||
fsblkcnt_t Ext2FS::blocks() const { return m_superblock.blocks_count; }
|
||||
fsblkcnt_t Ext2FS::bfree() const { return m_superblock.free_blocks_count; }
|
||||
fsblkcnt_t Ext2FS::bavail() const { return m_superblock.free_blocks_count; } // FIXME
|
||||
fsfilcnt_t Ext2FS::files() const { return m_superblock.inodes_count; }
|
||||
fsfilcnt_t Ext2FS::ffree() const { return m_superblock.free_inodes_count; }
|
||||
fsfilcnt_t Ext2FS::favail() const { return m_superblock.free_inodes_count; } // FIXME
|
||||
unsigned long Ext2FS::fsid() const { return *reinterpret_cast<const unsigned long*>(m_superblock.uuid); } // FIXME?
|
||||
unsigned long Ext2FS::flag() const { return 0; }
|
||||
unsigned long Ext2FS::namemax() const { return 0xFF; }
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<Ext2FS>> Ext2FS::create(BAN::RefPtr<BlockDevice> block_device)
|
||||
{
|
||||
auto ext2fs = TRY(BAN::RefPtr<Ext2FS>::create(block_device));
|
||||
|
|
|
@ -47,6 +47,11 @@ namespace Kernel
|
|||
dwarnln("Could not cleanup inode from FS: {}", ret.error());
|
||||
}
|
||||
|
||||
const FileSystem* Ext2Inode::filesystem() const
|
||||
{
|
||||
return &m_fs;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<BAN::Optional<uint32_t>> Ext2Inode::block_from_indirect_block(uint32_t block, uint32_t index, uint32_t depth)
|
||||
{
|
||||
if (block == 0)
|
||||
|
|
|
@ -64,6 +64,18 @@ namespace Kernel
|
|||
return validate_bpb(bpb_span.as<const FAT::BPB>());
|
||||
}
|
||||
|
||||
unsigned long FATFS::bsize() const { return m_bpb.bytes_per_sector; }
|
||||
unsigned long FATFS::frsize() const { return m_bpb.bytes_per_sector; }
|
||||
fsblkcnt_t FATFS::blocks() const { return data_sector_count(); }
|
||||
fsblkcnt_t FATFS::bfree() const { return 0; } // FIXME
|
||||
fsblkcnt_t FATFS::bavail() const { return 0; } // FIXME
|
||||
fsfilcnt_t FATFS::files() const { return m_bpb.number_of_fats * fat_size() * 8 / bits_per_fat_entry(); }
|
||||
fsfilcnt_t FATFS::ffree() const { return 0; } // FIXME
|
||||
fsfilcnt_t FATFS::favail() const { return 0; } // FIXME
|
||||
unsigned long FATFS::fsid() const { return m_type == Type::FAT32 ? m_bpb.ext_32.volume_id : m_bpb.ext_12_16.volume_id; }
|
||||
unsigned long FATFS::flag() const { return 0; }
|
||||
unsigned long FATFS::namemax() const { return 255; }
|
||||
|
||||
BAN::ErrorOr<BAN::RefPtr<FATFS>> FATFS::create(BAN::RefPtr<BlockDevice> block_device)
|
||||
{
|
||||
// support only block devices with sectors at least 512 bytes
|
||||
|
@ -226,7 +238,7 @@ namespace Kernel
|
|||
{
|
||||
if (index >= root_sector_count())
|
||||
return BAN::Error::from_errno(ENOENT);
|
||||
const uint32_t first_root_sector = m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_sector_count());
|
||||
const uint32_t first_root_sector = m_bpb.reserved_sector_count + (m_bpb.number_of_fats * fat_size());
|
||||
TRY(m_block_device->read_blocks(first_root_sector + index, 1, buffer));
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -46,6 +46,11 @@ namespace Kernel
|
|||
return timespec { .tv_sec = epoch, .tv_nsec = 0 };
|
||||
}
|
||||
|
||||
const FileSystem* FATInode::filesystem() const
|
||||
{
|
||||
return &m_fs;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<void> FATInode::for_each_directory_entry(BAN::ConstByteSpan entry_span, BAN::Function<BAN::Iteration(const FAT::DirectoryEntry&)> callback)
|
||||
{
|
||||
ASSERT(mode().ifdir());
|
||||
|
|
|
@ -41,6 +41,11 @@ namespace Kernel
|
|||
|
||||
/* GENERAL INODE */
|
||||
|
||||
const FileSystem* TmpInode::filesystem() const
|
||||
{
|
||||
return &m_fs;
|
||||
}
|
||||
|
||||
dev_t TmpInode::dev() const
|
||||
{
|
||||
return m_fs.dev();
|
||||
|
|
|
@ -1496,6 +1496,35 @@ namespace Kernel
|
|||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_fstatvfsat(int fd, const char* path, struct statvfs* buf)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
TRY(validate_pointer_access(buf, sizeof(struct statvfs), true));
|
||||
|
||||
auto inode = TRY(find_file(fd, path, 0)).inode;
|
||||
auto* fs = inode->filesystem();
|
||||
if (fs == nullptr)
|
||||
{
|
||||
ASSERT(inode->mode().ifsock() || inode->mode().ififo());
|
||||
dwarnln("TODO: fstatvfs on sockets or pipe?");
|
||||
return BAN::Error::from_errno(EINVAL);
|
||||
}
|
||||
|
||||
buf->f_bsize = fs->bsize();
|
||||
buf->f_frsize = fs->frsize();
|
||||
buf->f_blocks = fs->blocks();
|
||||
buf->f_bfree = fs->bfree();
|
||||
buf->f_bavail = fs->bavail();
|
||||
buf->f_files = fs->files();
|
||||
buf->f_ffree = fs->ffree();
|
||||
buf->f_favail = fs->favail();
|
||||
buf->f_fsid = fs->fsid();
|
||||
buf->f_flag = fs->flag();
|
||||
buf->f_namemax = fs->namemax();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BAN::ErrorOr<long> Process::sys_realpath(const char* path, char* buffer)
|
||||
{
|
||||
LockGuard _(m_process_lock);
|
||||
|
|
|
@ -32,6 +32,7 @@ set(LIBC_SOURCES
|
|||
sys/select.cpp
|
||||
sys/socket.cpp
|
||||
sys/stat.cpp
|
||||
sys/statvfs.cpp
|
||||
sys/time.cpp
|
||||
sys/utsname.cpp
|
||||
sys/wait.cpp
|
||||
|
|
|
@ -48,6 +48,7 @@ __BEGIN_DECLS
|
|||
O(SYS_FCNTL, fcntl) \
|
||||
O(SYS_NANOSLEEP, nanosleep) \
|
||||
O(SYS_FSTATAT, fstatat) \
|
||||
O(SYS_FSTATVFSAT, fstatvfsat) \
|
||||
O(SYS_SYNC, sync) \
|
||||
O(SYS_MMAP, mmap) \
|
||||
O(SYS_MUNMAP, munmap) \
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
#include <fcntl.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
static int fstatvfsat(int fildes, const char* path, struct statvfs* buf)
|
||||
{
|
||||
return syscall(SYS_FSTATVFSAT, fildes, path, buf);
|
||||
}
|
||||
|
||||
int fstatvfs(int fildes, struct statvfs* buf)
|
||||
{
|
||||
return fstatvfsat(fildes, nullptr, buf);
|
||||
}
|
||||
|
||||
int statvfs(const char* __restrict path, struct statvfs* __restrict buf)
|
||||
{
|
||||
return fstatvfsat(AT_FDCWD, path, buf);
|
||||
}
|
Loading…
Reference in New Issue