Serenity Operating System
at hosted 201 lines 7.8 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * 2. Redistributions in binary form must reproduce the above copyright notice, 12 * this list of conditions and the following disclaimer in the documentation 13 * and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#pragma once 28 29#include <AK/Bitmap.h> 30#include <AK/HashMap.h> 31#include <Kernel/FileSystem/FileBackedFileSystem.h> 32#include <Kernel/FileSystem/Inode.h> 33#include <Kernel/FileSystem/ext2_fs.h> 34#include <Kernel/KBuffer.h> 35#include <Kernel/UnixTypes.h> 36 37struct ext2_group_desc; 38struct ext2_inode; 39struct ext2_super_block; 40 41namespace Kernel { 42 43class Ext2FS; 44 45class Ext2FSInode final : public Inode { 46 friend class Ext2FS; 47 48public: 49 virtual ~Ext2FSInode() override; 50 51 size_t size() const { return m_raw_inode.i_size; } 52 bool is_symlink() const { return Kernel::is_symlink(m_raw_inode.i_mode); } 53 bool is_directory() const { return Kernel::is_directory(m_raw_inode.i_mode); } 54 55 // ^Inode (RefCounted magic) 56 virtual void one_ref_left() override; 57 58private: 59 // ^Inode 60 virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override; 61 virtual InodeMetadata metadata() const override; 62 virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override; 63 virtual RefPtr<Inode> lookup(StringView name) override; 64 virtual void flush_metadata() override; 65 virtual ssize_t write_bytes(off_t, ssize_t, const u8* data, FileDescription*) override; 66 virtual KResult add_child(InodeIdentifier child_id, const StringView& name, mode_t) override; 67 virtual KResult remove_child(const StringView& name) override; 68 virtual int set_atime(time_t) override; 69 virtual int set_ctime(time_t) override; 70 virtual int set_mtime(time_t) override; 71 virtual KResult increment_link_count() override; 72 virtual KResult decrement_link_count() override; 73 virtual size_t directory_entry_count() const override; 74 virtual KResult chmod(mode_t) override; 75 virtual KResult chown(uid_t, gid_t) override; 76 virtual KResult truncate(u64) override; 77 78 bool write_directory(const Vector<FS::DirectoryEntry>&); 79 void populate_lookup_cache() const; 80 KResult resize(u64); 81 82 Ext2FS& fs(); 83 const Ext2FS& fs() const; 84 Ext2FSInode(Ext2FS&, unsigned index); 85 86 mutable Vector<unsigned> m_block_list; 87 mutable HashMap<String, unsigned> m_lookup_cache; 88 ext2_inode m_raw_inode; 89}; 90 91class Ext2FS final : public FileBackedFS { 92 friend class Ext2FSInode; 93 94public: 95 static NonnullRefPtr<Ext2FS> create(FileDescription&); 96 97 virtual ~Ext2FS() override; 98 virtual bool initialize() override; 99 100 virtual unsigned total_block_count() const override; 101 virtual unsigned free_block_count() const override; 102 virtual unsigned total_inode_count() const override; 103 virtual unsigned free_inode_count() const override; 104 105 virtual KResult prepare_to_unmount() const override; 106 107 virtual bool supports_watchers() const override { return true; } 108 109private: 110 typedef unsigned BlockIndex; 111 typedef unsigned GroupIndex; 112 typedef unsigned InodeIndex; 113 explicit Ext2FS(FileDescription&); 114 115 const ext2_super_block& super_block() const { return m_super_block; } 116 const ext2_group_desc& group_descriptor(GroupIndex) const; 117 ext2_group_desc* block_group_descriptors() { return (ext2_group_desc*)m_cached_group_descriptor_table.value().data(); } 118 const ext2_group_desc* block_group_descriptors() const { return (const ext2_group_desc*)m_cached_group_descriptor_table.value().data(); } 119 void flush_block_group_descriptor_table(); 120 unsigned inodes_per_block() const; 121 unsigned inodes_per_group() const; 122 unsigned blocks_per_group() const; 123 unsigned inode_size() const; 124 125 bool write_ext2_inode(InodeIndex, const ext2_inode&); 126 bool read_block_containing_inode(InodeIndex inode, BlockIndex& block_index, unsigned& offset, u8* buffer) const; 127 128 bool flush_super_block(); 129 130 virtual const char* class_name() const override; 131 virtual InodeIdentifier root_inode() const override; 132 virtual KResultOr<NonnullRefPtr<Inode>> create_inode(InodeIdentifier parent_id, const String& name, mode_t, off_t size, dev_t, uid_t, gid_t) override; 133 virtual KResult create_directory(InodeIdentifier parent_inode, const String& name, mode_t, uid_t, gid_t) override; 134 virtual RefPtr<Inode> get_inode(InodeIdentifier) const override; 135 virtual void flush_writes() override; 136 137 BlockIndex first_block_index() const; 138 InodeIndex find_a_free_inode(GroupIndex preferred_group, off_t expected_size); 139 Vector<BlockIndex> allocate_blocks(GroupIndex preferred_group_index, size_t count); 140 GroupIndex group_index_from_inode(InodeIndex) const; 141 GroupIndex group_index_from_block_index(BlockIndex) const; 142 143 Vector<BlockIndex> block_list_for_inode_impl(const ext2_inode&, bool include_block_list_blocks = false) const; 144 Vector<BlockIndex> block_list_for_inode(const ext2_inode&, bool include_block_list_blocks = false) const; 145 bool write_block_list_for_inode(InodeIndex, ext2_inode&, const Vector<BlockIndex>&); 146 147 bool get_inode_allocation_state(InodeIndex) const; 148 bool set_inode_allocation_state(InodeIndex, bool); 149 bool set_block_allocation_state(BlockIndex, bool); 150 151 void uncache_inode(InodeIndex); 152 void free_inode(Ext2FSInode&); 153 154 struct BlockListShape { 155 unsigned direct_blocks { 0 }; 156 unsigned indirect_blocks { 0 }; 157 unsigned doubly_indirect_blocks { 0 }; 158 unsigned triply_indirect_blocks { 0 }; 159 unsigned meta_blocks { 0 }; 160 }; 161 162 BlockListShape compute_block_list_shape(unsigned blocks); 163 164 unsigned m_block_group_count { 0 }; 165 166 mutable ext2_super_block m_super_block; 167 mutable Optional<KBuffer> m_cached_group_descriptor_table; 168 169 mutable HashMap<InodeIndex, RefPtr<Ext2FSInode>> m_inode_cache; 170 171 bool m_super_block_dirty { false }; 172 bool m_block_group_descriptors_dirty { false }; 173 174 struct CachedBitmap { 175 CachedBitmap(BlockIndex bi, KBuffer&& buf) 176 : bitmap_block_index(bi) 177 , buffer(move(buf)) 178 { 179 } 180 BlockIndex bitmap_block_index { 0 }; 181 bool dirty { false }; 182 KBuffer buffer; 183 Bitmap bitmap(u32 blocks_per_group) { return Bitmap::wrap(buffer.data(), blocks_per_group); } 184 }; 185 186 CachedBitmap& get_bitmap_block(BlockIndex); 187 188 Vector<OwnPtr<CachedBitmap>> m_cached_bitmaps; 189}; 190 191inline Ext2FS& Ext2FSInode::fs() 192{ 193 return static_cast<Ext2FS&>(Inode::fs()); 194} 195 196inline const Ext2FS& Ext2FSInode::fs() const 197{ 198 return static_cast<const Ext2FS&>(Inode::fs()); 199} 200 201}