Compare commits

...

10 Commits

11 changed files with 215 additions and 163 deletions

View File

@ -102,8 +102,6 @@ namespace Kernel
BAN::ErrorOr<long> open_inode(VirtualFileSystem::File&&, int flags);
BAN::ErrorOr<void> create_file_or_dir(const VirtualFileSystem::File& parent, BAN::StringView path, mode_t mode) const;
BAN::ErrorOr<long> open_file_impl(const VirtualFileSystem::File& parent, BAN::StringView path, int oflag, mode_t = 0);
BAN::ErrorOr<long> sys_open(const char* path, int, mode_t);
BAN::ErrorOr<long> sys_openat(int, const char* path, int, mode_t);
BAN::ErrorOr<long> sys_close(int fd);
BAN::ErrorOr<long> sys_read(int fd, void* buffer, size_t count);
@ -111,15 +109,12 @@ namespace Kernel
BAN::ErrorOr<long> sys_access(const char* path, int amode);
BAN::ErrorOr<long> sys_create_dir(const char*, mode_t);
BAN::ErrorOr<long> sys_unlink(const char*);
BAN::ErrorOr<long> readlink_impl(BAN::RefPtr<Inode>, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_readlink(const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize);
BAN::ErrorOr<long> sys_pread(int fd, void* buffer, size_t count, off_t offset);
BAN::ErrorOr<long> sys_chmod(const char* path, mode_t mode);
BAN::ErrorOr<long> sys_fchmod(int fildes, mode_t mode);
BAN::ErrorOr<long> sys_chown(const char* path, uid_t uid, gid_t gid);
BAN::ErrorOr<long> sys_fchmodat(int fd, const char* path, mode_t mode, int flag);
BAN::ErrorOr<long> sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag);
BAN::ErrorOr<long> sys_socket(int domain, int type, int protocol);
BAN::ErrorOr<long> sys_getsockname(int socket, sockaddr* address, socklen_t* address_len);
@ -148,9 +143,7 @@ namespace Kernel
BAN::ErrorOr<long> sys_truncate(int fd, off_t length);
BAN::ErrorOr<long> sys_fstat(int fd, struct stat*);
BAN::ErrorOr<long> sys_fstatat(int fd, const char* path, struct stat* buf, int flag);
BAN::ErrorOr<long> sys_stat(const char* path, struct stat* buf, int flag);
BAN::ErrorOr<long> sys_realpath(const char* path, char* buffer);
@ -220,6 +213,8 @@ namespace Kernel
Process(const Credentials&, pid_t pid, pid_t parent, pid_t sid, pid_t pgrp);
static Process* create_process(const Credentials&, pid_t parent, pid_t sid = 0, pid_t pgrp = 0);
BAN::ErrorOr<VirtualFileSystem::File> find_file(int fd, const char* path, int flags);
BAN::ErrorOr<void> validate_string_access(const char*);
BAN::ErrorOr<void> validate_pointer_access_check(const void*, size_t, bool needs_write);
BAN::ErrorOr<void> validate_pointer_access(const void*, size_t, bool needs_write);

View File

@ -351,6 +351,28 @@ namespace Kernel
return read_from_vec_of_str(m_environ, offset, buffer);
}
BAN::ErrorOr<VirtualFileSystem::File> Process::find_file(int fd, const char* path, int flags)
{
ASSERT(m_process_lock.is_locked());
if (path)
TRY(validate_string_access(path));
VirtualFileSystem::File parent_file;
if (path && path[0] == '/')
parent_file = VirtualFileSystem::get().root_file();
else if (fd == AT_FDCWD)
parent_file = TRY(m_working_directory.clone());
else
parent_file = TRY(m_open_file_descriptors.file_of(fd));
auto file = path
? TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags))
: BAN::move(parent_file);
return file;
}
BAN::ErrorOr<long> Process::sys_exit(int status)
{
ASSERT(this == &Process::current());
@ -849,14 +871,31 @@ namespace Kernel
return TRY(m_open_file_descriptors.open(BAN::move(file), flags));
}
BAN::ErrorOr<long> Process::open_file_impl(const VirtualFileSystem::File& parent, BAN::StringView path, int flags, mode_t mode)
BAN::ErrorOr<long> Process::sys_openat(int fd, const char* 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);
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, path, flags | O_NOFOLLOW);
TRY(validate_string_access(path));
VirtualFileSystem::File parent_file;
if (path[0] == '/')
parent_file = VirtualFileSystem::get().root_file();
else if (fd == AT_FDCWD)
parent_file = TRY(m_working_directory.clone());
else
{
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);
parent_file = TRY(m_open_file_descriptors.file_of(fd));
}
auto file_or_error = VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags | O_NOFOLLOW);
VirtualFileSystem::File file;
if (file_or_error.is_error())
@ -865,8 +904,8 @@ namespace Kernel
return file_or_error.release_error();
// FIXME: There is a race condition between next two lines
TRY(create_file_or_dir(parent, path, (mode & 0777) | Inode::Mode::IFREG));
file = TRY(VirtualFileSystem::get().file_from_relative_path(parent, m_credentials, path, flags));
TRY(create_file_or_dir(parent_file, path, (mode & 0777) | Inode::Mode::IFREG));
file = TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags));
}
else
{
@ -879,13 +918,13 @@ namespace Kernel
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_relative_path(parent, m_credentials, path, flags));
file = TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags));
}
auto inode = file.inode;
ASSERT(inode);
int fd = TRY(m_open_file_descriptors.open(BAN::move(file), flags));
fd = TRY(m_open_file_descriptors.open(BAN::move(file), flags));
// Open controlling terminal
if (!(flags & O_NOCTTY) && inode->is_tty() && is_session_leader() && !m_controlling_terminal)
@ -894,37 +933,6 @@ namespace Kernel
return fd;
}
BAN::ErrorOr<long> Process::sys_open(const char* path, int flags, mode_t mode)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (path[0] == '/')
return open_file_impl(VirtualFileSystem::get().root_file(), path, flags, mode);
return open_file_impl(m_working_directory, path, flags, mode);
}
BAN::ErrorOr<long> Process::sys_openat(int fd, const char* path, int flags, mode_t mode)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
VirtualFileSystem::File parent_file;
if (fd == AT_FDCWD)
parent_file = TRY(m_working_directory.clone());
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);
parent_file = TRY(m_open_file_descriptors.file_of(fd));
}
return open_file_impl(parent_file, path, flags, mode);
}
BAN::ErrorOr<long> Process::sys_close(int fd)
{
LockGuard _(m_process_lock);
@ -1008,37 +1016,20 @@ namespace Kernel
return 0;
}
BAN::ErrorOr<long> Process::readlink_impl(BAN::RefPtr<Inode> inode, char* buffer, size_t bufsize)
{
// FIXME: no allocation needed
auto link_target = TRY(inode->link_target());
size_t byte_count = BAN::Math::min<size_t>(link_target.size(), bufsize);
memcpy(buffer, link_target.data(), byte_count);
return byte_count;
}
BAN::ErrorOr<long> Process::sys_readlink(const char* path, char* buffer, size_t bufsize)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
TRY(validate_pointer_access(buffer, bufsize, true));
auto absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_NOFOLLOW | O_RDONLY));
return readlink_impl(file.inode, buffer, bufsize);
}
BAN::ErrorOr<long> Process::sys_readlinkat(int fd, const char* path, char* buffer, size_t bufsize)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
TRY(validate_pointer_access(buffer, bufsize, true));
auto parent_file = TRY(m_open_file_descriptors.file_of(fd));
auto file = TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, O_NOFOLLOW | O_RDONLY));
return readlink_impl(file.inode, buffer, bufsize);
auto inode = TRY(find_file(fd, path, O_NOFOLLOW | O_RDONLY)).inode;
// FIXME: no allocation needed
auto link_target = TRY(inode->link_target());
const size_t byte_count = BAN::Math::min<size_t>(link_target.size(), bufsize);
memcpy(buffer, link_target.data(), byte_count);
return byte_count;
}
BAN::ErrorOr<long> Process::sys_pread(int fd, void* buffer, size_t count, off_t offset)
@ -1049,41 +1040,51 @@ namespace Kernel
return TRY(inode->read(offset, { (uint8_t*)buffer, count }));
}
BAN::ErrorOr<long> Process::sys_chmod(const char* path, mode_t mode)
BAN::ErrorOr<long> Process::sys_fchmodat(int fd, const char* path, mode_t mode, int flag)
{
if (mode & S_IFMASK)
return BAN::Error::from_errno(EINVAL);
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
auto absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_WRONLY));
TRY(file.inode->chmod(mode));
return 0;
}
BAN::ErrorOr<long> Process::sys_fchmod(int fildes, mode_t mode)
{
if (mode & S_IFMASK)
if (flag & ~AT_SYMLINK_NOFOLLOW)
return BAN::Error::from_errno(EINVAL);
if (flag == AT_SYMLINK_NOFOLLOW)
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
auto inode = TRY(m_open_file_descriptors.inode_of(fildes));
auto inode = TRY(find_file(fd, path, flag)).inode;
if (!m_credentials.is_superuser() && inode->uid() != m_credentials.euid())
{
dwarnln("cannot chmod uid {} vs {}", inode->uid(), m_credentials.euid());
return BAN::Error::from_errno(EPERM);
}
TRY(inode->chmod(mode));
return 0;
}
BAN::ErrorOr<long> Process::sys_chown(const char* path, uid_t uid, gid_t gid)
BAN::ErrorOr<long> Process::sys_fchownat(int fd, const char* path, uid_t uid, gid_t gid, int flag)
{
LockGuard _(m_process_lock);
TRY(validate_string_access(path));
if (flag & ~AT_SYMLINK_NOFOLLOW)
return BAN::Error::from_errno(EINVAL);
if (flag == AT_SYMLINK_NOFOLLOW)
flag = O_NOFOLLOW;
auto absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_WRONLY));
TRY(file.inode->chown(uid, gid));
LockGuard _(m_process_lock);
auto inode = TRY(find_file(fd, path, flag)).inode;
if (uid != -1 && !m_credentials.is_superuser())
return BAN::Error::from_errno(EPERM);
if (gid != -1 && !m_credentials.is_superuser() && (m_credentials.euid() != uid || !m_credentials.has_egid(gid)))
return BAN::Error::from_errno(EPERM);
if (uid == -1)
uid = inode->uid();
if (gid == -1)
gid = inode->gid();
TRY(inode->chown(uid, gid));
return 0;
}
@ -1414,62 +1415,31 @@ namespace Kernel
return {};
}
static void read_stat_from_inode(BAN::RefPtr<Inode> inode, struct stat* out)
BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flag)
{
out->st_dev = inode->dev();
out->st_ino = inode->ino();
out->st_mode = inode->mode().mode;
out->st_nlink = inode->nlink();
out->st_uid = inode->uid();
out->st_gid = inode->gid();
out->st_rdev = inode->rdev();
out->st_size = inode->size();
out->st_atim = inode->atime();
out->st_mtim = inode->mtime();
out->st_ctim = inode->ctime();
out->st_blksize = inode->blksize();
out->st_blocks = inode->blocks();
}
BAN::ErrorOr<long> Process::sys_fstat(int fd, struct stat* buf)
{
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buf, sizeof(struct stat), true));
auto inode = TRY(m_open_file_descriptors.inode_of(fd));
read_stat_from_inode(inode, buf);
return 0;
}
BAN::ErrorOr<long> Process::sys_fstatat(int fd, const char* path, struct stat* buf, int flags)
{
if (flags & ~AT_SYMLINK_NOFOLLOW)
if (flag & ~AT_SYMLINK_NOFOLLOW)
return BAN::Error::from_errno(EINVAL);
if (flags == AT_SYMLINK_NOFOLLOW)
flags = O_NOFOLLOW;
if (flag == AT_SYMLINK_NOFOLLOW)
flag = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buf, sizeof(struct stat), true));
auto parent_file = TRY(m_open_file_descriptors.file_of(fd));
auto inode = TRY(VirtualFileSystem::get().file_from_relative_path(parent_file, m_credentials, path, flags)).inode;
read_stat_from_inode(inode, buf);
return 0;
}
auto inode = TRY(find_file(fd, path, flag)).inode;
buf->st_dev = inode->dev();
buf->st_ino = inode->ino();
buf->st_mode = inode->mode().mode;
buf->st_nlink = inode->nlink();
buf->st_uid = inode->uid();
buf->st_gid = inode->gid();
buf->st_rdev = inode->rdev();
buf->st_size = inode->size();
buf->st_atim = inode->atime();
buf->st_mtim = inode->mtime();
buf->st_ctim = inode->ctime();
buf->st_blksize = inode->blksize();
buf->st_blocks = inode->blocks();
BAN::ErrorOr<long> Process::sys_stat(const char* path, struct stat* buf, int flags)
{
if (flags & ~AT_SYMLINK_NOFOLLOW)
return BAN::Error::from_errno(EINVAL);
if (flags == AT_SYMLINK_NOFOLLOW)
flags = O_NOFOLLOW;
LockGuard _(m_process_lock);
TRY(validate_pointer_access(buf, sizeof(struct stat), true));
auto absolute_path = TRY(absolute_path_of(path));
auto inode = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, flags)).inode;
read_stat_from_inode(inode, buf);
return 0;
}
@ -1481,7 +1451,7 @@ namespace Kernel
auto absolute_path = TRY(absolute_path_of(path));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_SEARCH));
auto file = TRY(VirtualFileSystem::get().file_from_absolute_path(m_credentials, absolute_path, O_RDONLY));
if (file.canonical_path.size() >= PATH_MAX)
return BAN::Error::from_errno(ENAMETOOLONG);

View File

@ -15,7 +15,7 @@ int open(const char* path, int oflag, ...)
mode_t mode = va_arg(args, mode_t);
va_end(args);
return syscall(SYS_OPEN, path, oflag, __UMASKED_MODE(mode));
return openat(AT_FDCWD, path, oflag, mode);
}
int openat(int fd, const char* path, int oflag, ...)

View File

@ -11,7 +11,6 @@ __BEGIN_DECLS
O(SYS_WRITE, write) \
O(SYS_TERMID, termid) \
O(SYS_CLOSE, close) \
O(SYS_OPEN, open) \
O(SYS_OPENAT, openat) \
O(SYS_SEEK, seek) \
O(SYS_TELL, tell) \
@ -21,7 +20,6 @@ __BEGIN_DECLS
O(SYS_EXEC, exec) \
O(SYS_SLEEP, sleep) \
O(SYS_WAIT, wait) \
O(SYS_FSTAT, fstat) \
O(SYS_READ_DIR, readdir) \
O(SYS_SET_UID, setuid) \
O(SYS_SET_GID, setgid) \
@ -48,21 +46,18 @@ __BEGIN_DECLS
O(SYS_FCNTL, fcntl) \
O(SYS_NANOSLEEP, nanosleep) \
O(SYS_FSTATAT, fstatat) \
O(SYS_STAT, stat) \
O(SYS_SYNC, sync) \
O(SYS_MMAP, mmap) \
O(SYS_MUNMAP, munmap) \
O(SYS_TTY_CTRL, tty_ctrl) \
O(SYS_POWEROFF, poweroff) \
O(SYS_CHMOD, chmod) \
O(SYS_FCHMOD, fchmod) \
O(SYS_FCHMODAT, fchmodat) \
O(SYS_CREATE_DIR, create_dir) \
O(SYS_UNLINK, unlink) \
O(SYS_READLINK, readlink) \
O(SYS_READLINKAT, readlinkat) \
O(SYS_MSYNC, msync) \
O(SYS_PREAD, pread) \
O(SYS_CHOWN, chown) \
O(SYS_FCHOWNAT, fchownat) \
O(SYS_LOAD_KEYMAP, load_keymap) \
O(SYS_SOCKET, socket) \
O(SYS_BIND, bind) \

View File

@ -1,6 +1,5 @@
#include <BAN/Assert.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/syscall.h>
@ -10,17 +9,22 @@ mode_t __umask = 0;
int chmod(const char* path, mode_t mode)
{
return syscall(SYS_CHMOD, path, mode);
return fchmodat(AT_FDCWD, path, mode, 0);
}
int fchmod(int fildes, mode_t mode)
{
return syscall(SYS_FCHMOD, fildes, mode);
return fchmodat(fildes, nullptr, mode, 0);
}
int fchmodat(int fildes, const char* path, mode_t mode, int flag)
{
return syscall(SYS_FCHMODAT, fildes, path, mode, flag);
}
int fstat(int fildes, struct stat* buf)
{
return syscall(SYS_FSTAT, fildes, buf);
return fstatat(fildes, nullptr, buf, 0);
}
int fstatat(int fd, const char* __restrict path, struct stat* __restrict buf, int flag)
@ -30,12 +34,12 @@ int fstatat(int fd, const char* __restrict path, struct stat* __restrict buf, in
int lstat(const char* __restrict path, struct stat* __restrict buf)
{
return syscall(SYS_STAT, path, buf, AT_SYMLINK_NOFOLLOW);
return fstatat(AT_FDCWD, path, buf, AT_SYMLINK_NOFOLLOW);
}
int stat(const char* __restrict path, struct stat* __restrict buf)
{
return syscall(SYS_STAT, path, buf, 0);
return fstatat(AT_FDCWD, path, buf, 0);
}
mode_t umask(mode_t cmask)

View File

@ -3,6 +3,7 @@
#include <kernel/Syscall.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <stdarg.h>
#include <stdio.h>
@ -86,7 +87,7 @@ ssize_t write(int fildes, const void* buf, size_t nbyte)
ssize_t readlink(const char* __restrict path, char* __restrict buf, size_t bufsize)
{
return syscall(SYS_READLINK, path, buf, bufsize);
return readlinkat(AT_FDCWD, path, buf, bufsize);
}
ssize_t readlinkat(int fd, const char* __restrict path, char* __restrict buf, size_t bufsize)
@ -314,7 +315,22 @@ int chdir(const char* path)
int chown(const char* path, uid_t owner, gid_t group)
{
return syscall(SYS_CHOWN, path, owner, group);
return fchownat(AT_FDCWD, path, owner, group, 0);
}
int lchown(const char* path, uid_t owner, gid_t group)
{
return fchownat(AT_FDCWD, path, owner, group, AT_SYMLINK_NOFOLLOW);
}
int fchown(int fildes, uid_t owner, gid_t group)
{
return fchownat(fildes, nullptr, owner, group, 0);
}
int fchownat(int fd, const char* path, uid_t owner, gid_t group, int flag)
{
return syscall(SYS_FCHOWNAT, fd, path, owner, group, flag);
}
void sync(void)

View File

@ -557,7 +557,7 @@ static void handle_dynamic(LoadedElf& elf)
if (auto ret = syscall(SYS_REALPATH, path_buffer, realpath); ret < 0)
print_error_and_exit("realpath", ret);
int library_fd = syscall(SYS_OPEN, realpath, O_RDONLY);
int library_fd = syscall(SYS_OPENAT, AT_FDCWD, realpath, O_RDONLY);
if (library_fd < 0)
print_error_and_exit("could not open library", library_fd);
@ -882,7 +882,7 @@ int _entry(int argc, char** argv, char** envp, int fd)
argc--;
argv++;
fd = syscall(SYS_OPEN, argv[0], O_RDONLY);
fd = syscall(SYS_OPENAT, AT_FDCWD, argv[0], O_RDONLY);
if (fd < 0)
print_error_and_exit("could not open program", fd);
}

View File

@ -68,7 +68,7 @@ static int s_random_fd;
void init_random()
{
s_random_fd = syscall(SYS_OPEN, "/dev/random", O_RDONLY);
s_random_fd = syscall(SYS_OPENAT, AT_FDCWD, "/dev/random", O_RDONLY);
if (s_random_fd < 0)
print_error_and_exit("could not open /dev/random", s_random_fd);
}

View File

@ -342,6 +342,54 @@ BAN::Optional<int> execute_builtin(BAN::Vector<BAN::String>& args, int fd_in, in
while (*current)
fprintf(fout, "%s\n", *current++);
}
else if (args.front() == "cd"_sv)
{
if (args.size() > 2)
{
fprintf(fout, "cd: too many arguments\n");
return 1;
}
BAN::StringView path;
if (args.size() == 1)
{
if (const char* path_env = getenv("HOME"))
path = path_env;
else
return 0;
}
else
path = args[1];
if (chdir(path.data()) == -1)
ERROR_RETURN("chdir", 1);
}
else if (args.front() == "time"_sv)
{
args.remove(0);
timespec start, end;
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1)
ERROR_RETURN("clock_gettime", 1);
int ret = execute_command(args, fd_in, fd_out);
if (clock_gettime(CLOCK_MONOTONIC, &end) == -1)
ERROR_RETURN("clock_gettime", 1);
uint64_t total_ns = 0;
total_ns += (end.tv_sec - start.tv_sec) * 1'000'000'000;
total_ns += end.tv_nsec - start.tv_nsec;
int secs = total_ns / 1'000'000'000;
int msecs = (total_ns % 1'000'000'000) / 1'000'000;
fprintf(fout, "took %d.%03d s\n", secs, msecs);
return ret;
}
else if (args.front() == "start-gui"_sv)
{
pid_t pid = fork();

View File

@ -130,7 +130,7 @@ int open_server_fd()
exit(1);
}
if (chmod("/tmp/resolver.sock", 0777) == -1)
if (chmod(LibGUI::s_window_server_socket.data(), 0777) == -1)
{
perror("chmod");
exit(1);

View File

@ -21,6 +21,7 @@ struct simple_entry_t
{
BAN::String name;
struct stat st;
BAN::String link;
};
struct full_entry_t
@ -117,6 +118,8 @@ BAN::String build_time_string(BAN::Time time)
int list_directory(const BAN::String& path, config_t config)
{
static char link_buffer[PATH_MAX];
BAN::Vector<simple_entry_t> entries;
struct stat st;
@ -131,7 +134,16 @@ int list_directory(const BAN::String& path, config_t config)
int ret = 0;
if (!S_ISDIR(st.st_mode))
{
MUST(entries.emplace_back(path, st));
if (S_ISLNK(st.st_mode))
{
if (readlink(path.data(), link_buffer, sizeof(link_buffer)) == -1)
perror("readlink");
else
MUST(entries.back().link.append(link_buffer));
}
}
else
{
DIR* dirp = opendir(path.data());
@ -155,6 +167,13 @@ int list_directory(const BAN::String& path, config_t config)
}
MUST(entries.emplace_back(BAN::StringView(dirent->d_name), st));
if (S_ISLNK(st.st_mode))
{
if (readlinkat(dirfd(dirp), dirent->d_name, link_buffer, sizeof(link_buffer)) == -1)
perror("readlink");
else
MUST(entries.back().link.append(link_buffer));
}
}
closedir(dirp);
@ -214,6 +233,11 @@ int list_directory(const BAN::String& path, config_t config)
GET_ENTRY_STRING(time, time);
full_entry.full_name = MUST(BAN::String::formatted("{}{}\e[m", entry_color(entry.st.st_mode), entry.name));
if (S_ISLNK(entry.st.st_mode))
{
MUST(full_entry.full_name.append(" -> "_sv));
MUST(full_entry.full_name.append(entry.link));
}
MUST(full_entries.push_back(BAN::move(full_entry)));
}