浏览代码

Kernel: Let symlinks resolve themselves

Symlink resolution is now a virtual method on an inode,
Inode::resolve_as_symlink(). The default implementation just reads the stored
inode contents, treats them as a path and calls through to VFS::resolve_path().

This will let us support other, magical files that appear to be plain old
symlinks but resolve to something else. This is particularly useful for ProcFS.
Sergey Bugaev 5 年之前
父节点
当前提交
ae64fd1b27
共有 3 个文件被更改,包括 22 次插入10 次删除
  1. 19 0
      Kernel/FileSystem/Inode.cpp
  2. 2 0
      Kernel/FileSystem/Inode.h
  3. 1 10
      Kernel/FileSystem/VirtualFileSystem.cpp

+ 19 - 0
Kernel/FileSystem/Inode.cpp

@@ -4,6 +4,8 @@
 #include <Kernel/FileSystem/InodeWatcher.h>
 #include <Kernel/Net/LocalSocket.h>
 #include <Kernel/VM/InodeVMObject.h>
+#include <Kernel/FileSystem/VirtualFileSystem.h>
+#include <Kernel/FileSystem/Custody.h>
 
 InlineLinkedList<Inode>& all_inodes()
 {
@@ -56,6 +58,23 @@ ByteBuffer Inode::read_entire(FileDescription* descriptor) const
     return builder.to_byte_buffer();
 }
 
+KResultOr<NonnullRefPtr<Custody>> Inode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const
+{
+    // The default implementation simply treats the stored
+    // contents as a path and resolves that. That is, it
+    // behaves exactly how you would expect a symlink to work.
+    auto contents = read_entire();
+
+    if (!contents) {
+        if (out_parent)
+            *out_parent = nullptr;
+        return KResult(-ENOENT);
+    }
+
+    auto path = StringView(contents.data(), contents.size());
+    return VFS::the().resolve_path(path, base, out_parent, options, symlink_recursion_level);
+}
+
 unsigned Inode::fsid() const
 {
     return m_fs.fsid();

+ 2 - 0
Kernel/FileSystem/Inode.h

@@ -15,6 +15,7 @@ class FileDescription;
 class InodeVMObject;
 class InodeWatcher;
 class LocalSocket;
+class Custody;
 
 class Inode : public RefCounted<Inode>
     , public Weakable<Inode>
@@ -53,6 +54,7 @@ public:
     virtual KResult chmod(mode_t) = 0;
     virtual KResult chown(uid_t, gid_t) = 0;
     virtual KResult truncate(off_t) { 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;
 
     LocalSocket* socket() { return m_socket.ptr(); }
     const LocalSocket* socket() const { return m_socket.ptr(); }

+ 1 - 10
Kernel/FileSystem/VirtualFileSystem.cpp

@@ -741,16 +741,7 @@ KResultOr<NonnullRefPtr<Custody>> VFS::resolve_path(StringView path, Custody& ba
                 if (options & O_NOFOLLOW_NOERROR)
                     break;
             }
-            auto symlink_contents = child_inode->read_entire();
-            if (!symlink_contents) {
-                if (out_parent)
-                    *out_parent = nullptr;
-                return KResult(-ENOENT);
-            }
-
-            auto symlink_path = StringView(symlink_contents.data(), symlink_contents.size());
-            auto symlink_target = resolve_path(symlink_path, parent, out_parent, options, symlink_recursion_level + 1);
-
+            auto symlink_target = child_inode->resolve_as_link(parent, out_parent, options, symlink_recursion_level + 1);
             if (symlink_target.is_error() || !have_more_parts)
                 return symlink_target;