forked from Bananymous/banan-os
				
			Kernel: Move open file descriptors to their own class
This simplifies code a lot :)
This commit is contained in:
		
							parent
							
								
									a337f414fc
								
							
						
					
					
						commit
						a2f5ad7bed
					
				|  | @ -33,6 +33,7 @@ set(KERNEL_SOURCES | ||||||
| 	kernel/Memory/kmalloc.cpp | 	kernel/Memory/kmalloc.cpp | ||||||
| 	kernel/Memory/PhysicalRange.cpp | 	kernel/Memory/PhysicalRange.cpp | ||||||
| 	kernel/Memory/VirtualRange.cpp | 	kernel/Memory/VirtualRange.cpp | ||||||
|  | 	kernel/OpenFileDescriptorSet.cpp | ||||||
| 	kernel/Panic.cpp | 	kernel/Panic.cpp | ||||||
| 	kernel/PCI.cpp | 	kernel/PCI.cpp | ||||||
| 	kernel/PIC.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/GeneralAllocator.h> | ||||||
| #include <kernel/Memory/Heap.h> | #include <kernel/Memory/Heap.h> | ||||||
| #include <kernel/Memory/VirtualRange.h> | #include <kernel/Memory/VirtualRange.h> | ||||||
|  | #include <kernel/OpenFileDescriptorSet.h> | ||||||
| #include <kernel/SpinLock.h> | #include <kernel/SpinLock.h> | ||||||
| #include <kernel/Terminal/TTY.h> | #include <kernel/Terminal/TTY.h> | ||||||
| #include <kernel/Thread.h> | #include <kernel/Thread.h> | ||||||
| 
 | 
 | ||||||
| #include <sys/stat.h> |  | ||||||
| #include <termios.h> | #include <termios.h> | ||||||
| 
 | 
 | ||||||
| namespace LibELF { class ELF; } | namespace LibELF { class ELF; } | ||||||
|  | @ -128,20 +128,6 @@ namespace Kernel | ||||||
| 		BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const; | 		BAN::ErrorOr<BAN::String> absolute_path_of(BAN::StringView) const; | ||||||
| 
 | 
 | ||||||
| 	private: | 	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 | 		struct ExitStatus | ||||||
| 		{ | 		{ | ||||||
| 			Semaphore semaphore; | 			Semaphore semaphore; | ||||||
|  | @ -152,7 +138,8 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 		Credentials m_credentials; | 		Credentials m_credentials; | ||||||
| 
 | 
 | ||||||
| 		BAN::Vector<OpenFileDescription> m_open_files; | 		OpenFileDescriptorSet m_open_file_descriptors; | ||||||
|  | 
 | ||||||
| 		BAN::Vector<VirtualRange*> m_mapped_ranges; | 		BAN::Vector<VirtualRange*> m_mapped_ranges; | ||||||
| 
 | 
 | ||||||
| 		mutable RecursiveSpinLock m_lock; | 		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 <BAN/StringView.h> | ||||||
| #include <kernel/CriticalScope.h> | #include <kernel/CriticalScope.h> | ||||||
| #include <kernel/FS/Pipe.h> |  | ||||||
| #include <kernel/FS/VirtualFileSystem.h> | #include <kernel/FS/VirtualFileSystem.h> | ||||||
| #include <kernel/LockGuard.h> | #include <kernel/LockGuard.h> | ||||||
| #include <kernel/Memory/Heap.h> | #include <kernel/Memory/Heap.h> | ||||||
|  | @ -92,6 +91,7 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	Process::Process(const Credentials& credentials, pid_t pid) | 	Process::Process(const Credentials& credentials, pid_t pid) | ||||||
| 		: m_credentials(credentials) | 		: m_credentials(credentials) | ||||||
|  | 		, m_open_file_descriptors(m_credentials) | ||||||
| 		, m_pid(pid) | 		, m_pid(pid) | ||||||
| 		, m_tty(TTY::current()) | 		, m_tty(TTY::current()) | ||||||
| 	{ } | 	{ } | ||||||
|  | @ -135,13 +135,7 @@ namespace Kernel | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		m_threads.clear(); | 		m_threads.clear(); | ||||||
| 
 | 		m_open_file_descriptors.close_all(); | ||||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) |  | ||||||
| 		{ |  | ||||||
| 			if (validate_fd(fd).is_error()) |  | ||||||
| 				continue; |  | ||||||
| 			(void)sys_close(fd); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		// NOTE: We must unmap ranges while the page table is still alive
 | 		// NOTE: We must unmap ranges while the page table is still alive
 | ||||||
| 		for (auto* range : m_mapped_ranges) | 		for (auto* range : m_mapped_ranges) | ||||||
|  | @ -282,15 +276,7 @@ namespace Kernel | ||||||
| 		forked->m_tty = m_tty; | 		forked->m_tty = m_tty; | ||||||
| 		forked->m_working_directory = m_working_directory; | 		forked->m_working_directory = m_working_directory; | ||||||
| 
 | 
 | ||||||
| 		forked->m_open_files = m_open_files; | 		MUST(forked->m_open_file_descriptors.clone_from(m_open_file_descriptors)); | ||||||
| 		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(); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		forked->m_userspace_info = m_userspace_info; | 		forked->m_userspace_info = m_userspace_info; | ||||||
| 
 | 
 | ||||||
|  | @ -339,14 +325,7 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 		LockGuard lock_guard(m_lock); | 		LockGuard lock_guard(m_lock); | ||||||
| 
 | 
 | ||||||
| 		for (int fd = 0; fd < (int)m_open_files.size(); fd++) | 		m_open_file_descriptors.close_cloexec(); | ||||||
| 		{ |  | ||||||
| 			if (validate_fd(fd).is_error()) |  | ||||||
| 				continue; |  | ||||||
| 			auto& file = open_file_description(fd); |  | ||||||
| 			if (file.flags & O_CLOEXEC) |  | ||||||
| 				MUST(sys_close(fd)); |  | ||||||
| 		} |  | ||||||
| 
 | 
 | ||||||
| 		m_fixed_width_allocators.clear(); | 		m_fixed_width_allocators.clear(); | ||||||
| 		m_general_allocator.clear(); | 		m_general_allocator.clear(); | ||||||
|  | @ -513,34 +492,17 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_open(BAN::StringView path, int flags) | 	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); | 		LockGuard _(m_lock); | ||||||
| 		int fd = TRY(get_free_fd()); | 		BAN::String absolute_path = TRY(absolute_path_of(path)); | ||||||
| 		auto& open_file_description = m_open_files[fd]; | 		return TRY(m_open_file_descriptors.open(absolute_path, flags)); | ||||||
| 		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::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags) | 	BAN::ErrorOr<long> Process::sys_openat(int fd, BAN::StringView path, int flags) | ||||||
| 	{ | 	{ | ||||||
|  | 		LockGuard _(m_lock); | ||||||
|  | 
 | ||||||
| 		BAN::String absolute_path; | 		BAN::String absolute_path; | ||||||
| 		 | 		TRY(absolute_path.append(TRY(m_open_file_descriptors.path_of(fd)))); | ||||||
| 		{ |  | ||||||
| 			LockGuard _(m_lock); |  | ||||||
| 			TRY(validate_fd(fd)); |  | ||||||
| 			TRY(absolute_path.append(open_file_description(fd).path)); |  | ||||||
| 		} |  | ||||||
| 		 |  | ||||||
| 		TRY(absolute_path.push_back('/')); | 		TRY(absolute_path.push_back('/')); | ||||||
| 		TRY(absolute_path.append(path)); | 		TRY(absolute_path.append(path)); | ||||||
| 
 | 
 | ||||||
|  | @ -550,149 +512,46 @@ namespace Kernel | ||||||
| 	BAN::ErrorOr<long> Process::sys_close(int fd) | 	BAN::ErrorOr<long> Process::sys_close(int fd) | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		TRY(validate_fd(fd)); | 		TRY(m_open_file_descriptors.close(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; |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count) | 	BAN::ErrorOr<long> Process::sys_read(int fd, void* buffer, size_t count) | ||||||
| 	{ | 	{ | ||||||
| 		OpenFileDescription open_fd_copy; | 		LockGuard _(m_lock); | ||||||
| 
 | 		return TRY(m_open_file_descriptors.read(fd, buffer, count)); | ||||||
| 		{ |  | ||||||
| 			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; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count) | 	BAN::ErrorOr<long> Process::sys_write(int fd, const void* buffer, size_t count) | ||||||
| 	{ | 	{ | ||||||
| 		OpenFileDescription open_fd_copy; | 		LockGuard _(m_lock); | ||||||
| 
 | 		return TRY(m_open_file_descriptors.write(fd, buffer, count)); | ||||||
| 		{ |  | ||||||
| 			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; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_pipe(int fildes[2]) | 	BAN::ErrorOr<long> Process::sys_pipe(int fildes[2]) | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 
 | 		TRY(m_open_file_descriptors.pipe(fildes)); | ||||||
| 		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(); |  | ||||||
| 
 |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_dup2(int fildes, int fildes2) | 	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); | 		LockGuard _(m_lock); | ||||||
| 
 | 		return TRY(m_open_file_descriptors.dup2(fildes, fildes2)); | ||||||
| 		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; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence) | 	BAN::ErrorOr<long> Process::sys_seek(int fd, off_t offset, int whence) | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		TRY(validate_fd(fd)); | 		TRY(m_open_file_descriptors.seek(fd, offset, whence)); | ||||||
| 
 |  | ||||||
| 		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; |  | ||||||
| 
 |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_tell(int fd) | 	BAN::ErrorOr<long> Process::sys_tell(int fd) | ||||||
| 	{ | 	{ | ||||||
| 		LockGuard _(m_lock); | 		LockGuard _(m_lock); | ||||||
| 		TRY(validate_fd(fd)); | 		return TRY(m_open_file_descriptors.tell(fd)); | ||||||
| 		return open_file_description(fd).offset; |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_creat(BAN::StringView path, mode_t mode) | 	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) | 	BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* out) | ||||||
| 	{ | 	{ | ||||||
| 		OpenFileDescription open_fd_copy; | 		LockGuard _(m_lock); | ||||||
| 
 | 		TRY(m_open_file_descriptors.fstat(fd, out)); | ||||||
| 		{ |  | ||||||
| 			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(); |  | ||||||
| 
 |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -762,22 +601,8 @@ namespace Kernel | ||||||
| 
 | 
 | ||||||
| 	BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) | 	BAN::ErrorOr<long> Process::sys_read_dir_entries(int fd, DirectoryEntryList* list, size_t list_size) | ||||||
| 	{ | 	{ | ||||||
| 		OpenFileDescription open_fd_copy; | 		LockGuard _(m_lock); | ||||||
| 
 | 		TRY(m_open_file_descriptors.read_dir_entries(fd, list, list_size)); | ||||||
| 		{ |  | ||||||
| 			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; |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		return 0; | 		return 0; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -1131,52 +956,4 @@ namespace Kernel | ||||||
| 		return absolute_path; | 		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