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)
|
||||
{
|
||||
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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user