Serenity Operating System
at portability 219 lines 5.9 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#include <AK/NonnullRefPtrVector.h> 28#include <AK/StringBuilder.h> 29#include <Kernel/FileSystem/Inode.h> 30#include <Kernel/FileSystem/InodeWatcher.h> 31#include <Kernel/Net/LocalSocket.h> 32#include <Kernel/VM/InodeVMObject.h> 33#include <Kernel/FileSystem/VirtualFileSystem.h> 34#include <Kernel/FileSystem/Custody.h> 35 36namespace Kernel { 37 38InlineLinkedList<Inode>& all_inodes() 39{ 40 static InlineLinkedList<Inode>* list; 41 if (!list) 42 list = new InlineLinkedList<Inode>; 43 return *list; 44} 45 46void Inode::sync() 47{ 48 NonnullRefPtrVector<Inode, 32> inodes; 49 { 50 InterruptDisabler disabler; 51 for (auto& inode : all_inodes()) { 52 if (inode.is_metadata_dirty()) 53 inodes.append(inode); 54 } 55 } 56 57 for (auto& inode : inodes) { 58 ASSERT(inode.is_metadata_dirty()); 59 inode.flush_metadata(); 60 } 61} 62 63ByteBuffer Inode::read_entire(FileDescription* descriptor) const 64{ 65 size_t initial_size = metadata().size ? metadata().size : 4096; 66 StringBuilder builder(initial_size); 67 68 ssize_t nread; 69 u8 buffer[4096]; 70 off_t offset = 0; 71 for (;;) { 72 nread = read_bytes(offset, sizeof(buffer), buffer, descriptor); 73 ASSERT(nread <= (ssize_t)sizeof(buffer)); 74 if (nread <= 0) 75 break; 76 builder.append((const char*)buffer, nread); 77 offset += nread; 78 if (nread < (ssize_t)sizeof(buffer)) 79 break; 80 } 81 if (nread < 0) { 82 kprintf("Inode::read_entire: ERROR: %d\n", nread); 83 return nullptr; 84 } 85 86 return builder.to_byte_buffer(); 87} 88 89KResultOr<NonnullRefPtr<Custody>> Inode::resolve_as_link(Custody& base, RefPtr<Custody>* out_parent, int options, int symlink_recursion_level) const 90{ 91 // The default implementation simply treats the stored 92 // contents as a path and resolves that. That is, it 93 // behaves exactly how you would expect a symlink to work. 94 auto contents = read_entire(); 95 96 if (!contents) { 97 if (out_parent) 98 *out_parent = nullptr; 99 return KResult(-ENOENT); 100 } 101 102 auto path = StringView(contents.data(), contents.size()); 103 return VFS::the().resolve_path(path, base, out_parent, options, symlink_recursion_level); 104} 105 106unsigned Inode::fsid() const 107{ 108 return m_fs.fsid(); 109} 110 111Inode::Inode(FS& fs, unsigned index) 112 : m_fs(fs) 113 , m_index(index) 114{ 115 all_inodes().append(this); 116} 117 118Inode::~Inode() 119{ 120 all_inodes().remove(this); 121} 122 123void Inode::will_be_destroyed() 124{ 125 if (m_metadata_dirty) 126 flush_metadata(); 127} 128 129void Inode::inode_contents_changed(off_t offset, ssize_t size, const u8* data) 130{ 131 if (m_vmobject) 132 m_vmobject->inode_contents_changed({}, offset, size, data); 133} 134 135void Inode::inode_size_changed(size_t old_size, size_t new_size) 136{ 137 if (m_vmobject) 138 m_vmobject->inode_size_changed({}, old_size, new_size); 139} 140 141int Inode::set_atime(time_t) 142{ 143 return -ENOTIMPL; 144} 145 146int Inode::set_ctime(time_t) 147{ 148 return -ENOTIMPL; 149} 150 151int Inode::set_mtime(time_t) 152{ 153 return -ENOTIMPL; 154} 155 156KResult Inode::increment_link_count() 157{ 158 return KResult(-ENOTIMPL); 159} 160 161KResult Inode::decrement_link_count() 162{ 163 return KResult(-ENOTIMPL); 164} 165 166void Inode::set_vmobject(VMObject& vmobject) 167{ 168 m_vmobject = vmobject.make_weak_ptr(); 169} 170 171bool Inode::bind_socket(LocalSocket& socket) 172{ 173 LOCKER(m_lock); 174 if (m_socket) 175 return false; 176 m_socket = socket; 177 return true; 178} 179 180bool Inode::unbind_socket() 181{ 182 LOCKER(m_lock); 183 if (!m_socket) 184 return false; 185 m_socket = nullptr; 186 return true; 187} 188 189void Inode::register_watcher(Badge<InodeWatcher>, InodeWatcher& watcher) 190{ 191 LOCKER(m_lock); 192 ASSERT(!m_watchers.contains(&watcher)); 193 m_watchers.set(&watcher); 194} 195 196void Inode::unregister_watcher(Badge<InodeWatcher>, InodeWatcher& watcher) 197{ 198 LOCKER(m_lock); 199 ASSERT(m_watchers.contains(&watcher)); 200 m_watchers.remove(&watcher); 201} 202 203void Inode::set_metadata_dirty(bool metadata_dirty) 204{ 205 if (m_metadata_dirty == metadata_dirty) 206 return; 207 208 m_metadata_dirty = metadata_dirty; 209 if (m_metadata_dirty) { 210 // FIXME: Maybe we should hook into modification events somewhere else, I'm not sure where. 211 // We don't always end up on this particular code path, for instance when writing to an ext2fs file. 212 LOCKER(m_lock); 213 for (auto& watcher : m_watchers) { 214 watcher->notify_inode_event({}, InodeWatcher::Event::Type::Modified); 215 } 216 } 217} 218 219}