kernel+libc+libos+ls: Add readlink()
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
b61307e5cb
commit
1a6ad11462
10
apps/ls.cpp
10
apps/ls.cpp
@ -85,6 +85,8 @@ Result<int> luna_main(int argc, char** argv)
|
||||
struct stat st;
|
||||
TRY(os::FileSystem::stat({ dirfd, file.view() }, st, false));
|
||||
|
||||
auto link = TRY(os::FileSystem::readlink({ dirfd, file.view() }));
|
||||
|
||||
StringView owner;
|
||||
StringView group;
|
||||
|
||||
@ -92,14 +94,14 @@ Result<int> luna_main(int argc, char** argv)
|
||||
|
||||
if (!human_readable && !si)
|
||||
{
|
||||
os::println("%6o %u %4s %4s %10lu %s", st.st_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
st.st_size, file.chars());
|
||||
os::println("%6o %u %4s %4s %10lu %s%s%s", st.st_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
st.st_size, file.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
else
|
||||
{
|
||||
auto size = TRY(to_dynamic_unit(st.st_size, 10, false, si ? Unit::SI : Unit::Binary, false));
|
||||
os::println("%6o %u %4s %4s %6s %s", st.st_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
size.chars(), file.chars());
|
||||
os::println("%6o %u %4s %4s %6s %s%s%s", st.st_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||
size.chars(), file.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,3 +62,29 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Result<u64> sys_readlinkat(Registers*, SyscallArgs args)
|
||||
{
|
||||
int dirfd = (int)args[0];
|
||||
auto path = TRY(MemoryManager::strdup_from_user(args[1]));
|
||||
char* buf = (char*)args[2];
|
||||
usize bufsiz = (usize)args[3];
|
||||
|
||||
auto* current = Scheduler::current();
|
||||
|
||||
auto symlink = TRY(current->resolve_atfile(dirfd, path, true, false));
|
||||
|
||||
if (symlink->type() != VFS::InodeType::Symlink) return err(EINVAL);
|
||||
|
||||
auto linkpath = TRY(symlink->readlink());
|
||||
check(!linkpath.is_empty());
|
||||
|
||||
usize nread = linkpath.length();
|
||||
if (nread > bufsiz) nread = bufsiz;
|
||||
|
||||
kdbgln("readlink: reading %zu bytes from symlink (%s)", nread, linkpath.chars());
|
||||
|
||||
if (!MemoryManager::copy_to_user(buf, linkpath.chars(), nread)) return err(EFAULT);
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
@ -139,6 +139,12 @@ extern "C"
|
||||
/* Create a symbolic link relative to a file descriptor. */
|
||||
int symlinkat(const char* target, int dirfd, const char* linkpath);
|
||||
|
||||
/* Read the contents of a symbolic link. */
|
||||
ssize_t readlink(const char* path, char* buf, size_t max);
|
||||
|
||||
/* 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);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
@ -418,4 +418,16 @@ extern "C"
|
||||
long rc = syscall(SYS_symlinkat, target, dirfd, linkpath);
|
||||
__errno_return(rc, int);
|
||||
}
|
||||
|
||||
ssize_t readlink(const char* path, char* buf, size_t max)
|
||||
{
|
||||
long rc = syscall(SYS_readlinkat, AT_FDCWD, path, buf, max);
|
||||
__errno_return(rc, ssize_t);
|
||||
}
|
||||
|
||||
ssize_t readlinkat(int dirfd, const char* path, char* buf, size_t max)
|
||||
{
|
||||
long rc = syscall(SYS_readlinkat, dirfd, path, buf, max);
|
||||
__errno_return(rc, ssize_t);
|
||||
}
|
||||
}
|
||||
|
@ -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(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat)
|
||||
|
||||
enum Syscalls
|
||||
{
|
||||
|
@ -21,6 +21,8 @@ namespace os
|
||||
|
||||
Result<void> remove_tree(const Path& path);
|
||||
|
||||
Result<String> readlink(const Path& path);
|
||||
|
||||
Result<String> working_directory();
|
||||
Result<String> home_directory();
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <luna/PathParser.h>
|
||||
#include <luna/String.h>
|
||||
#include <os/Directory.h>
|
||||
#include <os/FileSystem.h>
|
||||
@ -68,6 +69,23 @@ namespace os::FileSystem
|
||||
return remove(path);
|
||||
}
|
||||
|
||||
Result<String> readlink(const Path& path)
|
||||
{
|
||||
struct stat st;
|
||||
TRY(stat(path, st, false));
|
||||
if (!S_ISLNK(st.st_mode)) return String {};
|
||||
|
||||
char* buf = TRY(make_array<char>(st.st_size + 1));
|
||||
auto guard = make_scope_guard([buf] { delete[] buf; });
|
||||
usize nread = TRY(
|
||||
Result<usize>::from_syscall(syscall(SYS_readlinkat, path.dirfd(), path.name().chars(), buf, st.st_size)));
|
||||
|
||||
buf[nread] = '\0';
|
||||
guard.deactivate();
|
||||
|
||||
return String { buf, nread };
|
||||
}
|
||||
|
||||
Result<String> working_directory()
|
||||
{
|
||||
char* ptr = getcwd(NULL, 0);
|
||||
|
Loading…
Reference in New Issue
Block a user