瀏覽代碼

Make stat() work on device files again.

FileDescriptor will now keep a pointer to the original inode even after
opening it resolves to a character device.

Fixed up /bin/ls to display major and minor device numbers instead of size
for device files.
Andreas Kling 6 年之前
父節點
當前提交
c4fce9b3f9

+ 1 - 1
Kernel/Ext2FileSystem.cpp

@@ -360,7 +360,7 @@ InodeMetadata Ext2FSInode::metadata() const
     if (isBlockDevice(m_raw_inode.i_mode) || isCharacterDevice(m_raw_inode.i_mode)) {
         unsigned dev = m_raw_inode.i_block[0];
         metadata.majorDevice = (dev & 0xfff00) >> 8;
-        metadata.minorDevice= (dev & 0xff) | ((dev >> 12) & 0xfff00);
+        metadata.minorDevice = (dev & 0xff) | ((dev >> 12) & 0xfff00);
     }
     return metadata;
 }

+ 5 - 4
Kernel/FileDescriptor.cpp

@@ -59,10 +59,11 @@ RetainPtr<FileDescriptor> FileDescriptor::clone()
             ? FileDescriptor::create_pipe_reader(*m_fifo)
             : FileDescriptor::create_pipe_writer(*m_fifo);
     } else {
-        if (m_inode)
-            descriptor = FileDescriptor::create(m_inode.copyRef());
-        else {
+        if (m_device) {
             descriptor = FileDescriptor::create(m_device.copyRef());
+            descriptor->m_inode = m_inode.copyRef();
+        } else {
+            descriptor = FileDescriptor::create(m_inode.copyRef());
         }
     }
     if (!descriptor)
@@ -90,7 +91,7 @@ int FileDescriptor::fstat(stat* buffer)
     if (!metadata.isValid())
         return -EIO;
 
-    buffer->st_dev = 0; // FIXME
+    buffer->st_dev = encodedDevice(metadata.majorDevice, metadata.minorDevice);
     buffer->st_ino = metadata.inode.index();
     buffer->st_mode = metadata.mode;
     buffer->st_nlink = metadata.linkCount;

+ 3 - 0
Kernel/FileDescriptor.h

@@ -6,6 +6,7 @@
 #include <AK/ByteBuffer.h>
 #include <AK/CircularQueue.h>
 #include <AK/Retainable.h>
+#include <AK/Badge.h>
 
 class TTY;
 class MasterPTY;
@@ -68,6 +69,8 @@ public:
 
     ByteBuffer& generator_cache() { return m_generator_cache; }
 
+    void set_original_inode(Badge<VFS>, RetainPtr<Inode>&& inode) { m_inode = move(inode); }
+
 private:
     friend class VFS;
     explicit FileDescriptor(RetainPtr<Inode>&&);

+ 2 - 2
Kernel/Process.cpp

@@ -1215,7 +1215,7 @@ int Process::sys$lstat(const char* path, stat* statbuf)
     if (!validate_write_typed(statbuf))
         return -EFAULT;
     int error;
-    auto descriptor = VFS::the().open(move(path), error, O_NOFOLLOW_NOERROR, 0, cwd_inode()->identifier());
+    auto descriptor = VFS::the().open(move(path), error, O_NOFOLLOW_NOERROR | O_DONT_OPEN_DEVICE, 0, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     descriptor->fstat(statbuf);
@@ -1227,7 +1227,7 @@ int Process::sys$stat(const char* path, stat* statbuf)
     if (!validate_write_typed(statbuf))
         return -EFAULT;
     int error;
-    auto descriptor = VFS::the().open(move(path), error, 0, 0, cwd_inode()->identifier());
+    auto descriptor = VFS::the().open(move(path), error, O_DONT_OPEN_DEVICE, 0, cwd_inode()->identifier());
     if (!descriptor)
         return error;
     descriptor->fstat(statbuf);

+ 4 - 2
Kernel/VirtualFileSystem.cpp

@@ -146,13 +146,15 @@ RetainPtr<FileDescriptor> VFS::open(const String& path, int& error, int options,
         return nullptr;
     }
     auto metadata = inode->metadata();
-    if (metadata.isCharacterDevice()) {
+    if (!(options & O_DONT_OPEN_DEVICE) && 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);
+        auto descriptor = (*it).value->open(error, options);
+        descriptor->set_original_inode(Badge<VFS>(), move(inode));
+        return descriptor;
     }
     return FileDescriptor::create(move(inode));
 }

+ 1 - 0
Kernel/VirtualFileSystem.h

@@ -24,6 +24,7 @@
 #define O_NOFOLLOW 00400000
 #define O_CLOEXEC 02000000
 #define O_NOFOLLOW_NOERROR 0x4000000
+#define O_DONT_OPEN_DEVICE 0x8000000
 
 class CharacterDevice;
 class FileDescriptor;

+ 4 - 0
LibC/sys/stat.h

@@ -9,4 +9,8 @@ mode_t umask(mode_t);
 int chmod(const char* pathname, mode_t);
 int mkdir(const char* pathname, mode_t);
 
+inline dev_t makedev(unsigned int major, unsigned int minor) { return (minor & 0xffu) | (major << 8u) | ((minor & ~0xffu) << 12u); }
+inline unsigned int major(dev_t dev) { return (dev & 0xfff00u) >> 8u; }
+inline unsigned int minor(dev_t dev) { return (dev & 0xffu) | ((dev >> 12u) & 0xfff00u); }
+
 __END_DECLS

+ 5 - 1
Userland/ls.cpp

@@ -5,6 +5,7 @@
 #include <string.h>
 #include <getopt.h>
 #include <sys/ioctl.h>
+#include <sys/stat.h>
 #include <AK/AKString.h>
 #include <AK/Vector.h>
 
@@ -150,7 +151,10 @@ int do_dir(const char* path)
 
         printf(" %4u %4u", st.st_uid, st.st_gid);
 
-        printf(" %10u  ", st.st_size);
+        if (S_ISCHR(st.st_mode))
+            printf("  %4u,%4u ", major(st.st_dev), minor(st.st_dev));
+        else
+            printf(" %10u ", st.st_size);
 
         printf(" %10u  ", st.st_mtime);