kernel+libc+ln: Add support for userspace hard link creation
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
apio 2023-05-27 11:32:40 +02:00
parent a98e9e8009
commit bd8aaa917f
Signed by: apio
GPG Key ID: B8A7D06E42258954
9 changed files with 88 additions and 6 deletions

View File

@ -5,16 +5,21 @@
Result<int> luna_main(int argc, char** argv)
{
StringView target;
StringView link;
StringView linkpath;
bool create_symlink { false };
os::ArgumentParser parser;
parser.add_description("Create symbolic links.");
parser.add_description("Create links between files.");
parser.add_system_program_info("ln"_sv);
parser.add_positional_argument(target, "target", true);
parser.add_positional_argument(link, "linkpath", true);
parser.add_positional_argument(linkpath, "linkpath", true);
parser.add_switch_argument(create_symlink, 's', "symbolic"_sv, "create symlinks instead of hard links"_sv);
parser.parse(argc, argv);
if (symlink(target.chars(), link.chars()) < 0)
auto link_function = create_symlink ? symlink : link;
if (link_function(target.chars(), linkpath.chars()) < 0)
{
perror("ln");
return 1;

View File

@ -62,6 +62,11 @@ class MountInode : public VFS::Inode, public LinkedListNode<MountInode>
return m_mount_root_inode->gid();
}
nlink_t nlinks() const override
{
return m_mount_root_inode->nlinks();
}
Result<void> chmod(mode_t mode) override
{
return m_mount_root_inode->chmod(mode);

View File

@ -116,6 +116,11 @@ namespace VFS
virtual mode_t mode() const = 0;
virtual nlink_t nlinks() const
{
return 1;
}
virtual u32 uid() const
{
return 0;

View File

@ -94,6 +94,11 @@ namespace TmpFS
return m_gid;
}
nlink_t nlinks() const override
{
return (nlink_t)m_nlinks;
}
Result<void> chmod(mode_t mode) override
{
m_mode = mode;
@ -200,6 +205,11 @@ namespace TmpFS
return m_gid;
}
nlink_t nlinks() const override
{
return (nlink_t)m_nlinks;
}
Result<void> chmod(mode_t) override
{
return {};
@ -329,6 +339,11 @@ namespace TmpFS
return m_gid;
}
nlink_t nlinks() const override
{
return (nlink_t)m_nlinks;
}
Result<void> chmod(mode_t mode) override
{
m_mode = mode;

View File

@ -2,6 +2,7 @@
#include "memory/MemoryManager.h"
#include "sys/Syscall.h"
#include "thread/Scheduler.h"
#include <bits/atfile.h>
#include <luna/PathParser.h>
Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
@ -88,3 +89,36 @@ Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
return nread;
}
Result<u64> sys_linkat(Registers*, SyscallArgs args)
{
int olddirfd = (int)args[0];
auto oldpath = TRY(MemoryManager::strdup_from_user(args[1]));
int newdirfd = (int)args[2];
auto newpath = TRY(MemoryManager::strdup_from_user(args[3]));
int flags = (int)args[4];
auto* current = Scheduler::current();
auto parser = TRY(PathParser::create(newpath.chars()));
auto parent = TRY(parser.dirname());
// FIXME: Use AT_SYMLINK_FOLLOW.
auto target = TRY(current->resolve_atfile(olddirfd, oldpath, flags & AT_EMPTY_PATH, false));
if (target->type() == VFS::InodeType::Directory) return err(EPERM);
auto parent_inode = TRY(current->resolve_atfile(newdirfd, parent, false, true));
if (target->fs() != parent_inode->fs()) return err(EXDEV);
if (!VFS::can_write(parent_inode, current->auth)) return err(EACCES);
auto child_name = TRY(parser.basename());
TRY(VFS::validate_filename(child_name.view()));
TRY(parent_inode->add_entry(target, child_name.chars()));
return 0;
}

View File

@ -38,7 +38,7 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
kstat.st_ino = inode->inode_number();
kstat.st_mode = make_mode(inode->mode(), inode->type());
kstat.st_nlink = 1; // FIXME: Count hard links to files.
kstat.st_nlink = inode->nlinks();
kstat.st_uid = inode->uid();
kstat.st_gid = inode->gid();
kstat.st_size = inode->size();

View File

@ -145,6 +145,12 @@ extern "C"
/* Read the contents of a symbolic link relative to a file descriptor. */
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t max);
/* Create a hard link. */
int link(const char* oldpath, const char* newpath);
/* Create a hard link relative to a file descriptor. */
int linkat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath, int flags);
#ifdef __cplusplus
}
#endif

View File

@ -430,4 +430,16 @@ extern "C"
long rc = syscall(SYS_readlinkat, dirfd, path, buf, max);
__errno_return(rc, ssize_t);
}
int link(const char* oldpath, const char* newpath)
{
long rc = syscall(SYS_linkat, AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
__errno_return(rc, int);
}
int linkat(int olddirfd, const char* oldpath, int newdirfd, const char* newpath, int flags)
{
long rc = syscall(SYS_linkat, olddirfd, oldpath, newdirfd, newpath, flags);
__errno_return(rc, int);
}
}

View File

@ -5,7 +5,7 @@
_e(lseek) _e(mkdir) _e(execve) _e(fork) _e(waitpid) _e(getppid) _e(fcntl) _e(getdents) _e(getuid) _e(geteuid) \
_e(getgid) _e(getegid) _e(setuid) _e(setgid) _e(seteuid) _e(setegid) _e(fchmodat) _e(fchownat) _e(ioctl) \
_e(fstatat) _e(chdir) _e(getcwd) _e(unlinkat) _e(uname) _e(sethostname) _e(dup2) _e(pipe) _e(mount) \
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask)
_e(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat) _e(umask) _e(linkat)
enum Syscalls
{