diff --git a/BAN/BAN/Time.cpp b/BAN/BAN/Time.cpp new file mode 100644 index 000000000..8090cd343 --- /dev/null +++ b/BAN/BAN/Time.cpp @@ -0,0 +1,71 @@ +#include + +namespace BAN +{ + + static constexpr bool is_leap_year(uint64_t year) + { + if (year % 400 == 0) + return true; + if (year % 100 == 0) + return false; + if (year % 4 == 0) + return true; + return false; + } + + static constexpr uint64_t leap_days_since_epoch(const BAN::Time& time) + { + uint64_t leap_years = 0; + for (uint32_t year = 1970; year < time.year; year++) + if (is_leap_year(year)) + leap_years++; + if (is_leap_year(time.year) && time.month >= 3) + leap_years++; + return leap_years; + } + + static constexpr uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; + + uint64_t to_unix_time(const BAN::Time& time) + { + uint64_t years = time.year - 1970; + uint64_t days = years * 365 + month_days[time.month - 1] + leap_days_since_epoch(time) + (time.day - 1); + uint64_t hours = days * 24 + time.hour; + uint64_t minutes = hours * 60 + time.minute; + uint64_t seconds = minutes * 60 + time.second; + return seconds; + } + + BAN::Time from_unix_time(uint64_t unix_time) + { + BAN::Time time {}; + + time.second = unix_time % 60; unix_time /= 60; + time.minute = unix_time % 60; unix_time /= 60; + time.hour = unix_time % 24; unix_time /= 24; + + uint64_t total_days = unix_time; + + time.week_day = (total_days + 4) % 7 + 1; + + time.year = 1970; + while (total_days >= 365U + is_leap_year(time.year)) + { + total_days -= 365U + is_leap_year(time.year); + time.year++; + } + + bool is_leap_day = is_leap_year(time.year) && total_days == month_days[2]; + bool had_leap_day = is_leap_year(time.year) && total_days > month_days[2]; + + for (time.month = 1; time.month < 12; time.month++) + if (total_days < month_days[time.month] + (is_leap_day || had_leap_day)) + break; + + time.day = total_days - month_days[time.month - 1] + !had_leap_day; + + return time; + } + +} \ No newline at end of file diff --git a/BAN/Makefile b/BAN/Makefile index dd4be40a6..4deb4938b 100644 --- a/BAN/Makefile +++ b/BAN/Makefile @@ -34,6 +34,7 @@ $(ARCH_FREEOBJS) \ BAN/Memory.o \ BAN/String.o \ BAN/StringView.o \ +BAN/Time.o \ HOSTEDOBJS=\ $(ARCH_HOSTEDOBJS) \ diff --git a/BAN/include/BAN/Time.h b/BAN/include/BAN/Time.h index 6f2ed7b2d..7b7561035 100644 --- a/BAN/include/BAN/Time.h +++ b/BAN/include/BAN/Time.h @@ -9,15 +9,18 @@ namespace BAN struct Time { - uint8_t second; - uint8_t minute; - uint8_t hour; - uint8_t week_day; - uint8_t day; + uint32_t year; uint8_t month; - int year; + uint8_t day; + uint8_t hour; + uint8_t minute; + uint8_t second; + uint8_t week_day; }; + uint64_t to_unix_time(const BAN::Time&); + BAN::Time from_unix_time(uint64_t); + } namespace BAN::Formatter diff --git a/kernel/include/kernel/RTC.h b/kernel/include/kernel/RTC.h index ffedbd376..af5f6b112 100644 --- a/kernel/include/kernel/RTC.h +++ b/kernel/include/kernel/RTC.h @@ -6,6 +6,5 @@ namespace RTC { BAN::Time get_current_time(); - uint64_t get_unix_time(); } \ No newline at end of file diff --git a/kernel/kernel/FS/Ext2.cpp b/kernel/kernel/FS/Ext2.cpp index 6e9f2de94..8dc5b6a4a 100644 --- a/kernel/kernel/FS/Ext2.cpp +++ b/kernel/kernel/FS/Ext2.cpp @@ -334,7 +334,7 @@ namespace Kernel if (error_or.error().get_error_code() != ENOENT) return error_or.error(); - uint64_t current_time = RTC::get_unix_time(); + uint64_t current_time = BAN::to_unix_time(RTC::get_current_time()); Ext2::Inode ext2_inode; ext2_inode.mode = mode; diff --git a/kernel/kernel/RTC.cpp b/kernel/kernel/RTC.cpp index ddabafb5d..5da86c983 100644 --- a/kernel/kernel/RTC.cpp +++ b/kernel/kernel/RTC.cpp @@ -87,41 +87,4 @@ namespace RTC return time; } - static bool is_leap_year(uint64_t year) - { - if (year % 400 == 0) - return true; - if (year % 100 == 0) - return false; - if (year % 4 == 0) - return true; - return false; - } - - static uint64_t leap_days_since_epoch(const BAN::Time& time) - { - uint64_t leap_years = 0; - for (int year = 1970; year < time.year; year++) - if (is_leap_year(year)) - leap_years++; - if (is_leap_year(time.year)) - if (time.month >= 3 || (time.month == 2 && time.day == 29)) - leap_years++; - return leap_years; - } - - uint64_t get_unix_time() - { - auto time = get_current_time(); - - uint64_t month_days[] { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 }; - - uint64_t years = time.year - 1970; - uint64_t days = years * 365 + month_days[time.month - 1] + time.day + leap_days_since_epoch(time) - 1; - uint64_t hours = days * 24 + time.hour; - uint64_t minutes = hours * 60 + time.minute; - uint64_t seconds = minutes * 60 + time.second; - return seconds; - } - } \ No newline at end of file diff --git a/kernel/kernel/Shell.cpp b/kernel/kernel/Shell.cpp index 9b707adbc..9b9a6e263 100644 --- a/kernel/kernel/Shell.cpp +++ b/kernel/kernel/Shell.cpp @@ -425,6 +425,43 @@ argument_done: } TTY_PRINTLN(""); } + else if (arguments.front() == "stat") + { + if (arguments.size() != 2) + return BAN::Error::from_c_string("usage: 'stat path'"); + + stat st; + TRY(Process::current()->stat(arguments[1], &st)); + + auto mode_string = [](mode_t mode) + { + static char buffer[11] {}; + buffer[0] = (mode & Inode::Mode::IFDIR) ? 'd' : '-'; + buffer[1] = (mode & Inode::Mode::IRUSR) ? 'r' : '-'; + buffer[2] = (mode & Inode::Mode::IWUSR) ? 'w' : '-'; + buffer[3] = (mode & Inode::Mode::IXUSR) ? 'x' : '-'; + buffer[4] = (mode & Inode::Mode::IRGRP) ? 'r' : '-'; + buffer[5] = (mode & Inode::Mode::IWGRP) ? 'w' : '-'; + buffer[6] = (mode & Inode::Mode::IXGRP) ? 'x' : '-'; + buffer[7] = (mode & Inode::Mode::IROTH) ? 'r' : '-'; + buffer[8] = (mode & Inode::Mode::IWOTH) ? 'w' : '-'; + buffer[9] = (mode & Inode::Mode::IXOTH) ? 'x' : '-'; + return (const char*)buffer; + }; + + const char* type = + (st.st_mode & Inode::Mode::IFREG) ? "regular file" : + (st.st_mode & Inode::Mode::IFDIR) ? "directory" : + "other"; + + TTY_PRINTLN(" File: {}", arguments[1]); + TTY_PRINTLN(" Size: {}\tBlocks: {}\tIO Block: {}\t {}", st.st_size, st.st_blocks, st.st_blksize, type); + TTY_PRINTLN("Device: {},{}\tInode: {}\tLinks: {}", st.st_dev, st.st_rdev, st.st_ino, st.st_nlink); + TTY_PRINTLN("Access: ({}/{})\tUid: {}\tGid: {}", st.st_mode, mode_string(st.st_mode), st.st_uid, st.st_gid); + TTY_PRINTLN("Access: {}", BAN::from_unix_time(st.st_atime)); + TTY_PRINTLN("Modify: {}", BAN::from_unix_time(st.st_mtime)); + TTY_PRINTLN("Change: {}", BAN::from_unix_time(st.st_ctime)); + } else if (arguments.front() == "cd") { if (arguments.size() > 2)