kernel+libc+ln: Add support for userspace hard link creation
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
a98e9e8009
commit
bd8aaa917f
13
apps/ln.cpp
13
apps/ln.cpp
@ -5,16 +5,21 @@
|
|||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
{
|
{
|
||||||
StringView target;
|
StringView target;
|
||||||
StringView link;
|
StringView linkpath;
|
||||||
|
|
||||||
|
bool create_symlink { false };
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
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_system_program_info("ln"_sv);
|
||||||
parser.add_positional_argument(target, "target", true);
|
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);
|
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");
|
perror("ln");
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -62,6 +62,11 @@ class MountInode : public VFS::Inode, public LinkedListNode<MountInode>
|
|||||||
return m_mount_root_inode->gid();
|
return m_mount_root_inode->gid();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlink_t nlinks() const override
|
||||||
|
{
|
||||||
|
return m_mount_root_inode->nlinks();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> chmod(mode_t mode) override
|
Result<void> chmod(mode_t mode) override
|
||||||
{
|
{
|
||||||
return m_mount_root_inode->chmod(mode);
|
return m_mount_root_inode->chmod(mode);
|
||||||
|
@ -116,6 +116,11 @@ namespace VFS
|
|||||||
|
|
||||||
virtual mode_t mode() const = 0;
|
virtual mode_t mode() const = 0;
|
||||||
|
|
||||||
|
virtual nlink_t nlinks() const
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
virtual u32 uid() const
|
virtual u32 uid() const
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -94,6 +94,11 @@ namespace TmpFS
|
|||||||
return m_gid;
|
return m_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlink_t nlinks() const override
|
||||||
|
{
|
||||||
|
return (nlink_t)m_nlinks;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> chmod(mode_t mode) override
|
Result<void> chmod(mode_t mode) override
|
||||||
{
|
{
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
@ -200,6 +205,11 @@ namespace TmpFS
|
|||||||
return m_gid;
|
return m_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlink_t nlinks() const override
|
||||||
|
{
|
||||||
|
return (nlink_t)m_nlinks;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> chmod(mode_t) override
|
Result<void> chmod(mode_t) override
|
||||||
{
|
{
|
||||||
return {};
|
return {};
|
||||||
@ -329,6 +339,11 @@ namespace TmpFS
|
|||||||
return m_gid;
|
return m_gid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nlink_t nlinks() const override
|
||||||
|
{
|
||||||
|
return (nlink_t)m_nlinks;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> chmod(mode_t mode) override
|
Result<void> chmod(mode_t mode) override
|
||||||
{
|
{
|
||||||
m_mode = mode;
|
m_mode = mode;
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "memory/MemoryManager.h"
|
#include "memory/MemoryManager.h"
|
||||||
#include "sys/Syscall.h"
|
#include "sys/Syscall.h"
|
||||||
#include "thread/Scheduler.h"
|
#include "thread/Scheduler.h"
|
||||||
|
#include <bits/atfile.h>
|
||||||
#include <luna/PathParser.h>
|
#include <luna/PathParser.h>
|
||||||
|
|
||||||
Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
|
Result<u64> sys_unlinkat(Registers*, SyscallArgs args)
|
||||||
@ -88,3 +89,36 @@ Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
return nread;
|
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;
|
||||||
|
}
|
||||||
|
@ -38,7 +38,7 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
kstat.st_ino = inode->inode_number();
|
kstat.st_ino = inode->inode_number();
|
||||||
kstat.st_mode = make_mode(inode->mode(), inode->type());
|
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_uid = inode->uid();
|
||||||
kstat.st_gid = inode->gid();
|
kstat.st_gid = inode->gid();
|
||||||
kstat.st_size = inode->size();
|
kstat.st_size = inode->size();
|
||||||
|
@ -145,6 +145,12 @@ extern "C"
|
|||||||
/* Read the contents of a symbolic link relative to a file descriptor. */
|
/* 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);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -430,4 +430,16 @@ extern "C"
|
|||||||
long rc = syscall(SYS_readlinkat, dirfd, path, buf, max);
|
long rc = syscall(SYS_readlinkat, dirfd, path, buf, max);
|
||||||
__errno_return(rc, ssize_t);
|
__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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(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(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(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
|
enum Syscalls
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user