diff --git a/Kernel/FileSystem/Ext2FileSystem.cpp b/Kernel/FileSystem/Ext2FileSystem.cpp index bc68681070..2f897e8d99 100644 --- a/Kernel/FileSystem/Ext2FileSystem.cpp +++ b/Kernel/FileSystem/Ext2FileSystem.cpp @@ -1694,6 +1694,19 @@ KResult Ext2FSInode::truncate(u64 size) return KSuccess; } +KResultOr Ext2FSInode::get_block_address(int index) +{ + LOCKER(m_lock); + + if (m_block_list.is_empty()) + m_block_list = fs().block_list_for_inode(m_raw_inode); + + if (index < 0 || (size_t)index >= m_block_list.size()) + return 0; + + return m_block_list[index]; +} + unsigned Ext2FS::total_block_count() const { LOCKER(m_lock); diff --git a/Kernel/FileSystem/Ext2FileSystem.h b/Kernel/FileSystem/Ext2FileSystem.h index 6302a8690c..a395bd4c8e 100644 --- a/Kernel/FileSystem/Ext2FileSystem.h +++ b/Kernel/FileSystem/Ext2FileSystem.h @@ -77,6 +77,8 @@ private: virtual KResult chown(uid_t, gid_t) override; virtual KResult truncate(u64) override; + virtual KResultOr get_block_address(int) override; + bool write_directory(const Vector&); bool populate_lookup_cache() const; KResult resize(u64); diff --git a/Kernel/FileSystem/Inode.h b/Kernel/FileSystem/Inode.h index 61339d7107..49a7564c6a 100644 --- a/Kernel/FileSystem/Inode.h +++ b/Kernel/FileSystem/Inode.h @@ -85,6 +85,8 @@ public: virtual KResult truncate(u64) { return KSuccess; } virtual KResultOr> resolve_as_link(Custody& base, RefPtr* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const; + virtual KResultOr get_block_address(int) { return -ENOTSUP; } + LocalSocket* socket() { return m_socket.ptr(); } const LocalSocket* socket() const { return m_socket.ptr(); } bool bind_socket(LocalSocket&); diff --git a/Kernel/FileSystem/InodeFile.cpp b/Kernel/FileSystem/InodeFile.cpp index 5db5b8814d..6773324b43 100644 --- a/Kernel/FileSystem/InodeFile.cpp +++ b/Kernel/FileSystem/InodeFile.cpp @@ -32,6 +32,8 @@ #include #include #include +#include +#include namespace Kernel { @@ -69,6 +71,36 @@ KResultOr InodeFile::write(FileDescription& description, size_t offset, return nwritten; } +int InodeFile::ioctl(FileDescription& description, unsigned request, FlatPtr arg) +{ + (void)description; + + switch (request) { + case FIBMAP: { + if (!Process::current()->is_superuser()) + return -EPERM; + + int block_number = 0; + if (!copy_from_user(&block_number, (int*)arg)) + return -EFAULT; + + if (block_number < 0) + return -EINVAL; + + auto block_address = inode().get_block_address(block_number); + if (block_address.is_error()) + return block_address.error(); + + if (!copy_to_user((int*)arg, &block_address.value())) + return -EFAULT; + + return 0; + } + default: + return -EINVAL; + } +} + KResultOr InodeFile::mmap(Process& process, FileDescription& description, const Range& range, size_t offset, int prot, bool shared) { // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec. diff --git a/Kernel/FileSystem/InodeFile.h b/Kernel/FileSystem/InodeFile.h index a0b7b122c0..ba3fc99ad6 100644 --- a/Kernel/FileSystem/InodeFile.h +++ b/Kernel/FileSystem/InodeFile.h @@ -49,6 +49,7 @@ public: virtual KResultOr read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override; virtual KResultOr write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override; + virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg) override; virtual KResultOr mmap(Process&, FileDescription&, const Range&, size_t offset, int prot, bool shared) override; virtual String absolute_path(const FileDescription&) const override; diff --git a/Userland/Libraries/LibC/sys/ioctl_numbers.h b/Userland/Libraries/LibC/sys/ioctl_numbers.h index 2492349060..df31bebaf9 100644 --- a/Userland/Libraries/LibC/sys/ioctl_numbers.h +++ b/Userland/Libraries/LibC/sys/ioctl_numbers.h @@ -67,7 +67,8 @@ enum IOCtlNumber { SIOCGIFHWADDR, SIOCSIFNETMASK, SIOCADDRT, - SIOCDELRT + SIOCDELRT, + FIBMAP }; #define TIOCGPGRP TIOCGPGRP @@ -92,3 +93,4 @@ enum IOCtlNumber { #define SIOCSIFNETMASK SIOCSIFNETMASK #define SIOCADDRT SIOCADDRT #define SIOCDELRT SIOCDELRT +#define FIBMAP FIBMAP