/* * Copyright (c) 2018-2020, Andreas Kling * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #define O_RDONLY (1 << 0) #define O_WRONLY (1 << 1) #define O_RDWR (O_RDONLY | O_WRONLY) #define O_ACCMODE (O_RDONLY | O_WRONLY) #define O_EXEC (1 << 2) #define O_CREAT (1 << 3) #define O_EXCL (1 << 4) #define O_NOCTTY (1 << 5) #define O_TRUNC (1 << 6) #define O_APPEND (1 << 7) #define O_NONBLOCK (1 << 8) #define O_DIRECTORY (1 << 9) #define O_NOFOLLOW (1 << 10) #define O_CLOEXEC (1 << 11) #define O_DIRECT (1 << 12) // Kernel internal options #define O_NOFOLLOW_NOERROR (1 << 29) #define O_UNLINK_INTERNAL (1 << 30) #define MS_NODEV 1 #define MS_NOEXEC 2 #define MS_NOSUID 4 #define MS_BIND 8 class Custody; class Device; class FileDescription; class UnveiledPath; struct UidAndGid { uid_t uid; gid_t gid; }; class VFS { AK_MAKE_ETERNAL public: class Mount { public: Mount(FS&, Custody* host_custody, int flags); Mount(Inode& source, Custody& host_custody, int flags); InodeIdentifier host() const; InodeIdentifier guest() const { return m_guest; } const FS& guest_fs() const { return *m_guest_fs; } String absolute_path() const; int flags() const { return m_flags; } private: InodeIdentifier m_host; InodeIdentifier m_guest; NonnullRefPtr m_guest_fs; RefPtr m_host_custody; int m_flags; }; static VFS& the(); VFS(); ~VFS(); bool mount_root(FS&); KResult mount(FS&, Custody& mount_point, int flags); KResult bind_mount(Custody& source, Custody& mount_point, int flags); KResult unmount(InodeIdentifier guest_inode_id); KResultOr> open(StringView path, int options, mode_t mode, Custody& base, Optional = {}); KResultOr> create(StringView path, int options, mode_t mode, Custody& parent_custody, Optional = {}); KResult mkdir(StringView path, mode_t mode, Custody& base); KResult link(StringView old_path, StringView new_path, Custody& base); KResult unlink(StringView path, Custody& base); KResult symlink(StringView target, StringView linkpath, Custody& base); KResult rmdir(StringView path, Custody& base); KResult chmod(StringView path, mode_t, Custody& base); KResult chmod(Inode&, mode_t); KResult chown(StringView path, uid_t, gid_t, Custody& base); KResult chown(Inode&, uid_t, gid_t); KResult access(StringView path, int mode, Custody& base); KResultOr lookup_metadata(StringView path, Custody& base, int options = 0); KResult utime(StringView path, Custody& base, time_t atime, time_t mtime); KResult rename(StringView oldpath, StringView newpath, Custody& base); KResult mknod(StringView path, mode_t, dev_t, Custody& base); KResultOr> open_directory(StringView path, Custody& base); size_t mount_count() const { return m_mounts.size(); } void for_each_mount(Function) const; InodeIdentifier root_inode_id() const; void sync(); Custody& root_custody(); KResultOr> resolve_path(StringView path, Custody& base, RefPtr* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0); private: friend class FileDescription; const UnveiledPath* find_matching_unveiled_path(StringView path); KResult validate_path_against_process_veil(StringView path, int options); RefPtr get_inode(InodeIdentifier); bool is_vfs_root(InodeIdentifier) const; void traverse_directory_inode(Inode&, Function); Mount* find_mount_for_host(InodeIdentifier); Mount* find_mount_for_guest(InodeIdentifier); Lock m_lock { "VFSLock" }; RefPtr m_root_inode; Vector m_mounts; RefPtr m_root_custody; };