Kernel: Move open file descriptors to their own class
This simplifies code a lot :)
This commit is contained in:
		
							parent
							
								
									274ecbba78
								
							
						
					
					
						commit
						78c091f7f8
					
				|  | @ -33,6 +33,7 @@ set(KERNEL_SOURCES | |||
| 	kernel/Memory/kmalloc.cpp | ||||
| 	kernel/Memory/PhysicalRange.cpp | ||||
| 	kernel/Memory/VirtualRange.cpp | ||||
| 	kernel/OpenFileDescriptorSet.cpp | ||||
| 	kernel/Panic.cpp | ||||
| 	kernel/PCI.cpp | ||||
| 	kernel/PIC.cpp | ||||
|  |  | |||
|  | @ -0,0 +1,72 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Array.h> | ||||
| #include <kernel/FS/Inode.h> | ||||
| 
 | ||||
| #include <limits.h> | ||||
| #include <sys/stat.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class OpenFileDescriptorSet | ||||
| 	{ | ||||
| 		BAN_NON_COPYABLE(OpenFileDescriptorSet); | ||||
| 
 | ||||
| 	public: | ||||
| 		OpenFileDescriptorSet(const Credentials&); | ||||
| 		~OpenFileDescriptorSet(); | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> clone_from(const OpenFileDescriptorSet&); | ||||
| 
 | ||||
| 		BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags); | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> pipe(int fds[2]); | ||||
| 
 | ||||
| 		BAN::ErrorOr<int> dup2(int, int); | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> seek(int fd, off_t offset, int whence); | ||||
| 		BAN::ErrorOr<off_t> tell(int) const; | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> fstat(int fd, struct stat*) const; | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> close(int); | ||||
| 		void close_all(); | ||||
| 		void close_cloexec(); | ||||
| 
 | ||||
| 		BAN::ErrorOr<size_t> read(int fd, void* buffer, size_t count); | ||||
| 		BAN::ErrorOr<size_t> write(int fd, const void* buffer, size_t count); | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size); | ||||
| 
 | ||||
| 		BAN::ErrorOr<BAN::StringView> path_of(int) const; | ||||
| 
 | ||||
| 	private: | ||||
| 		struct OpenFileDescription : public BAN::RefCounted<OpenFileDescription> | ||||
| 		{ | ||||
| 			OpenFileDescription(BAN::RefPtr<Inode> inode, BAN::String path, off_t offset, uint8_t flags) | ||||
| 				: inode(inode) | ||||
| 				, path(BAN::move(path)) | ||||
| 				, offset(offset) | ||||
| 				, flags(flags) | ||||
| 			{ } | ||||
| 
 | ||||
| 			BAN::RefPtr<Inode> inode; | ||||
| 			BAN::String path; | ||||
| 			off_t offset { 0 }; | ||||
| 			uint8_t flags { 0 }; | ||||
| 
 | ||||
| 			friend class BAN::RefPtr<OpenFileDescription>; | ||||
| 		}; | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> validate_fd(int) const; | ||||
| 		BAN::ErrorOr<int> get_free_fd() const; | ||||
| 		BAN::ErrorOr<void> get_free_fd_pair(int fds[2]) const; | ||||
| 
 | ||||
| 	private: | ||||
| 		const Credentials& m_credentials; | ||||
| 
 | ||||
| 		BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> m_open_files; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -9,11 +9,11 @@ | |||
| #include <kernel/Memory/GeneralAllocator.h> | ||||
| #include <kernel/Memory/Heap.h> | ||||
| #include <kernel/Memory/VirtualRange.h> | ||||
| #include <kernel/OpenFileDescriptorSet.h> | ||||
| #include <kernel/SpinLock.h> | ||||
| #include <kernel/Terminal/TTY.h> | ||||
| #include <kernel/Thread.h> | ||||
| 
 | ||||
| #include <sys/stat.h> | ||||
| #include <termios.h> | ||||
| 
 | ||||
| namespace LibELF { class ELF; } | ||||
|  | @ -128,20 +128,6 @@ namespace Kernel | |||
| 		BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const; | ||||
| 
 | ||||
| 	private: | ||||
| 		struct OpenFileDescription | ||||
| 		{ | ||||
| 			BAN::RefPtr<Inode> inode; | ||||
| 			BAN::String path; | ||||
| 			off_t offset { 0 }; | ||||
| 			uint8_t flags { 0 }; | ||||
| 		}; | ||||
| 
 | ||||
| 		BAN::ErrorOr<void> validate_fd(int); | ||||
| 		OpenFileDescription& open_file_description(int); | ||||
| 		BAN::ErrorOr<int> get_free_fd(); | ||||
| 		BAN::ErrorOr<void> get_free_fd_pair(int fds[2]); | ||||
| 
 | ||||
| 
 | ||||
| 		struct ExitStatus | ||||
| 		{ | ||||
| 			Semaphore semaphore; | ||||
|  | @ -152,7 +138,8 @@ namespace Kernel | |||
| 
 | ||||
| 		Credentials m_credentials; | ||||
| 
 | ||||
| 		BAN::Vector<OpenFileDescription> m_open_files; | ||||
| 		OpenFileDescriptorSet m_open_file_descriptors; | ||||
| 
 | ||||
| 		BAN::Vector<VirtualRange*> m_mapped_ranges; | ||||
| 
 | ||||
| 		mutable RecursiveSpinLock m_lock; | ||||
|  |  | |||
|  | @ -0,0 +1,245 @@ | |||
| #include <kernel/FS/Pipe.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/OpenFileDescriptorSet.h> | ||||
| 
 | ||||
| #include <fcntl.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 
 | ||||
| 	OpenFileDescriptorSet::OpenFileDescriptorSet(const Credentials& credentials) | ||||
| 		: m_credentials(credentials) | ||||
| 	{ | ||||
| 
 | ||||
| 	} | ||||
| 
 | ||||
| 	OpenFileDescriptorSet::~OpenFileDescriptorSet() | ||||
| 	{ | ||||
| 		close_all(); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::clone_from(const OpenFileDescriptorSet& other) | ||||
| 	{ | ||||
| 		close_all(); | ||||
| 
 | ||||
| 		for (int fd = 0; fd < (int)other.m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (other.validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			 | ||||
| 			auto& open_file = other.m_open_files[fd]; | ||||
| 
 | ||||
| 			auto result = BAN::RefPtr<OpenFileDescription>::create(open_file->inode, open_file->path, open_file->offset, open_file->flags); | ||||
| 
 | ||||
| 			if (result.is_error()) | ||||
| 			{ | ||||
| 				close_all(); | ||||
| 				return result.error(); | ||||
| 			} | ||||
| 
 | ||||
| 			m_open_files[fd] = result.release_value(); | ||||
| 
 | ||||
| 			if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe()) | ||||
| 				((Pipe*)m_open_files[fd]->inode.ptr())->clone_writing(); | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags) | ||||
| 	{ | ||||
| 		if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_CLOEXEC)) | ||||
| 			return BAN::Error::from_errno(ENOTSUP); | ||||
| 
 | ||||
| 		auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)); | ||||
| 
 | ||||
| 		int fd = TRY(get_free_fd()); | ||||
| 		m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(file.inode, BAN::move(file.canonical_path), 0, flags)); | ||||
| 
 | ||||
| 		return fd; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::pipe(int fds[2]) | ||||
| 	{ | ||||
| 		TRY(get_free_fd_pair(fds)); | ||||
| 
 | ||||
| 		auto pipe = TRY(Pipe::create(m_credentials)); | ||||
| 		m_open_files[fds[0]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""sv, 0, O_RDONLY)); | ||||
| 		m_open_files[fds[1]] = TRY(BAN::RefPtr<OpenFileDescription>::create(pipe, ""sv, 0, O_WRONLY)); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<int> OpenFileDescriptorSet::dup2(int fildes, int fildes2) | ||||
| 	{ | ||||
| 		if (fildes2 < 0 || fildes2 >= (int)m_open_files.size()) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 
 | ||||
| 		TRY(validate_fd(fildes)); | ||||
| 		if (fildes == fildes2) | ||||
| 			return fildes; | ||||
| 
 | ||||
| 		(void)close(fildes2); | ||||
| 		 | ||||
| 		m_open_files[fildes2] = m_open_files[fildes]; | ||||
| 		m_open_files[fildes2]->flags &= ~O_CLOEXEC; | ||||
| 
 | ||||
| 		if (m_open_files[fildes]->flags & O_WRONLY && m_open_files[fildes]->inode->is_pipe()) | ||||
| 			((Pipe*)m_open_files[fildes]->inode.ptr())->clone_writing(); | ||||
| 
 | ||||
| 		return fildes; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::seek(int fd, off_t offset, int whence) | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 
 | ||||
| 		off_t new_offset = 0; | ||||
| 
 | ||||
| 		switch (whence) | ||||
| 		{ | ||||
| 			case SEEK_CUR: | ||||
| 				new_offset = m_open_files[fd]->offset + offset; | ||||
| 				break; | ||||
| 			case SEEK_END: | ||||
| 				new_offset = m_open_files[fd]->inode->size() - offset; | ||||
| 				break; | ||||
| 			case SEEK_SET: | ||||
| 				new_offset = offset; | ||||
| 				break; | ||||
| 			default: | ||||
| 				return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (new_offset < 0) | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 
 | ||||
| 		m_open_files[fd]->offset = new_offset; | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<off_t> OpenFileDescriptorSet::tell(int fd) const | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		return m_open_files[fd]->offset; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::fstat(int fd, struct stat* out) const | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 
 | ||||
| 		auto inode = m_open_files[fd]->inode; | ||||
| 		out->st_dev		= inode->dev(); | ||||
| 		out->st_ino		= inode->ino(); | ||||
| 		out->st_mode	= inode->mode().mode; | ||||
| 		out->st_nlink	= inode->nlink(); | ||||
| 		out->st_uid		= inode->uid(); | ||||
| 		out->st_gid		= inode->gid(); | ||||
| 		out->st_rdev	= inode->rdev(); | ||||
| 		out->st_size	= inode->size(); | ||||
| 		out->st_atim	= inode->atime(); | ||||
| 		out->st_mtim	= inode->mtime(); | ||||
| 		out->st_ctim	= inode->ctime(); | ||||
| 		out->st_blksize	= inode->blksize(); | ||||
| 		out->st_blocks	= inode->blocks(); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::close(int fd) | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 
 | ||||
| 		if (m_open_files[fd]->flags & O_WRONLY && m_open_files[fd]->inode->is_pipe()) | ||||
| 			((Pipe*)m_open_files[fd]->inode.ptr())->close_writing(); | ||||
| 		 | ||||
| 		m_open_files[fd].clear(); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	void OpenFileDescriptorSet::close_all() | ||||
| 	{ | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 			(void)close(fd); | ||||
| 	} | ||||
| 
 | ||||
| 	void OpenFileDescriptorSet::close_cloexec() | ||||
| 	{ | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			if (m_open_files[fd]->flags & O_CLOEXEC) | ||||
| 				(void)close(fd); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<size_t> OpenFileDescriptorSet::read(int fd, void* buffer, size_t count) | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		auto& open_file = m_open_files[fd]; | ||||
| 		size_t nread = TRY(open_file->inode->read(open_file->offset, buffer, count)); | ||||
| 		open_file->offset += nread; | ||||
| 		return nread; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<size_t> OpenFileDescriptorSet::write(int fd, const void* buffer, size_t count) | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		auto& open_file = m_open_files[fd]; | ||||
| 		size_t nwrite = TRY(open_file->inode->write(open_file->offset, buffer, count)); | ||||
| 		open_file->offset += nwrite; | ||||
| 		return nwrite; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		auto& open_file = m_open_files[fd]; | ||||
| 		TRY(open_file->inode->read_next_directory_entries(open_file->offset, list, list_size)); | ||||
| 		open_file->offset++; | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::StringView> OpenFileDescriptorSet::path_of(int fd) const | ||||
| 	{ | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		return m_open_files[fd]->path.sv(); | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::validate_fd(int fd) const | ||||
| 	{ | ||||
| 		if (fd < 0 || fd >= (int)m_open_files.size()) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 		if (!m_open_files[fd]) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<int> OpenFileDescriptorSet::get_free_fd() const | ||||
| 	{ | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 			if (!m_open_files[fd]) | ||||
| 				return fd; | ||||
| 		return BAN::Error::from_errno(EMFILE); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> OpenFileDescriptorSet::get_free_fd_pair(int fds[2]) const | ||||
| 	{ | ||||
| 		size_t found = 0; | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (!m_open_files[fd]) | ||||
| 				fds[found++] = fd; | ||||
| 			if (found == 2) | ||||
| 				return {}; | ||||
| 		} | ||||
| 		return BAN::Error::from_errno(EMFILE); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -1,6 +1,5 @@ | |||
| #include <BAN/StringView.h> | ||||
| #include <kernel/CriticalScope.h> | ||||
| #include <kernel/FS/Pipe.h> | ||||
| #include <kernel/FS/VirtualFileSystem.h> | ||||
| #include <kernel/LockGuard.h> | ||||
| #include <kernel/Memory/Heap.h> | ||||
|  | @ -92,6 +91,7 @@ namespace Kernel | |||
| 
 | ||||
| 	Process::Process(const Credentials& credentials, pid_t pid) | ||||
| 		: m_credentials(credentials) | ||||
| 		, m_open_file_descriptors(m_credentials) | ||||
| 		, m_pid(pid) | ||||
| 		, m_tty(TTY::current()) | ||||
| 	{ } | ||||
|  | @ -135,13 +135,7 @@ namespace Kernel | |||
| 		} | ||||
| 
 | ||||
| 		m_threads.clear(); | ||||
| 
 | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			(void)sys_close(fd); | ||||
| 		} | ||||
| 		m_open_file_descriptors.close_all(); | ||||
| 
 | ||||
| 		// NOTE: We must unmap ranges while the page table is still alive
 | ||||
| 		for (auto* range : m_mapped_ranges) | ||||
|  | @ -282,15 +276,7 @@ namespace Kernel | |||
| 		forked->m_tty = m_tty; | ||||
| 		forked->m_working_directory = m_working_directory; | ||||
| 
 | ||||
| 		forked->m_open_files = m_open_files; | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			auto& openfd = open_file_description(fd); | ||||
| 			if (openfd.flags & O_WRONLY && openfd.inode->is_pipe()) | ||||
| 				((Pipe*)openfd.inode.ptr())->clone_writing(); | ||||
| 		} | ||||
| 		MUST(forked->m_open_file_descriptors.clone_from(m_open_file_descriptors)); | ||||
| 
 | ||||
| 		forked->m_userspace_info = m_userspace_info; | ||||
| 
 | ||||
|  | @ -339,14 +325,7 @@ namespace Kernel | |||
| 
 | ||||
| 		LockGuard lock_guard(m_lock); | ||||
| 
 | ||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (validate_fd(fd).is_error()) | ||||
| 				continue; | ||||
| 			auto& file = open_file_description(fd); | ||||
| 			if (file.flags & O_CLOEXEC) | ||||
| 				MUST(sys_close(fd)); | ||||
| 		} | ||||
| 		m_open_file_descriptors.close_cloexec(); | ||||
| 
 | ||||
| 		m_fixed_width_allocators.clear(); | ||||
| 		m_general_allocator.clear(); | ||||
|  | @ -513,34 +492,17 @@ namespace Kernel | |||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags) | ||||
| 	{ | ||||
| 		if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_CLOEXEC)) | ||||
| 			return BAN::Error::from_errno(ENOTSUP); | ||||
| 
 | ||||
| 		BAN::String absolute_path = TRY(absolute_path_of(path)); | ||||
| 
 | ||||
| 		auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)); | ||||
| 
 | ||||
| 		LockGuard _(m_lock); | ||||
| 		int fd = TRY(get_free_fd()); | ||||
| 		auto& open_file_description = m_open_files[fd]; | ||||
| 		open_file_description.inode = file.inode; | ||||
| 		open_file_description.path = BAN::move(file.canonical_path); | ||||
| 		open_file_description.offset = 0; | ||||
| 		open_file_description.flags = flags; | ||||
| 
 | ||||
| 		return fd; | ||||
| 		BAN::String absolute_path = TRY(absolute_path_of(path)); | ||||
| 		return TRY(m_open_file_descriptors.open(absolute_path, flags)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 
 | ||||
| 		BAN::String absolute_path; | ||||
| 		 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			TRY(validate_fd(fd)); | ||||
| 			TRY(absolute_path.append(open_file_description(fd).path)); | ||||
| 		} | ||||
| 		 | ||||
| 		TRY(absolute_path.append(TRY(m_open_file_descriptors.path_of(fd)))); | ||||
| 		TRY(absolute_path.push_back('/')); | ||||
| 		TRY(absolute_path.append(path)); | ||||
| 
 | ||||
|  | @ -550,149 +512,46 @@ namespace Kernel | |||
| 	BAN::ErrorOr<long> Process::sys_close(int fd) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		auto& open_file_description = this->open_file_description(fd); | ||||
| 		if (open_file_description.flags & O_WRONLY && open_file_description.inode->is_pipe()) | ||||
| 			((Pipe*)open_file_description.inode.ptr())->close_writing(); | ||||
| 		open_file_description.inode = nullptr; | ||||
| 		TRY(m_open_file_descriptors.close(fd)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count) | ||||
| 	{ | ||||
| 		OpenFileDescription open_fd_copy; | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			TRY(validate_fd(fd)); | ||||
| 			open_fd_copy = open_file_description(fd); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!(open_fd_copy.flags & O_RDONLY)) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 
 | ||||
| 		size_t nread = TRY(open_fd_copy.inode->read(open_fd_copy.offset, buffer, count)); | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			MUST(validate_fd(fd)); | ||||
| 			open_file_description(fd).offset += nread; | ||||
| 		} | ||||
| 
 | ||||
| 		return nread; | ||||
| 		LockGuard _(m_lock); | ||||
| 		return TRY(m_open_file_descriptors.read(fd, buffer, count)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count) | ||||
| 	{ | ||||
| 		OpenFileDescription open_fd_copy; | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			TRY(validate_fd(fd)); | ||||
| 			open_fd_copy = open_file_description(fd); | ||||
| 		} | ||||
| 
 | ||||
| 		if (!(open_fd_copy.flags & O_WRONLY)) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 
 | ||||
| 		size_t nwrite = TRY(open_fd_copy.inode->write(open_fd_copy.offset, buffer, count)); | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			MUST(validate_fd(fd)); | ||||
| 			open_file_description(fd).offset += nwrite; | ||||
| 		} | ||||
| 
 | ||||
| 		return nwrite; | ||||
| 		LockGuard _(m_lock); | ||||
| 		return TRY(m_open_file_descriptors.write(fd, buffer, count)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_pipe(int fildes[2]) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 
 | ||||
| 		auto pipe = TRY(Pipe::create(m_credentials)); | ||||
| 
 | ||||
| 		TRY(get_free_fd_pair(fildes)); | ||||
| 
 | ||||
| 		auto& openfd_read = m_open_files[fildes[0]]; | ||||
| 		openfd_read.inode = pipe; | ||||
| 		openfd_read.flags = O_RDONLY; | ||||
| 		openfd_read.offset = 0; | ||||
| 		openfd_read.path.clear(); | ||||
| 
 | ||||
| 		auto& openfd_write = m_open_files[fildes[1]]; | ||||
| 		openfd_write.inode = pipe; | ||||
| 		openfd_write.flags = O_WRONLY; | ||||
| 		openfd_write.offset = 0; | ||||
| 		openfd_write.path.clear(); | ||||
| 
 | ||||
| 		TRY(m_open_file_descriptors.pipe(fildes)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_dup2(int fildes, int fildes2) | ||||
| 	{ | ||||
| 		// FIXME: m_open_files should be BAN::Array<BAN::RefPtr<OpenFileDescription>, OPEN_MAX> for accurate dup2
 | ||||
| 
 | ||||
| 		if (fildes2 < 0 || fildes2 >= 100) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 
 | ||||
| 		LockGuard _(m_lock); | ||||
| 
 | ||||
| 		TRY(validate_fd(fildes)); | ||||
| 		if (fildes == fildes2) | ||||
| 			return fildes; | ||||
| 
 | ||||
| 		if (m_open_files.size() <= (size_t)fildes2) | ||||
| 			TRY(m_open_files.resize(fildes2 + 1)); | ||||
| 		 | ||||
| 		if (!validate_fd(fildes2).is_error()) | ||||
| 			TRY(sys_close(fildes2)); | ||||
| 		 | ||||
| 		m_open_files[fildes2] = m_open_files[fildes]; | ||||
| 		m_open_files[fildes2].flags &= ~O_CLOEXEC; | ||||
| 
 | ||||
| 		if (m_open_files[fildes].flags & O_WRONLY && m_open_files[fildes].inode->is_pipe()) | ||||
| 			((Pipe*)m_open_files[fildes].inode.ptr())->clone_writing(); | ||||
| 
 | ||||
| 		return fildes; | ||||
| 		return TRY(m_open_file_descriptors.dup2(fildes, fildes2)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(validate_fd(fd)); | ||||
| 
 | ||||
| 		auto& open_fd = open_file_description(fd); | ||||
| 
 | ||||
| 		off_t new_offset = 0; | ||||
| 
 | ||||
| 		switch (whence) | ||||
| 		{ | ||||
| 			case SEEK_CUR: | ||||
| 				new_offset = open_fd.offset + offset; | ||||
| 				break; | ||||
| 			case SEEK_END: | ||||
| 				new_offset = open_fd.inode->size() - offset; | ||||
| 				break; | ||||
| 			case SEEK_SET: | ||||
| 				new_offset = offset; | ||||
| 				break; | ||||
| 			default: | ||||
| 				return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (new_offset < 0) | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		open_fd.offset = new_offset; | ||||
| 
 | ||||
| 		TRY(m_open_file_descriptors.seek(fd, offset, whence)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_tell(int fd) | ||||
| 	{ | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(validate_fd(fd)); | ||||
| 		return open_file_description(fd).offset; | ||||
| 		return TRY(m_open_file_descriptors.tell(fd)); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_creat(BAN::StringView path, mode_t mode) | ||||
|  | @ -727,28 +586,8 @@ namespace Kernel | |||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out) | ||||
| 	{ | ||||
| 		OpenFileDescription open_fd_copy; | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			TRY(validate_fd(fd)); | ||||
| 			open_fd_copy = open_file_description(fd); | ||||
| 		} | ||||
| 
 | ||||
| 		out->st_dev		= open_fd_copy.inode->dev(); | ||||
| 		out->st_ino		= open_fd_copy.inode->ino(); | ||||
| 		out->st_mode	= open_fd_copy.inode->mode().mode; | ||||
| 		out->st_nlink	= open_fd_copy.inode->nlink(); | ||||
| 		out->st_uid		= open_fd_copy.inode->uid(); | ||||
| 		out->st_gid		= open_fd_copy.inode->gid(); | ||||
| 		out->st_rdev	= open_fd_copy.inode->rdev(); | ||||
| 		out->st_size	= open_fd_copy.inode->size(); | ||||
| 		out->st_atim	= open_fd_copy.inode->atime(); | ||||
| 		out->st_mtim	= open_fd_copy.inode->mtime(); | ||||
| 		out->st_ctim	= open_fd_copy.inode->ctime(); | ||||
| 		out->st_blksize	= open_fd_copy.inode->blksize(); | ||||
| 		out->st_blocks	= open_fd_copy.inode->blocks(); | ||||
| 
 | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(m_open_file_descriptors.fstat(fd, out)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -762,22 +601,8 @@ namespace Kernel | |||
| 
 | ||||
| 	BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) | ||||
| 	{ | ||||
| 		OpenFileDescription open_fd_copy; | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			TRY(validate_fd(fd)); | ||||
| 			open_fd_copy = open_file_description(fd); | ||||
| 		} | ||||
| 
 | ||||
| 		TRY(open_fd_copy.inode->read_next_directory_entries(open_fd_copy.offset, list, list_size)); | ||||
| 
 | ||||
| 		{ | ||||
| 			LockGuard _(m_lock); | ||||
| 			MUST(validate_fd(fd)); | ||||
| 			open_file_description(fd).offset = open_fd_copy.offset + 1; | ||||
| 		} | ||||
| 
 | ||||
| 		LockGuard _(m_lock); | ||||
| 		TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size)); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
|  | @ -1131,52 +956,4 @@ namespace Kernel | |||
| 		return absolute_path; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> Process::validate_fd(int fd) | ||||
| 	{ | ||||
| 		ASSERT(m_lock.is_locked()); | ||||
| 		if (fd < 0 || m_open_files.size() <= (size_t)fd || !m_open_files[fd].inode) | ||||
| 			return BAN::Error::from_errno(EBADF); | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	Process::OpenFileDescription& Process::open_file_description(int fd) | ||||
| 	{ | ||||
| 		ASSERT(m_lock.is_locked()); | ||||
| 		MUST(validate_fd(fd)); | ||||
| 		return m_open_files[fd]; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<int> Process::get_free_fd() | ||||
| 	{ | ||||
| 		ASSERT(m_lock.is_locked()); | ||||
| 		for (size_t fd = 0; fd < m_open_files.size(); fd++) | ||||
| 			if (!m_open_files[fd].inode) | ||||
| 				return fd; | ||||
| 		TRY(m_open_files.push_back({})); | ||||
| 		return m_open_files.size() - 1; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> Process::get_free_fd_pair(int fds[2]) | ||||
| 	{ | ||||
| 		ASSERT(m_lock.is_locked()); | ||||
| 		int found = 0; | ||||
| 		for (size_t fd = 0; fd < m_open_files.size(); fd++) | ||||
| 		{ | ||||
| 			if (!m_open_files[fd].inode) | ||||
| 			{ | ||||
| 				fds[found++] = fd; | ||||
| 				if (found >= 2) | ||||
| 					return {}; | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		while (found < 2) | ||||
| 		{ | ||||
| 			TRY(m_open_files.push_back({})); | ||||
| 			fds[found++] = m_open_files.size() - 1; | ||||
| 		} | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
		Reference in New Issue