Kernel: Implement more POSIX compliant open() and openat() syscalls
This commit is contained in:
		
							parent
							
								
									401b460d75
								
							
						
					
					
						commit
						838d31fa41
					
				| 
						 | 
				
			
			@ -2,6 +2,7 @@
 | 
			
		|||
 | 
			
		||||
#include <BAN/Array.h>
 | 
			
		||||
#include <kernel/FS/Inode.h>
 | 
			
		||||
#include <kernel/FS/VirtualFileSystem.h>
 | 
			
		||||
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <sys/stat.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -21,7 +22,7 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		BAN::ErrorOr<void> clone_from(const OpenFileDescriptorSet&);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<int> open(BAN::RefPtr<Inode>, int flags);
 | 
			
		||||
		BAN::ErrorOr<int> open(VirtualFileSystem::File, int flags);
 | 
			
		||||
		BAN::ErrorOr<int> open(BAN::StringView absolute_path, int flags);
 | 
			
		||||
 | 
			
		||||
		BAN::ErrorOr<int> socket(int domain, int type, int protocol);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -55,32 +55,16 @@ namespace Kernel
 | 
			
		|||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::RefPtr<Inode> inode, int flags)
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::open(VirtualFileSystem::File file, int flags)
 | 
			
		||||
	{
 | 
			
		||||
		ASSERT(inode);
 | 
			
		||||
		ASSERT(!inode->mode().ifdir());
 | 
			
		||||
		ASSERT(file.inode);
 | 
			
		||||
 | 
			
		||||
		if (flags & ~(O_RDONLY | O_WRONLY))
 | 
			
		||||
		if (flags & ~(O_ACCMODE | O_NOFOLLOW | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_DIRECTORY | O_CREAT | O_EXCL | O_NONBLOCK))
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		int fd = TRY(get_free_fd());
 | 
			
		||||
		// FIXME: path?
 | 
			
		||||
		m_open_files[fd] = TRY(BAN::RefPtr<OpenFileDescription>::create(inode, ""_sv, 0, flags));
 | 
			
		||||
 | 
			
		||||
		return fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
 | 
			
		||||
	{
 | 
			
		||||
		if (flags & ~(O_RDONLY | O_WRONLY | O_NOFOLLOW | O_SEARCH | O_APPEND | O_TRUNC | O_CLOEXEC | O_TTY_INIT | O_DIRECTORY | O_NONBLOCK))
 | 
			
		||||
			return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
 | 
			
		||||
		int access_mask = O_EXEC | O_RDONLY | O_WRONLY | O_SEARCH;
 | 
			
		||||
		if ((flags & access_mask) != O_RDWR && __builtin_popcount(flags & access_mask) != 1)
 | 
			
		||||
		if ((flags & O_ACCMODE) != O_RDWR && __builtin_popcount(flags & O_ACCMODE) != 1)
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags));
 | 
			
		||||
 | 
			
		||||
		if ((flags & O_DIRECTORY) && !file.inode->mode().ifdir())
 | 
			
		||||
			return BAN::Error::from_errno(ENOTDIR);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -93,6 +77,11 @@ namespace Kernel
 | 
			
		|||
		return fd;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::open(BAN::StringView absolute_path, int flags)
 | 
			
		||||
	{
 | 
			
		||||
		return open(TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)), flags);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<int> OpenFileDescriptorSet::socket(int domain, int type, int protocol)
 | 
			
		||||
	{
 | 
			
		||||
		bool valid_protocol = true;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -664,9 +664,9 @@ namespace Kernel
 | 
			
		|||
			return BAN::Error::from_errno(EEXIST);
 | 
			
		||||
 | 
			
		||||
		if (Inode::Mode(mode).ifdir())
 | 
			
		||||
			TRY(parent_inode->create_directory(file_name, mode, m_credentials.euid(), m_credentials.egid()));
 | 
			
		||||
			TRY(parent_inode->create_directory(file_name, mode, m_credentials.euid(), parent_inode->gid()));
 | 
			
		||||
		else
 | 
			
		||||
			TRY(parent_inode->create_file(file_name, mode, m_credentials.euid(), m_credentials.egid()));
 | 
			
		||||
			TRY(parent_inode->create_file(file_name, mode, m_credentials.euid(), parent_inode->gid()));
 | 
			
		||||
 | 
			
		||||
		return {};
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -704,38 +704,51 @@ namespace Kernel
 | 
			
		|||
	{
 | 
			
		||||
		ASSERT(inode);
 | 
			
		||||
		LockGuard _(m_process_lock);
 | 
			
		||||
		return TRY(m_open_file_descriptors.open(inode, flags));
 | 
			
		||||
		return TRY(m_open_file_descriptors.open(VirtualFileSystem::File { .inode = inode, .canonical_path = {} }, flags));
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	BAN::ErrorOr<long> Process::open_file(BAN::StringView path, int flags, mode_t mode)
 | 
			
		||||
	{
 | 
			
		||||
		if ((flags & (O_DIRECTORY | O_CREAT)) == (O_DIRECTORY | O_CREAT))
 | 
			
		||||
			return BAN::Error::from_errno(EINVAL);
 | 
			
		||||
 | 
			
		||||
		LockGuard _(m_process_lock);
 | 
			
		||||
 | 
			
		||||
		BAN::String absolute_path = TRY(absolute_path_of(path));
 | 
			
		||||
 | 
			
		||||
		if (flags & O_CREAT)
 | 
			
		||||
		{
 | 
			
		||||
			if (flags & O_DIRECTORY)
 | 
			
		||||
				return BAN::Error::from_errno(ENOTSUP);
 | 
			
		||||
			auto file_or_error = VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_WRONLY);
 | 
			
		||||
			if (!file_or_error.is_error() && (flags & O_EXCL))
 | 
			
		||||
				return BAN::Error::from_errno(EEXIST);
 | 
			
		||||
		auto file_or_error = VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags | O_NOFOLLOW);
 | 
			
		||||
 | 
			
		||||
		VirtualFileSystem::File file;
 | 
			
		||||
		if (file_or_error.is_error())
 | 
			
		||||
		{
 | 
			
		||||
				if (file_or_error.error().get_error_code() == ENOENT)
 | 
			
		||||
					TRY(create_file_or_dir(path, Inode::Mode::IFREG | mode));
 | 
			
		||||
				else
 | 
			
		||||
			if (!(flags & O_CREAT) || file_or_error.error().get_error_code() != ENOENT)
 | 
			
		||||
				return file_or_error.release_error();
 | 
			
		||||
 | 
			
		||||
			// FIXME: There is a race condition between these lines
 | 
			
		||||
			TRY(create_file_or_dir(absolute_path, (mode & 0777) | Inode::Mode::IFREG));
 | 
			
		||||
			file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags));
 | 
			
		||||
		}
 | 
			
		||||
			flags &= ~O_CREAT;
 | 
			
		||||
		else
 | 
			
		||||
		{
 | 
			
		||||
			if ((flags & O_CREAT) && (flags & O_EXCL))
 | 
			
		||||
				return BAN::Error::from_errno(EEXIST);
 | 
			
		||||
 | 
			
		||||
			file = file_or_error.release_value();
 | 
			
		||||
			if (file.inode->mode().ifdir() && (flags & O_WRONLY))
 | 
			
		||||
				return BAN::Error::from_errno(EISDIR);
 | 
			
		||||
			if (!file.inode->mode().ifdir() && (flags & O_DIRECTORY))
 | 
			
		||||
				return BAN::Error::from_errno(ENOTDIR);
 | 
			
		||||
			if (file.inode->mode().iflnk() && !(flags & O_NOFOLLOW))
 | 
			
		||||
				file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		int fd = TRY(m_open_file_descriptors.open(absolute_path, flags));
 | 
			
		||||
		auto inode = MUST(m_open_file_descriptors.inode_of(fd));
 | 
			
		||||
		ASSERT(file.inode);
 | 
			
		||||
 | 
			
		||||
		int fd = TRY(m_open_file_descriptors.open(file, flags));
 | 
			
		||||
 | 
			
		||||
		// Open controlling terminal
 | 
			
		||||
		if ((flags & O_TTY_INIT) && !(flags & O_NOCTTY) && inode->is_tty() && is_session_leader() && !m_controlling_terminal)
 | 
			
		||||
			m_controlling_terminal = (TTY*)inode.ptr();
 | 
			
		||||
		if ((flags & O_TTY_INIT) && !(flags & O_NOCTTY) && file.inode->is_tty() && is_session_leader() && !m_controlling_terminal)
 | 
			
		||||
			m_controlling_terminal = (TTY*)file.inode.ptr();
 | 
			
		||||
 | 
			
		||||
		return fd;
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -753,10 +766,19 @@ namespace Kernel
 | 
			
		|||
 | 
			
		||||
		TRY(validate_string_access(path));
 | 
			
		||||
 | 
			
		||||
		// FIXME: handle O_SEARCH in fd
 | 
			
		||||
 | 
			
		||||
		BAN::String absolute_path;
 | 
			
		||||
 | 
			
		||||
		if (fd == AT_FDCWD)
 | 
			
		||||
			TRY(absolute_path.append(m_working_directory));
 | 
			
		||||
		else if (path[0] != '/')
 | 
			
		||||
		{
 | 
			
		||||
			int flags = TRY(m_open_file_descriptors.flags_of(fd));
 | 
			
		||||
			if (!(flags & O_RDONLY) && !(flags & O_SEARCH))
 | 
			
		||||
				return BAN::Error::from_errno(EBADF);
 | 
			
		||||
			if (!TRY(m_open_file_descriptors.inode_of(fd))->mode().ifdir())
 | 
			
		||||
				return BAN::Error::from_errno(ENOTDIR);
 | 
			
		||||
			TRY(absolute_path.append(TRY(m_open_file_descriptors.path_of(fd))));
 | 
			
		||||
		}
 | 
			
		||||
		TRY(absolute_path.push_back('/'));
 | 
			
		||||
		TRY(absolute_path.append(path));
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue