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.
This commit is contained in:
Andreas Kling 2019-01-31 05:05:57 +01:00
parent c3cc318028
commit c4fce9b3f9
8 changed files with 25 additions and 10 deletions

View file

@ -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;
}

View file

@ -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;

View file

@ -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>&&);

View file

@ -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);

View file

@ -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));
}

View file

@ -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;

View file

@ -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

View file

@ -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);