Serenity Operating System
at master 547 lines 16 kB view raw
1/* 2 * Copyright (c) 2018-2022, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2021, sin-ack <sin-ack@protonmail.com> 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/MemoryStream.h> 9#include <Kernel/API/POSIX/errno.h> 10#include <Kernel/Devices/BlockDevice.h> 11#include <Kernel/FileSystem/Custody.h> 12#include <Kernel/FileSystem/FIFO.h> 13#include <Kernel/FileSystem/InodeFile.h> 14#include <Kernel/FileSystem/InodeWatcher.h> 15#include <Kernel/FileSystem/OpenFileDescription.h> 16#include <Kernel/FileSystem/VirtualFileSystem.h> 17#include <Kernel/Memory/MemoryManager.h> 18#include <Kernel/Net/Socket.h> 19#include <Kernel/Process.h> 20#include <Kernel/TTY/MasterPTY.h> 21#include <Kernel/TTY/TTY.h> 22#include <Kernel/UnixTypes.h> 23 24namespace Kernel { 25 26ErrorOr<NonnullRefPtr<OpenFileDescription>> OpenFileDescription::try_create(Custody& custody) 27{ 28 auto inode_file = TRY(InodeFile::create(custody.inode())); 29 auto description = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) OpenFileDescription(move(inode_file)))); 30 31 description->m_state.with([&](auto& state) { state.custody = custody; }); 32 TRY(description->attach()); 33 return description; 34} 35 36ErrorOr<NonnullRefPtr<OpenFileDescription>> OpenFileDescription::try_create(File& file) 37{ 38 auto description = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) OpenFileDescription(file))); 39 TRY(description->attach()); 40 return description; 41} 42 43OpenFileDescription::OpenFileDescription(File& file) 44 : m_file(file) 45{ 46 if (file.is_inode()) 47 m_inode = static_cast<InodeFile&>(file).inode(); 48 49 auto metadata = this->metadata(); 50 m_state.with([&](auto& state) { state.is_directory = metadata.is_directory(); }); 51} 52 53OpenFileDescription::~OpenFileDescription() 54{ 55 m_file->detach(*this); 56 if (is_fifo()) 57 static_cast<FIFO*>(m_file.ptr())->detach(fifo_direction()); 58 // FIXME: Should this error path be observed somehow? 59 (void)m_file->close(); 60 if (m_inode) 61 m_inode->detach(*this); 62 63 if (m_inode) 64 m_inode->remove_flocks_for_description(*this); 65} 66 67ErrorOr<void> OpenFileDescription::attach() 68{ 69 if (m_inode) 70 TRY(m_inode->attach(*this)); 71 return m_file->attach(*this); 72} 73 74void OpenFileDescription::set_original_custody(Badge<VirtualFileSystem>, Custody& custody) 75{ 76 m_state.with([&](auto& state) { state.custody = custody; }); 77} 78 79Thread::FileBlocker::BlockFlags OpenFileDescription::should_unblock(Thread::FileBlocker::BlockFlags block_flags) const 80{ 81 using BlockFlags = Thread::FileBlocker::BlockFlags; 82 BlockFlags unblock_flags = BlockFlags::None; 83 if (has_flag(block_flags, BlockFlags::Read) && can_read()) 84 unblock_flags |= BlockFlags::Read; 85 if (has_flag(block_flags, BlockFlags::Write) && can_write()) 86 unblock_flags |= BlockFlags::Write; 87 // TODO: Implement Thread::FileBlocker::BlockFlags::Exception 88 89 if (has_any_flag(block_flags, BlockFlags::SocketFlags)) { 90 auto const* sock = socket(); 91 VERIFY(sock); 92 if (has_flag(block_flags, BlockFlags::Accept) && sock->can_accept()) 93 unblock_flags |= BlockFlags::Accept; 94 if (has_flag(block_flags, BlockFlags::Connect) && sock->setup_state() == Socket::SetupState::Completed) 95 unblock_flags |= BlockFlags::Connect; 96 } 97 return unblock_flags; 98} 99 100ErrorOr<struct stat> OpenFileDescription::stat() 101{ 102 // FIXME: This is due to the Device class not overriding File::stat(). 103 if (m_inode) 104 return m_inode->metadata().stat(); 105 return m_file->stat(); 106} 107 108ErrorOr<off_t> OpenFileDescription::seek(off_t offset, int whence) 109{ 110 if (!m_file->is_seekable()) 111 return ESPIPE; 112 113 auto metadata = this->metadata(); 114 115 auto new_offset = TRY(m_state.with([&](auto& state) -> ErrorOr<off_t> { 116 off_t new_offset; 117 switch (whence) { 118 case SEEK_SET: 119 new_offset = offset; 120 break; 121 case SEEK_CUR: 122 if (Checked<off_t>::addition_would_overflow(state.current_offset, offset)) 123 return EOVERFLOW; 124 new_offset = state.current_offset + offset; 125 break; 126 case SEEK_END: 127 if (!metadata.is_valid()) 128 return EIO; 129 if (Checked<off_t>::addition_would_overflow(metadata.size, offset)) 130 return EOVERFLOW; 131 new_offset = metadata.size + offset; 132 break; 133 default: 134 return EINVAL; 135 } 136 if (new_offset < 0) 137 return EINVAL; 138 state.current_offset = new_offset; 139 return new_offset; 140 })); 141 142 // FIXME: Return EINVAL if attempting to seek past the end of a seekable device. 143 144 m_file->did_seek(*this, new_offset); 145 if (m_inode) 146 m_inode->did_seek(*this, new_offset); 147 evaluate_block_conditions(); 148 return new_offset; 149} 150 151ErrorOr<size_t> OpenFileDescription::read(UserOrKernelBuffer& buffer, u64 offset, size_t count) 152{ 153 if (Checked<u64>::addition_would_overflow(offset, count)) 154 return EOVERFLOW; 155 return m_file->read(*this, offset, buffer, count); 156} 157 158ErrorOr<size_t> OpenFileDescription::write(u64 offset, UserOrKernelBuffer const& data, size_t data_size) 159{ 160 if (Checked<u64>::addition_would_overflow(offset, data_size)) 161 return EOVERFLOW; 162 return m_file->write(*this, offset, data, data_size); 163} 164 165ErrorOr<size_t> OpenFileDescription::read(UserOrKernelBuffer& buffer, size_t count) 166{ 167 auto offset = TRY(m_state.with([&](auto& state) -> ErrorOr<off_t> { 168 if (Checked<off_t>::addition_would_overflow(state.current_offset, count)) 169 return EOVERFLOW; 170 return state.current_offset; 171 })); 172 auto nread = TRY(m_file->read(*this, offset, buffer, count)); 173 if (m_file->is_seekable()) 174 m_state.with([&](auto& state) { state.current_offset = offset + nread; }); 175 evaluate_block_conditions(); 176 return nread; 177} 178 179ErrorOr<size_t> OpenFileDescription::write(UserOrKernelBuffer const& data, size_t size) 180{ 181 auto offset = TRY(m_state.with([&](auto& state) -> ErrorOr<off_t> { 182 if (Checked<off_t>::addition_would_overflow(state.current_offset, size)) 183 return EOVERFLOW; 184 return state.current_offset; 185 })); 186 auto nwritten = TRY(m_file->write(*this, offset, data, size)); 187 188 if (m_file->is_seekable()) 189 m_state.with([&](auto& state) { state.current_offset = offset + nwritten; }); 190 191 evaluate_block_conditions(); 192 return nwritten; 193} 194 195bool OpenFileDescription::can_write() const 196{ 197 return m_file->can_write(*this, offset()); 198} 199 200bool OpenFileDescription::can_read() const 201{ 202 return m_file->can_read(*this, offset()); 203} 204 205ErrorOr<NonnullOwnPtr<KBuffer>> OpenFileDescription::read_entire_file() 206{ 207 // HACK ALERT: (This entire function) 208 VERIFY(m_file->is_inode()); 209 VERIFY(m_inode); 210 return m_inode->read_entire(this); 211} 212 213ErrorOr<size_t> OpenFileDescription::get_dir_entries(UserOrKernelBuffer& output_buffer, size_t size) 214{ 215 if (!is_directory()) 216 return ENOTDIR; 217 218 auto metadata = this->metadata(); 219 if (!metadata.is_valid()) 220 return EIO; 221 222 size_t remaining = size; 223 u8 stack_buffer[PAGE_SIZE]; 224 Bytes temp_buffer(stack_buffer, sizeof(stack_buffer)); 225 FixedMemoryStream stream { temp_buffer }; 226 227 auto flush_stream_to_output_buffer = [&stream, &remaining, &temp_buffer, &output_buffer]() -> ErrorOr<void> { 228 auto buffered_size = TRY(stream.tell()); 229 230 if (buffered_size == 0) 231 return {}; 232 233 if (remaining < buffered_size) 234 return Error::from_errno(EINVAL); 235 236 TRY(output_buffer.write(temp_buffer.trim(buffered_size))); 237 output_buffer = output_buffer.offset(buffered_size); 238 remaining -= buffered_size; 239 TRY(stream.seek(0)); 240 return {}; 241 }; 242 243 ErrorOr<void> result = VirtualFileSystem::the().traverse_directory_inode(*m_inode, [&flush_stream_to_output_buffer, &stream, this](auto& entry) -> ErrorOr<void> { 244 // FIXME: Double check the calculation, at least the type for the name length mismatches. 245 size_t serialized_size = sizeof(ino_t) + sizeof(u8) + sizeof(size_t) + sizeof(char) * entry.name.length(); 246 if (serialized_size > TRY(stream.size()) - TRY(stream.tell())) 247 TRY(flush_stream_to_output_buffer()); 248 249 MUST(stream.write_value<u64>(entry.inode.index().value())); 250 MUST(stream.write_value(m_inode->fs().internal_file_type_to_directory_entry_type(entry))); 251 MUST(stream.write_value<u32>(entry.name.length())); 252 MUST(stream.write_until_depleted(entry.name.bytes())); 253 return {}; 254 }); 255 256 if (result.is_error()) { 257 // We should only return EFAULT when the userspace buffer is too small, 258 // so that userspace can reliably use it as a signal to increase its 259 // buffer size. 260 VERIFY(result.error().code() != EFAULT); 261 return result.release_error(); 262 } 263 264 TRY(flush_stream_to_output_buffer()); 265 266 return size - remaining; 267} 268 269bool OpenFileDescription::is_device() const 270{ 271 return m_file->is_device(); 272} 273 274Device const* OpenFileDescription::device() const 275{ 276 if (!is_device()) 277 return nullptr; 278 return static_cast<Device const*>(m_file.ptr()); 279} 280 281Device* OpenFileDescription::device() 282{ 283 if (!is_device()) 284 return nullptr; 285 return static_cast<Device*>(m_file.ptr()); 286} 287 288bool OpenFileDescription::is_tty() const 289{ 290 return m_file->is_tty(); 291} 292 293const TTY* OpenFileDescription::tty() const 294{ 295 if (!is_tty()) 296 return nullptr; 297 return static_cast<const TTY*>(m_file.ptr()); 298} 299 300TTY* OpenFileDescription::tty() 301{ 302 if (!is_tty()) 303 return nullptr; 304 return static_cast<TTY*>(m_file.ptr()); 305} 306 307bool OpenFileDescription::is_inode_watcher() const 308{ 309 return m_file->is_inode_watcher(); 310} 311 312InodeWatcher const* OpenFileDescription::inode_watcher() const 313{ 314 if (!is_inode_watcher()) 315 return nullptr; 316 return static_cast<InodeWatcher const*>(m_file.ptr()); 317} 318 319InodeWatcher* OpenFileDescription::inode_watcher() 320{ 321 if (!is_inode_watcher()) 322 return nullptr; 323 return static_cast<InodeWatcher*>(m_file.ptr()); 324} 325 326bool OpenFileDescription::is_master_pty() const 327{ 328 return m_file->is_master_pty(); 329} 330 331MasterPTY const* OpenFileDescription::master_pty() const 332{ 333 if (!is_master_pty()) 334 return nullptr; 335 return static_cast<MasterPTY const*>(m_file.ptr()); 336} 337 338MasterPTY* OpenFileDescription::master_pty() 339{ 340 if (!is_master_pty()) 341 return nullptr; 342 return static_cast<MasterPTY*>(m_file.ptr()); 343} 344 345ErrorOr<void> OpenFileDescription::close() 346{ 347 if (m_file->attach_count() > 0) 348 return {}; 349 return m_file->close(); 350} 351 352ErrorOr<NonnullOwnPtr<KString>> OpenFileDescription::original_absolute_path() const 353{ 354 if (auto custody = this->custody()) 355 return custody->try_serialize_absolute_path(); 356 return ENOENT; 357} 358 359ErrorOr<NonnullOwnPtr<KString>> OpenFileDescription::pseudo_path() const 360{ 361 if (auto custody = this->custody()) 362 return custody->try_serialize_absolute_path(); 363 return m_file->pseudo_path(*this); 364} 365 366InodeMetadata OpenFileDescription::metadata() const 367{ 368 if (m_inode) 369 return m_inode->metadata(); 370 return {}; 371} 372 373ErrorOr<NonnullLockRefPtr<Memory::VMObject>> OpenFileDescription::vmobject_for_mmap(Process& process, Memory::VirtualRange const& range, u64& offset, bool shared) 374{ 375 return m_file->vmobject_for_mmap(process, range, offset, shared); 376} 377 378ErrorOr<void> OpenFileDescription::truncate(u64 length) 379{ 380 return m_file->truncate(length); 381} 382 383ErrorOr<void> OpenFileDescription::sync() 384{ 385 return m_file->sync(); 386} 387 388bool OpenFileDescription::is_fifo() const 389{ 390 return m_file->is_fifo(); 391} 392 393FIFO* OpenFileDescription::fifo() 394{ 395 if (!is_fifo()) 396 return nullptr; 397 return static_cast<FIFO*>(m_file.ptr()); 398} 399 400bool OpenFileDescription::is_socket() const 401{ 402 return m_file->is_socket(); 403} 404 405Socket* OpenFileDescription::socket() 406{ 407 if (!is_socket()) 408 return nullptr; 409 return static_cast<Socket*>(m_file.ptr()); 410} 411 412Socket const* OpenFileDescription::socket() const 413{ 414 if (!is_socket()) 415 return nullptr; 416 return static_cast<Socket const*>(m_file.ptr()); 417} 418 419void OpenFileDescription::set_file_flags(u32 flags) 420{ 421 m_state.with([&](auto& state) { 422 state.is_blocking = !(flags & O_NONBLOCK); 423 state.should_append = flags & O_APPEND; 424 state.direct = flags & O_DIRECT; 425 state.file_flags = flags; 426 }); 427} 428 429ErrorOr<void> OpenFileDescription::chmod(Credentials const& credentials, mode_t mode) 430{ 431 return m_file->chmod(credentials, *this, mode); 432} 433 434ErrorOr<void> OpenFileDescription::chown(Credentials const& credentials, UserID uid, GroupID gid) 435{ 436 return m_file->chown(credentials, *this, uid, gid); 437} 438 439FileBlockerSet& OpenFileDescription::blocker_set() 440{ 441 return m_file->blocker_set(); 442} 443 444ErrorOr<void> OpenFileDescription::apply_flock(Process const& process, Userspace<flock const*> lock, ShouldBlock should_block) 445{ 446 if (!m_inode) 447 return EBADF; 448 449 return m_inode->apply_flock(process, *this, lock, should_block); 450} 451 452ErrorOr<void> OpenFileDescription::get_flock(Userspace<flock*> lock) const 453{ 454 if (!m_inode) 455 return EBADF; 456 457 return m_inode->get_flock(*this, lock); 458} 459bool OpenFileDescription::is_readable() const 460{ 461 return m_state.with([](auto& state) { return state.readable; }); 462} 463 464bool OpenFileDescription::is_writable() const 465{ 466 return m_state.with([](auto& state) { return state.writable; }); 467} 468 469void OpenFileDescription::set_readable(bool b) 470{ 471 m_state.with([&](auto& state) { state.readable = b; }); 472} 473 474void OpenFileDescription::set_writable(bool b) 475{ 476 m_state.with([&](auto& state) { state.writable = b; }); 477} 478 479void OpenFileDescription::set_rw_mode(int options) 480{ 481 m_state.with([&](auto& state) { 482 state.readable = (options & O_RDONLY) == O_RDONLY; 483 state.writable = (options & O_WRONLY) == O_WRONLY; 484 }); 485} 486 487bool OpenFileDescription::is_direct() const 488{ 489 return m_state.with([](auto& state) { return state.direct; }); 490} 491 492bool OpenFileDescription::is_directory() const 493{ 494 return m_state.with([](auto& state) { return state.is_directory; }); 495} 496 497bool OpenFileDescription::is_blocking() const 498{ 499 return m_state.with([](auto& state) { return state.is_blocking; }); 500} 501 502void OpenFileDescription::set_blocking(bool b) 503{ 504 m_state.with([&](auto& state) { state.is_blocking = b; }); 505} 506 507bool OpenFileDescription::should_append() const 508{ 509 return m_state.with([](auto& state) { return state.should_append; }); 510} 511 512u32 OpenFileDescription::file_flags() const 513{ 514 return m_state.with([](auto& state) { return state.file_flags; }); 515} 516 517FIFO::Direction OpenFileDescription::fifo_direction() const 518{ 519 return m_state.with([](auto& state) { return state.fifo_direction; }); 520} 521 522void OpenFileDescription::set_fifo_direction(Badge<FIFO>, FIFO::Direction direction) 523{ 524 m_state.with([&](auto& state) { state.fifo_direction = direction; }); 525} 526 527OwnPtr<OpenFileDescriptionData>& OpenFileDescription::data() 528{ 529 return m_state.with([](auto& state) -> OwnPtr<OpenFileDescriptionData>& { return state.data; }); 530} 531 532off_t OpenFileDescription::offset() const 533{ 534 return m_state.with([](auto& state) { return state.current_offset; }); 535} 536 537RefPtr<Custody const> OpenFileDescription::custody() const 538{ 539 return m_state.with([](auto& state) { return state.custody; }); 540} 541 542RefPtr<Custody> OpenFileDescription::custody() 543{ 544 return m_state.with([](auto& state) { return state.custody; }); 545} 546 547}