Browse Source

Kernel: Add FIBMAP ioctl to Ext2FileSystem

FIBMAP is a linux ioctl that gives the location on disk of a specific
block of a file
Peter Elliott 4 years ago
parent
commit
c0e88b9710

+ 13 - 0
Kernel/FileSystem/Ext2FileSystem.cpp

@@ -1694,6 +1694,19 @@ KResult Ext2FSInode::truncate(u64 size)
     return KSuccess;
     return KSuccess;
 }
 }
 
 
+KResultOr<int> 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
 unsigned Ext2FS::total_block_count() const
 {
 {
     LOCKER(m_lock);
     LOCKER(m_lock);

+ 2 - 0
Kernel/FileSystem/Ext2FileSystem.h

@@ -77,6 +77,8 @@ private:
     virtual KResult chown(uid_t, gid_t) override;
     virtual KResult chown(uid_t, gid_t) override;
     virtual KResult truncate(u64) override;
     virtual KResult truncate(u64) override;
 
 
+    virtual KResultOr<int> get_block_address(int) override;
+
     bool write_directory(const Vector<Ext2FSDirectoryEntry>&);
     bool write_directory(const Vector<Ext2FSDirectoryEntry>&);
     bool populate_lookup_cache() const;
     bool populate_lookup_cache() const;
     KResult resize(u64);
     KResult resize(u64);

+ 2 - 0
Kernel/FileSystem/Inode.h

@@ -85,6 +85,8 @@ public:
     virtual KResult truncate(u64) { return KSuccess; }
     virtual KResult truncate(u64) { return KSuccess; }
     virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody& base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const;
     virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody& base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const;
 
 
+    virtual KResultOr<int> get_block_address(int) { return -ENOTSUP; }
+
     LocalSocket* socket() { return m_socket.ptr(); }
     LocalSocket* socket() { return m_socket.ptr(); }
     const LocalSocket* socket() const { return m_socket.ptr(); }
     const LocalSocket* socket() const { return m_socket.ptr(); }
     bool bind_socket(LocalSocket&);
     bool bind_socket(LocalSocket&);

+ 32 - 0
Kernel/FileSystem/InodeFile.cpp

@@ -32,6 +32,8 @@
 #include <Kernel/Process.h>
 #include <Kernel/Process.h>
 #include <Kernel/VM/PrivateInodeVMObject.h>
 #include <Kernel/VM/PrivateInodeVMObject.h>
 #include <Kernel/VM/SharedInodeVMObject.h>
 #include <Kernel/VM/SharedInodeVMObject.h>
+#include <LibC/errno_numbers.h>
+#include <LibC/sys/ioctl_numbers.h>
 
 
 namespace Kernel {
 namespace Kernel {
 
 
@@ -69,6 +71,36 @@ KResultOr<size_t> InodeFile::write(FileDescription& description, size_t offset,
     return nwritten;
     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<Region*> InodeFile::mmap(Process& process, FileDescription& description, const Range& range, size_t offset, int prot, bool shared)
 KResultOr<Region*> 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.
     // FIXME: If PROT_EXEC, check that the underlying file system isn't mounted noexec.

+ 1 - 0
Kernel/FileSystem/InodeFile.h

@@ -49,6 +49,7 @@ public:
 
 
     virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
     virtual KResultOr<size_t> read(FileDescription&, size_t, UserOrKernelBuffer&, size_t) override;
     virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
     virtual KResultOr<size_t> write(FileDescription&, size_t, const UserOrKernelBuffer&, size_t) override;
+    virtual int ioctl(FileDescription&, unsigned request, FlatPtr arg) override;
     virtual KResultOr<Region*> mmap(Process&, FileDescription&, const Range&, size_t offset, int prot, bool shared) override;
     virtual KResultOr<Region*> mmap(Process&, FileDescription&, const Range&, size_t offset, int prot, bool shared) override;
 
 
     virtual String absolute_path(const FileDescription&) const override;
     virtual String absolute_path(const FileDescription&) const override;

+ 3 - 1
Userland/Libraries/LibC/sys/ioctl_numbers.h

@@ -67,7 +67,8 @@ enum IOCtlNumber {
     SIOCGIFHWADDR,
     SIOCGIFHWADDR,
     SIOCSIFNETMASK,
     SIOCSIFNETMASK,
     SIOCADDRT,
     SIOCADDRT,
-    SIOCDELRT
+    SIOCDELRT,
+    FIBMAP
 };
 };
 
 
 #define TIOCGPGRP TIOCGPGRP
 #define TIOCGPGRP TIOCGPGRP
@@ -92,3 +93,4 @@ enum IOCtlNumber {
 #define SIOCSIFNETMASK SIOCSIFNETMASK
 #define SIOCSIFNETMASK SIOCSIFNETMASK
 #define SIOCADDRT SIOCADDRT
 #define SIOCADDRT SIOCADDRT
 #define SIOCDELRT SIOCDELRT
 #define SIOCDELRT SIOCDELRT
+#define FIBMAP FIBMAP