Compare commits
31 Commits
bb7d460149
...
176864f623
Author | SHA1 | Date | |
---|---|---|---|
176864f623 | |||
1e586ee982 | |||
35c96024d4 | |||
9653497051 | |||
39a713333d | |||
52cbcb627f | |||
d55edf77cd | |||
e60b8cfdf0 | |||
0483f38038 | |||
1722b995c9 | |||
5afe1ec3a6 | |||
2c239f7d19 | |||
6fb25e2499 | |||
2ab3860d04 | |||
a35c8d74fb | |||
9422b8c878 | |||
1c4a26a381 | |||
01489a12d9 | |||
5eaacd7b29 | |||
249453ac3f | |||
260c86e22c | |||
62e14e7580 | |||
38fae0c97b | |||
4dcee8f828 | |||
84c1871d30 | |||
3a51807fa6 | |||
9cdfdbc6f9 | |||
1094042a7d | |||
1a6ad11462 | |||
b61307e5cb | |||
04d074538f |
65
apps/ls.cpp
65
apps/ls.cpp
@ -4,56 +4,20 @@
|
|||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/File.h>
|
#include <os/File.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
|
#include <os/Mode.h>
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
|
||||||
struct UsernameCache
|
void find_user_and_group(struct stat& st, StringView& owner, StringView& group)
|
||||||
{
|
|
||||||
uid_t uid;
|
|
||||||
String name;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct GroupCache
|
|
||||||
{
|
|
||||||
gid_t gid;
|
|
||||||
String name;
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector<UsernameCache> g_user_cache;
|
|
||||||
Vector<GroupCache> g_group_cache;
|
|
||||||
|
|
||||||
Result<void> find_user_and_group(struct stat& st, StringView& owner, StringView& group)
|
|
||||||
{
|
|
||||||
for (const auto& user : g_user_cache)
|
|
||||||
{
|
|
||||||
if (user.uid == st.st_uid) owner = user.name.view();
|
|
||||||
}
|
|
||||||
if (owner.is_empty())
|
|
||||||
{
|
{
|
||||||
auto* pw = getpwuid(st.st_uid);
|
auto* pw = getpwuid(st.st_uid);
|
||||||
if (!pw) owner = "???";
|
if (!pw) owner = "???";
|
||||||
else
|
else
|
||||||
owner = pw->pw_name;
|
owner = pw->pw_name;
|
||||||
|
|
||||||
auto name = TRY(String::from_string_view(owner));
|
|
||||||
TRY(g_user_cache.try_append({ st.st_uid, move(name) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& grp : g_group_cache)
|
|
||||||
{
|
|
||||||
if (grp.gid == st.st_gid) group = grp.name.view();
|
|
||||||
}
|
|
||||||
if (group.is_empty())
|
|
||||||
{
|
|
||||||
auto* grp = getgrgid(st.st_gid);
|
auto* grp = getgrgid(st.st_gid);
|
||||||
if (!grp) group = "???";
|
if (!grp) group = "???";
|
||||||
else
|
else
|
||||||
group = grp->gr_name;
|
group = grp->gr_name;
|
||||||
|
|
||||||
auto name = TRY(String::from_string_view(group));
|
|
||||||
TRY(g_group_cache.try_append({ st.st_gid, move(name) }));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Result<int> luna_main(int argc, char** argv)
|
Result<int> luna_main(int argc, char** argv)
|
||||||
@ -65,6 +29,8 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
bool human_readable { false };
|
bool human_readable { false };
|
||||||
bool si { false };
|
bool si { false };
|
||||||
bool follow_symlink_args { false };
|
bool follow_symlink_args { false };
|
||||||
|
bool one_per_line { false };
|
||||||
|
bool list_directories { false };
|
||||||
|
|
||||||
os::ArgumentParser parser;
|
os::ArgumentParser parser;
|
||||||
parser.add_description("List files contained in a directory (defaults to '.', the current directory)"_sv);
|
parser.add_description("List files contained in a directory (defaults to '.', the current directory)"_sv);
|
||||||
@ -78,13 +44,17 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
parser.add_switch_argument(si, ' ', "si"_sv, "same as -h, but show sizes in powers of 10"_sv);
|
parser.add_switch_argument(si, ' ', "si"_sv, "same as -h, but show sizes in powers of 10"_sv);
|
||||||
parser.add_switch_argument(follow_symlink_args, 'H', "dereference-args"_sv,
|
parser.add_switch_argument(follow_symlink_args, 'H', "dereference-args"_sv,
|
||||||
"follow symbolic links listed as arguments"_sv);
|
"follow symbolic links listed as arguments"_sv);
|
||||||
|
parser.add_switch_argument(one_per_line, '1', ""_sv, "list one file per line"_sv);
|
||||||
|
parser.add_switch_argument(list_directories, 'd', "directory"_sv, "list directories instead of their contents"_sv);
|
||||||
parser.parse(argc, argv);
|
parser.parse(argc, argv);
|
||||||
|
|
||||||
Vector<String> files;
|
Vector<String> files;
|
||||||
int dirfd = AT_FDCWD;
|
int dirfd = AT_FDCWD;
|
||||||
SharedPtr<os::Directory> dir;
|
SharedPtr<os::Directory> dir;
|
||||||
|
|
||||||
if (os::FileSystem::is_directory(pathname, follow_symlink_args))
|
if (!long_list) follow_symlink_args = true;
|
||||||
|
|
||||||
|
if (os::FileSystem::is_directory(pathname, follow_symlink_args) && !list_directories)
|
||||||
{
|
{
|
||||||
dir = TRY(os::Directory::open(pathname));
|
dir = TRY(os::Directory::open(pathname));
|
||||||
dirfd = dir->fd();
|
dirfd = dir->fd();
|
||||||
@ -106,7 +76,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
|
|
||||||
if (!long_list)
|
if (!long_list)
|
||||||
{
|
{
|
||||||
auto list = TRY(String::join(files, " "_sv));
|
auto list = TRY(String::join(files, one_per_line ? "\n"_sv : " "_sv));
|
||||||
if (!list.is_empty()) os::println("%s", list.chars());
|
if (!list.is_empty()) os::println("%s", list.chars());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -116,21 +86,26 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
TRY(os::FileSystem::stat({ dirfd, file.view() }, st, false));
|
TRY(os::FileSystem::stat({ dirfd, file.view() }, st, false));
|
||||||
|
|
||||||
|
auto link = TRY(os::FileSystem::readlink({ dirfd, file.view() }));
|
||||||
|
|
||||||
StringView owner;
|
StringView owner;
|
||||||
StringView group;
|
StringView group;
|
||||||
|
|
||||||
TRY(find_user_and_group(st, owner, group));
|
find_user_and_group(st, owner, group);
|
||||||
|
|
||||||
|
char formatted_mode[11];
|
||||||
|
os::format_mode(st.st_mode, formatted_mode);
|
||||||
|
|
||||||
if (!human_readable && !si)
|
if (!human_readable && !si)
|
||||||
{
|
{
|
||||||
os::println("%6o %u %4s %4s %10lu %s", st.st_mode, st.st_nlink, owner.chars(), group.chars(),
|
os::println("%s %u %4s %4s %10lu %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||||
st.st_size, file.chars());
|
st.st_size, file.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto size = TRY(to_dynamic_unit(st.st_size, 10, false, si ? Unit::SI : Unit::Binary, false));
|
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(),
|
os::println("%s %u %4s %4s %6s %s%s%s", formatted_mode, st.st_nlink, owner.chars(), group.chars(),
|
||||||
size.chars(), file.chars());
|
size.chars(), file.chars(), link.is_empty() ? "" : " -> ", link.chars());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -88,7 +88,7 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
auto cmd = TRY(input_file->read_line());
|
auto cmd = TRY(input_file->read_line());
|
||||||
if (cmd.is_empty())
|
if (cmd.is_empty())
|
||||||
{
|
{
|
||||||
puts("exit");
|
if (interactive) puts("exit");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#include <os/ArgumentParser.h>
|
#include <os/ArgumentParser.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
|
#include <os/Mode.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
@ -10,7 +11,9 @@ static const char* file_type(mode_t mode)
|
|||||||
case S_IFREG: return "regular file";
|
case S_IFREG: return "regular file";
|
||||||
case S_IFDIR: return "directory";
|
case S_IFDIR: return "directory";
|
||||||
case S_IFCHR: return "character special device";
|
case S_IFCHR: return "character special device";
|
||||||
|
case S_IFBLK: return "block special device";
|
||||||
case S_IFLNK: return "symbolic link";
|
case S_IFLNK: return "symbolic link";
|
||||||
|
case S_IFIFO: return "pipe";
|
||||||
default: return "unknown file type";
|
default: return "unknown file type";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -30,10 +33,13 @@ Result<int> luna_main(int argc, char** argv)
|
|||||||
struct stat st;
|
struct stat st;
|
||||||
TRY(os::FileSystem::stat(path, st, follow_symlinks));
|
TRY(os::FileSystem::stat(path, st, follow_symlinks));
|
||||||
|
|
||||||
|
char buf[11];
|
||||||
|
os::format_mode(st.st_mode, buf);
|
||||||
|
|
||||||
printf(" File: %s\n", path.chars());
|
printf(" File: %s\n", path.chars());
|
||||||
printf(" Size: %zu (%s)\n", st.st_size, file_type(st.st_mode));
|
printf(" Size: %zu (%s)\n", st.st_size, file_type(st.st_mode));
|
||||||
printf("Inode: %lu Links: %lu\n", st.st_ino, st.st_nlink);
|
printf("Inode: %lu Links: %lu\n", st.st_ino, st.st_nlink);
|
||||||
printf(" Mode: %#o UID: %u GID: %u\n", st.st_mode & ~S_IFMT, st.st_uid, st.st_gid);
|
printf(" Mode: (%#o/%s) UID: %u GID: %u\n", st.st_mode & ~S_IFMT, buf, st.st_uid, st.st_gid);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,11 @@ class Pipe
|
|||||||
class PipeInodeBase : public VFS::FileInode
|
class PipeInodeBase : public VFS::FileInode
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
VFS::InodeType type() const override
|
||||||
|
{
|
||||||
|
return VFS::InodeType::FIFO;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> truncate(usize) override
|
Result<void> truncate(usize) override
|
||||||
{
|
{
|
||||||
return err(ENOTSUP);
|
return err(ENOTSUP);
|
||||||
|
@ -168,6 +168,11 @@ namespace VFS
|
|||||||
return inode->mode() & S_ISGID;
|
return inode->mode() & S_ISGID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool is_seekable(SharedPtr<Inode> inode)
|
||||||
|
{
|
||||||
|
return inode->type() != InodeType::FIFO && inode->type() != InodeType::CharacterDevice;
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs)
|
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs)
|
||||||
{
|
{
|
||||||
root_fs = fs;
|
root_fs = fs;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include <bits/makedev.h>
|
||||||
#include <luna/SharedPtr.h>
|
#include <luna/SharedPtr.h>
|
||||||
#include <luna/StaticString.h>
|
#include <luna/StaticString.h>
|
||||||
#include <luna/StringView.h>
|
#include <luna/StringView.h>
|
||||||
@ -12,8 +13,10 @@ namespace VFS
|
|||||||
{
|
{
|
||||||
RegularFile,
|
RegularFile,
|
||||||
Directory,
|
Directory,
|
||||||
Device,
|
CharacterDevice,
|
||||||
Symlink
|
BlockDevice,
|
||||||
|
Symlink,
|
||||||
|
FIFO,
|
||||||
};
|
};
|
||||||
|
|
||||||
class Inode;
|
class Inode;
|
||||||
@ -48,6 +51,8 @@ namespace VFS
|
|||||||
m_handles--;
|
m_handles--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual dev_t host_device_id() const = 0;
|
||||||
|
|
||||||
virtual ~FileSystem() = default;
|
virtual ~FileSystem() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -101,6 +106,11 @@ namespace VFS
|
|||||||
return StringView {};
|
return StringView {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual dev_t device_id() const
|
||||||
|
{
|
||||||
|
return luna_dev_makedev(0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
// Metadata accessors
|
// Metadata accessors
|
||||||
virtual usize size() const = 0;
|
virtual usize size() const = 0;
|
||||||
|
|
||||||
@ -252,7 +262,7 @@ namespace VFS
|
|||||||
|
|
||||||
InodeType type() const override
|
InodeType type() const override
|
||||||
{
|
{
|
||||||
return InodeType::Device;
|
return InodeType::CharacterDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~DeviceInode() = default;
|
virtual ~DeviceInode() = default;
|
||||||
@ -276,6 +286,8 @@ namespace VFS
|
|||||||
bool is_setuid(SharedPtr<Inode> inode);
|
bool is_setuid(SharedPtr<Inode> inode);
|
||||||
bool is_setgid(SharedPtr<Inode> inode);
|
bool is_setgid(SharedPtr<Inode> inode);
|
||||||
|
|
||||||
|
bool is_seekable(VFS::InodeType type);
|
||||||
|
|
||||||
Inode& root_inode();
|
Inode& root_inode();
|
||||||
|
|
||||||
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
|
Result<void> mount_root(SharedPtr<VFS::FileSystem> fs);
|
||||||
|
@ -18,6 +18,11 @@ class Device
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool is_block_device() const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
virtual bool blocking() const = 0;
|
virtual bool blocking() const = 0;
|
||||||
|
|
||||||
virtual ~Device() = default;
|
virtual ~Device() = default;
|
||||||
|
@ -74,4 +74,10 @@ namespace DeviceRegistry
|
|||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_t next_null_device_id()
|
||||||
|
{
|
||||||
|
static u32 next_minor = 0;
|
||||||
|
return luna_dev_makedev(0, next_minor++);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,4 +21,7 @@ namespace DeviceRegistry
|
|||||||
mode_t mode = 0666);
|
mode_t mode = 0666);
|
||||||
|
|
||||||
Result<void> init();
|
Result<void> init();
|
||||||
|
|
||||||
|
// Used for file systems (like tmpfs) that do not have a host device.
|
||||||
|
dev_t next_null_device_id();
|
||||||
}
|
}
|
||||||
|
@ -55,10 +55,18 @@ namespace TmpFS
|
|||||||
inode->set_fs(*this, {});
|
inode->set_fs(*this, {});
|
||||||
inode->set_inode_number(m_next_inode_number++, {});
|
inode->set_inode_number(m_next_inode_number++, {});
|
||||||
inode->set_device(device, {});
|
inode->set_device(device, {});
|
||||||
|
// FIXME: This should be queried from Device directly, but Device doesn't have an API to store and retrieve its
|
||||||
|
// device ID atm.
|
||||||
|
inode->set_device_id(luna_dev_makedev(major, minor), {});
|
||||||
|
|
||||||
return (SharedPtr<VFS::Inode>)inode;
|
return (SharedPtr<VFS::Inode>)inode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FileSystem::FileSystem()
|
||||||
|
{
|
||||||
|
m_host_device_id = DeviceRegistry::next_null_device_id();
|
||||||
|
}
|
||||||
|
|
||||||
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> parent)
|
Result<void> FileSystem::set_mount_dir(SharedPtr<VFS::Inode> parent)
|
||||||
{
|
{
|
||||||
return m_root_inode->replace_entry(parent, "..");
|
return m_root_inode->replace_entry(parent, "..");
|
||||||
|
@ -27,16 +27,23 @@ namespace TmpFS
|
|||||||
|
|
||||||
static Result<SharedPtr<VFS::FileSystem>> create();
|
static Result<SharedPtr<VFS::FileSystem>> create();
|
||||||
|
|
||||||
|
dev_t host_device_id() const override
|
||||||
|
{
|
||||||
|
return m_host_device_id;
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~FileSystem() = default;
|
virtual ~FileSystem() = default;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FileSystem() = default;
|
FileSystem();
|
||||||
|
|
||||||
void set_root(SharedPtr<VFS::Inode> root);
|
void set_root(SharedPtr<VFS::Inode> root);
|
||||||
|
|
||||||
SharedPtr<VFS::Inode> m_root_inode;
|
SharedPtr<VFS::Inode> m_root_inode;
|
||||||
|
|
||||||
Atomic<usize> m_next_inode_number { 2 };
|
Atomic<usize> m_next_inode_number { 2 };
|
||||||
|
|
||||||
|
dev_t m_host_device_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FileInode : public VFS::FileInode
|
class FileInode : public VFS::FileInode
|
||||||
@ -236,6 +243,11 @@ namespace TmpFS
|
|||||||
public:
|
public:
|
||||||
DeviceInode() = default;
|
DeviceInode() = default;
|
||||||
|
|
||||||
|
VFS::InodeType type() const override
|
||||||
|
{
|
||||||
|
return m_device->is_block_device() ? VFS::InodeType::BlockDevice : VFS::InodeType::CharacterDevice;
|
||||||
|
}
|
||||||
|
|
||||||
void set_fs(FileSystem& fs, Badge<FileSystem>)
|
void set_fs(FileSystem& fs, Badge<FileSystem>)
|
||||||
{
|
{
|
||||||
m_fs = &fs;
|
m_fs = &fs;
|
||||||
@ -251,11 +263,21 @@ namespace TmpFS
|
|||||||
m_device = device;
|
m_device = device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_device_id(dev_t id, Badge<FileSystem>)
|
||||||
|
{
|
||||||
|
m_device_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
VFS::FileSystem* fs() const override
|
VFS::FileSystem* fs() const override
|
||||||
{
|
{
|
||||||
return m_fs;
|
return m_fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dev_t device_id() const override
|
||||||
|
{
|
||||||
|
return m_device_id;
|
||||||
|
}
|
||||||
|
|
||||||
usize inode_number() const override
|
usize inode_number() const override
|
||||||
{
|
{
|
||||||
return m_inode_number;
|
return m_inode_number;
|
||||||
@ -340,6 +362,7 @@ namespace TmpFS
|
|||||||
u32 m_uid { 0 };
|
u32 m_uid { 0 };
|
||||||
u32 m_gid { 0 };
|
u32 m_gid { 0 };
|
||||||
u32 m_nlinks { 0 };
|
u32 m_nlinks { 0 };
|
||||||
|
dev_t m_device_id { 0 };
|
||||||
};
|
};
|
||||||
|
|
||||||
class DirInode : public VFS::Inode
|
class DirInode : public VFS::Inode
|
||||||
|
@ -33,7 +33,7 @@ Result<u64> sys_read(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size));
|
usize nread = TRY(descriptor.inode->read(buf, descriptor.offset, size));
|
||||||
|
|
||||||
descriptor.offset += nread;
|
if (VFS::is_seekable(descriptor.inode->type())) descriptor.offset += nread;
|
||||||
|
|
||||||
return nread;
|
return nread;
|
||||||
}
|
}
|
||||||
@ -52,11 +52,12 @@ Result<u64> sys_write(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
if (!descriptor.is_writable()) return err(EBADF);
|
if (!descriptor.is_writable()) return err(EBADF);
|
||||||
|
|
||||||
if (descriptor.should_append()) descriptor.offset = descriptor.inode->size();
|
if (descriptor.should_append() && VFS::is_seekable(descriptor.inode->type()))
|
||||||
|
descriptor.offset = descriptor.inode->size();
|
||||||
|
|
||||||
usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size));
|
usize nwritten = TRY(descriptor.inode->write(buf, descriptor.offset, size));
|
||||||
|
|
||||||
descriptor.offset += nwritten;
|
if (VFS::is_seekable(descriptor.inode->type())) descriptor.offset += nwritten;
|
||||||
|
|
||||||
return nwritten;
|
return nwritten;
|
||||||
}
|
}
|
||||||
@ -71,6 +72,10 @@ Result<u64> sys_lseek(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
auto& descriptor = *TRY(current->resolve_fd(fd));
|
auto& descriptor = *TRY(current->resolve_fd(fd));
|
||||||
|
|
||||||
|
if (descriptor.inode->type() == VFS::InodeType::FIFO) return err(ESPIPE);
|
||||||
|
|
||||||
|
if (!VFS::is_seekable(descriptor.inode->type())) return descriptor.offset;
|
||||||
|
|
||||||
off_t new_offset;
|
off_t new_offset;
|
||||||
|
|
||||||
switch (whence)
|
switch (whence)
|
||||||
|
@ -62,3 +62,29 @@ Result<u64> sys_symlinkat(Registers*, SyscallArgs args)
|
|||||||
|
|
||||||
return 0;
|
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;
|
||||||
|
}
|
||||||
|
@ -13,8 +13,10 @@ static mode_t make_mode(mode_t mode, VFS::InodeType type)
|
|||||||
{
|
{
|
||||||
case VFS::InodeType::RegularFile: result |= S_IFREG; break;
|
case VFS::InodeType::RegularFile: result |= S_IFREG; break;
|
||||||
case VFS::InodeType::Directory: result |= S_IFDIR; break;
|
case VFS::InodeType::Directory: result |= S_IFDIR; break;
|
||||||
case VFS::InodeType::Device: result |= S_IFCHR; break;
|
case VFS::InodeType::CharacterDevice: result |= S_IFCHR; break;
|
||||||
|
case VFS::InodeType::BlockDevice: result |= S_IFBLK; break;
|
||||||
case VFS::InodeType::Symlink: result |= S_IFLNK; break;
|
case VFS::InodeType::Symlink: result |= S_IFLNK; break;
|
||||||
|
case VFS::InodeType::FIFO: result |= S_IFIFO; break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,6 +42,8 @@ Result<u64> sys_fstatat(Registers*, SyscallArgs args)
|
|||||||
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();
|
||||||
|
kstat.st_dev = inode->fs() ? inode->fs()->host_device_id() : 0;
|
||||||
|
kstat.st_rdev = inode->device_id();
|
||||||
|
|
||||||
if (!MemoryManager::copy_to_user_typed(st, &kstat)) return err(EFAULT);
|
if (!MemoryManager::copy_to_user_typed(st, &kstat)) return err(EFAULT);
|
||||||
|
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
#ifndef _BITS_FIXED_SIZE_TYPES_H
|
#ifndef _BITS_FIXED_SIZE_TYPES_H
|
||||||
#define _BITS_FIXED_SIZE_TYPES_H
|
#define _BITS_FIXED_SIZE_TYPES_H
|
||||||
|
|
||||||
#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H)
|
#if !defined(_SYS_TYPES_H) && !defined(_BITS_SETJMP_TYPES_H) && !defined(_BITS_MAKEDEV_H)
|
||||||
#error "Never include bits/fixed-size-types.h, use the standard <stdint.h> header instead."
|
#error "Never include bits/fixed-size-types.h, use the standard <stdint.h> header instead."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -6,6 +6,8 @@
|
|||||||
#define S_IFMT 070000
|
#define S_IFMT 070000
|
||||||
#define S_IFREG 000000
|
#define S_IFREG 000000
|
||||||
#define S_IFLNK 010000
|
#define S_IFLNK 010000
|
||||||
|
#define S_IFIFO 020000
|
||||||
|
#define S_IFBLK 030000
|
||||||
#define S_IFDIR 040000
|
#define S_IFDIR 040000
|
||||||
#define S_IFCHR 050000
|
#define S_IFCHR 050000
|
||||||
|
|
||||||
@ -14,7 +16,9 @@
|
|||||||
#define S_ISREG(mode) __CHECK_TYPE(mode, S_IFREG)
|
#define S_ISREG(mode) __CHECK_TYPE(mode, S_IFREG)
|
||||||
#define S_ISDIR(mode) __CHECK_TYPE(mode, S_IFDIR)
|
#define S_ISDIR(mode) __CHECK_TYPE(mode, S_IFDIR)
|
||||||
#define S_ISCHR(mode) __CHECK_TYPE(mode, S_IFCHR)
|
#define S_ISCHR(mode) __CHECK_TYPE(mode, S_IFCHR)
|
||||||
|
#define S_ISBLK(mode) __CHECK_TYPE(mode, S_IFBLK)
|
||||||
#define S_ISLNK(mode) __CHECK_TYPE(mode, S_IFLNK)
|
#define S_ISLNK(mode) __CHECK_TYPE(mode, S_IFLNK)
|
||||||
|
#define S_ISFIFO(mode) __CHECK_TYPE(mode, S_IFIFO)
|
||||||
|
|
||||||
#define S_IRWXU 0700
|
#define S_IRWXU 0700
|
||||||
#define S_IRUSR 0400
|
#define S_IRUSR 0400
|
||||||
|
@ -10,9 +10,11 @@ struct stat
|
|||||||
ino_t st_ino;
|
ino_t st_ino;
|
||||||
mode_t st_mode;
|
mode_t st_mode;
|
||||||
nlink_t st_nlink;
|
nlink_t st_nlink;
|
||||||
|
dev_t st_dev;
|
||||||
uid_t st_uid;
|
uid_t st_uid;
|
||||||
gid_t st_gid;
|
gid_t st_gid;
|
||||||
off_t st_size;
|
off_t st_size;
|
||||||
|
dev_t st_rdev;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -139,6 +139,12 @@ extern "C"
|
|||||||
/* Create a symbolic link relative to a file descriptor. */
|
/* Create a symbolic link relative to a file descriptor. */
|
||||||
int symlinkat(const char* target, int dirfd, const char* linkpath);
|
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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -184,11 +184,14 @@ extern "C"
|
|||||||
{
|
{
|
||||||
if (!cmd)
|
if (!cmd)
|
||||||
{
|
{
|
||||||
// FIXME: Check if there is a shell available in the system.
|
struct stat st;
|
||||||
errno = ENOTSUP;
|
if (stat("/bin/sh", &st) < 0) return 0;
|
||||||
return -1;
|
return S_ISREG(st.st_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: During the execution of system(), SIGCHLD will be blocked, and SIGINT and SIGQUIT will be ignored, in
|
||||||
|
// the process that calls system().
|
||||||
|
|
||||||
pid_t child = fork();
|
pid_t child = fork();
|
||||||
if (child == 0)
|
if (child == 0)
|
||||||
{
|
{
|
||||||
|
@ -418,4 +418,16 @@ extern "C"
|
|||||||
long rc = syscall(SYS_symlinkat, target, dirfd, linkpath);
|
long rc = syscall(SYS_symlinkat, target, dirfd, linkpath);
|
||||||
__errno_return(rc, int);
|
__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(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(umount) _e(pstat) _e(getrusage) _e(symlinkat) _e(readlinkat)
|
||||||
|
|
||||||
enum Syscalls
|
enum Syscalls
|
||||||
{
|
{
|
||||||
|
@ -11,6 +11,7 @@ set(SOURCES
|
|||||||
src/Directory.cpp
|
src/Directory.cpp
|
||||||
src/Main.cpp
|
src/Main.cpp
|
||||||
src/Path.cpp
|
src/Path.cpp
|
||||||
|
src/Mode.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(os ${SOURCES})
|
add_library(os ${SOURCES})
|
||||||
|
@ -21,6 +21,8 @@ namespace os
|
|||||||
|
|
||||||
Result<void> remove_tree(const Path& path);
|
Result<void> remove_tree(const Path& path);
|
||||||
|
|
||||||
|
Result<String> readlink(const Path& path);
|
||||||
|
|
||||||
Result<String> working_directory();
|
Result<String> working_directory();
|
||||||
Result<String> home_directory();
|
Result<String> home_directory();
|
||||||
|
|
||||||
|
8
libos/include/os/Mode.h
Normal file
8
libos/include/os/Mode.h
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
void format_mode(mode_t mode, char out[11]);
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <luna/PathParser.h>
|
||||||
#include <luna/String.h>
|
#include <luna/String.h>
|
||||||
#include <os/Directory.h>
|
#include <os/Directory.h>
|
||||||
#include <os/FileSystem.h>
|
#include <os/FileSystem.h>
|
||||||
@ -68,6 +69,23 @@ namespace os::FileSystem
|
|||||||
return remove(path);
|
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()
|
Result<String> working_directory()
|
||||||
{
|
{
|
||||||
char* ptr = getcwd(NULL, 0);
|
char* ptr = getcwd(NULL, 0);
|
||||||
|
34
libos/src/Mode.cpp
Normal file
34
libos/src/Mode.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include <os/Mode.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
namespace os
|
||||||
|
{
|
||||||
|
static char filetype(mode_t mode)
|
||||||
|
{
|
||||||
|
if (S_ISREG(mode)) return '-';
|
||||||
|
if (S_ISDIR(mode)) return 'd';
|
||||||
|
|
||||||
|
if (S_ISCHR(mode)) return 'c';
|
||||||
|
if (S_ISBLK(mode)) return 'b';
|
||||||
|
if (S_ISLNK(mode)) return 'l';
|
||||||
|
if (S_ISFIFO(mode)) return 'p';
|
||||||
|
|
||||||
|
return '?';
|
||||||
|
}
|
||||||
|
|
||||||
|
void format_mode(mode_t mode, char out[11])
|
||||||
|
{
|
||||||
|
out[0] = filetype(mode);
|
||||||
|
out[1] = (mode & S_IRUSR) ? 'r' : '-';
|
||||||
|
out[2] = (mode & S_IWUSR) ? 'w' : '-';
|
||||||
|
out[3] = (mode & S_ISUID) ? ((mode & S_IXUSR) ? 's' : 'S') : ((mode & S_IXUSR) ? 'x' : '-');
|
||||||
|
out[4] = (mode & S_IRGRP) ? 'r' : '-';
|
||||||
|
out[5] = (mode & S_IWGRP) ? 'w' : '-';
|
||||||
|
out[6] = (mode & S_ISGID) ? ((mode & S_IXGRP) ? 's' : 'S') : ((mode & S_IXGRP) ? 'x' : '-');
|
||||||
|
out[7] = (mode & S_IROTH) ? 'r' : '-';
|
||||||
|
out[8] = (mode & S_IWOTH) ? 'w' : '-';
|
||||||
|
// FIXME: Support the sticky bit.
|
||||||
|
out[9] = (mode & S_IXOTH) ? 'x' : '-';
|
||||||
|
out[10] = '\0';
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user