diff --git a/apps/ls.cpp b/apps/ls.cpp index 1f62f590..10d3bb11 100644 --- a/apps/ls.cpp +++ b/apps/ls.cpp @@ -1,10 +1,59 @@ -#include +#include #include #include #include #include -#include -#include +#include + +struct UsernameCache +{ + uid_t uid; + String name; +}; + +struct GroupCache +{ + gid_t gid; + String name; +}; + +Vector g_user_cache; +Vector g_group_cache; + +Result 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); + if (!pw) owner = "???"; + else + 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); + if (!grp) group = "???"; + else + 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 luna_main(int argc, char** argv) { @@ -56,13 +105,14 @@ Result luna_main(int argc, char** argv) for (const auto& file : files) { struct stat st; - if (fstatat(dirfd, file.chars(), &st, 0) < 0) - { - perror(file.chars()); - return 1; - } + TRY(os::FileSystem::stat({ dirfd, file.view() }, st)); - os::println("%6o %u %4u %4u %10lu %s", st.st_mode, st.st_nlink, st.st_uid, st.st_gid, st.st_size, + StringView owner; + StringView group; + + TRY(find_user_and_group(st, owner, group)); + + os::println("%6o %u %4s %4s %10lu %s", st.st_mode, st.st_nlink, owner.chars(), group.chars(), st.st_size, file.chars()); } } diff --git a/apps/stat.cpp b/apps/stat.cpp index 6d88e2df..2c225029 100644 --- a/apps/stat.cpp +++ b/apps/stat.cpp @@ -1,4 +1,5 @@ #include +#include #include #include @@ -24,11 +25,7 @@ Result luna_main(int argc, char** argv) parser.parse(argc, argv); struct stat st; - if (stat(path.chars(), &st) < 0) - { - perror("stat"); - return 1; - } + TRY(os::FileSystem::stat(path, st)); printf(" File: %s\n", path.chars()); printf(" Size: %zu (%s)\n", st.st_size, file_type(st.st_mode)); diff --git a/libos/include/os/FileSystem.h b/libos/include/os/FileSystem.h index 4bca16dc..029519e6 100644 --- a/libos/include/os/FileSystem.h +++ b/libos/include/os/FileSystem.h @@ -1,4 +1,5 @@ #pragma once +#include #include #include #include @@ -12,6 +13,8 @@ namespace os bool is_directory(const Path& path); + Result stat(const Path& path, struct stat& st); + Result create_directory(StringView path, mode_t mode); Result remove(const Path& path); diff --git a/libos/src/FileSystem.cpp b/libos/src/FileSystem.cpp index 01793e01..e82716c1 100644 --- a/libos/src/FileSystem.cpp +++ b/libos/src/FileSystem.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -6,7 +7,6 @@ #include #include #include -#include #include #include @@ -16,7 +16,7 @@ namespace os::FileSystem { struct stat st; - if (fstatat(path.dirfd(), path.name().chars(), &st, path.is_empty_path()) < 0) return false; + if (stat(path, st).has_error()) return false; return true; } @@ -25,11 +25,19 @@ namespace os::FileSystem { struct stat st; - if (fstatat(path.dirfd(), path.name().chars(), &st, path.is_empty_path()) < 0) return false; + if (stat(path, st).has_error()) return false; return S_ISDIR(st.st_mode); } + Result stat(const Path& path, struct stat& st) + { + long rc = + syscall(SYS_fstatat, path.dirfd(), path.name().chars(), &st, path.is_empty_path() ? AT_EMPTY_PATH : 0); + + return Result::from_syscall(rc); + } + Result create_directory(StringView path, mode_t mode) { long rc = syscall(SYS_mkdir, path.chars(), mode);