From 18c93de9d43bdd6709f8dcda8accc776dc88bb3d Mon Sep 17 00:00:00 2001 From: MikeCAT Date: Mon, 1 Aug 2022 13:39:33 +0000 Subject: [PATCH] support -l option for ls --- kernel/fat.cpp | 28 ++++++++++++++++++++++++++++ kernel/fat.hpp | 8 ++++++++ kernel/terminal.cpp | 40 ++++++++++++++++++++++++++++++++++------ 3 files changed, 70 insertions(+), 6 deletions(-) diff --git a/kernel/fat.cpp b/kernel/fat.cpp index 1bfd393b2..696bd12c9 100644 --- a/kernel/fat.cpp +++ b/kernel/fat.cpp @@ -66,6 +66,34 @@ void FormatName(const DirectoryEntry& entry, char* dest) { } } +void FormatWriteTime(const DirectoryEntry& entry, char* dest) { + int year = ((entry.write_date >> 9) & 0x3f) + 1980; + int month = (entry.write_date >> 5) & 0xf; + int date = entry.write_date & 0x1f; + int hour = (entry.write_time >> 11) & 0x1f; + int minute = (entry.write_time >> 5) & 0x3f; + int second = (entry.write_time & 0x1f) * 2; + + auto int_to_str = [](char* out, int value, int num_digits) { + for (int i = 0; i < num_digits; i++) { + out[num_digits - 1 - i] = '0' + (value % 10); + value /= 10; + } + }; + int_to_str(&dest[0], year, 4); + dest[4] = '-'; + int_to_str(&dest[5], month, 2); + dest[7] = '-'; + int_to_str(&dest[8], date, 2); + dest[10] = ' '; + int_to_str(&dest[11], hour, 2); + dest[13] = ':'; + int_to_str(&dest[14], minute, 2); + dest[16] = ':'; + int_to_str(&dest[17], second, 2); + dest[19] = '\0'; +} + unsigned long NextCluster(unsigned long cluster) { uint32_t next = GetFAT()[cluster]; if (IsEndOfClusterchain(next)) { diff --git a/kernel/fat.hpp b/kernel/fat.hpp index 9754b0fcc..a331e7799 100644 --- a/kernel/fat.hpp +++ b/kernel/fat.hpp @@ -112,6 +112,14 @@ void ReadName(const DirectoryEntry& entry, char* base, char* ext); */ void FormatName(const DirectoryEntry& entry, char* dest); +/** @brief ディレクトリエントリの更新日時を dest にコピーする。 + * 日時は "YYYY-MM-DD hh:mm:ss" 形式で表現する。 + * + * @param entry 更新日時を得る対象のディレクトリエントリ + * @param dest 更新日時を表現する文字列を格納するに十分な大きさの配列。 + */ +void FormatWriteTime(const DirectoryEntry& entry, char* dest); + static const unsigned long kEndOfClusterchain = 0x0ffffffflu; /** @brief 指定されたクラスタの次のクラスタ番号を返す。 diff --git a/kernel/terminal.cpp b/kernel/terminal.cpp index 5e24e592a..d97d2e79d 100644 --- a/kernel/terminal.cpp +++ b/kernel/terminal.cpp @@ -149,7 +149,7 @@ Error FreePML4(Task& current_task) { return FreePageMap(reinterpret_cast(cr3)); } -void ListAllEntries(FileDescriptor& fd, uint32_t dir_cluster) { +void ListAllEntries(FileDescriptor& fd, uint32_t dir_cluster, bool verbose) { const auto kEntriesPerCluster = fat::bytes_per_cluster / sizeof(fat::DirectoryEntry); @@ -165,6 +165,16 @@ void ListAllEntries(FileDescriptor& fd, uint32_t dir_cluster) { continue; } + if (verbose) { + if ((uint8_t)dir[i].attr & (uint8_t)fat::Attribute::kDirectory) { + PrintToFD(fd, "%10s", ""); + } else { + PrintToFD(fd, "%10lu", (unsigned long)dir[i].file_size); + } + char date[20]; + fat::FormatWriteTime(dir[i], date); + PrintToFD(fd, " %s ", date); + } char name[13]; fat::FormatName(dir[i], name); PrintToFD(fd, "%s\n", name); @@ -447,15 +457,23 @@ void Terminal::ExecuteLine() { dev.class_code.base, dev.class_code.sub, dev.class_code.interface); } } else if (strcmp(command, "ls") == 0) { - if (!first_arg || first_arg[0] == '\0') { - ListAllEntries(*files_[1], fat::boot_volume_image->root_cluster); + char* file_name = first_arg; + bool verbose = false; + if (file_name && file_name[0] == '-') { + for (++file_name; *file_name && !isspace(*file_name); ++file_name) { + if (*file_name == 'l') verbose = true; + } + while (isspace(*file_name)) file_name++; + } + if (!file_name || file_name[0] == '\0') { + ListAllEntries(*files_[1], fat::boot_volume_image->root_cluster, verbose); } else { - auto [ dir, post_slash ] = fat::FindFile(first_arg); + auto [ dir, post_slash ] = fat::FindFile(file_name); if (dir == nullptr) { - PrintToFD(*files_[2], "No such file or directory: %s\n", first_arg); + PrintToFD(*files_[2], "No such file or directory: %s\n", file_name); exit_code = 1; } else if (dir->attr == fat::Attribute::kDirectory) { - ListAllEntries(*files_[1], dir->FirstCluster()); + ListAllEntries(*files_[1], dir->FirstCluster(), verbose); } else { char name[13]; fat::FormatName(*dir, name); @@ -463,6 +481,16 @@ void Terminal::ExecuteLine() { PrintToFD(*files_[2], "%s is not a directory\n", name); exit_code = 1; } else { + if (verbose) { + if ((uint8_t)dir->attr & (uint8_t)fat::Attribute::kDirectory) { + PrintToFD(*files_[1], "%10s", ""); + } else { + PrintToFD(*files_[1], "%10lu", (unsigned long)dir->file_size); + } + char date[20]; + fat::FormatWriteTime(*dir, date); + PrintToFD(*files_[1], " %s ", date); + } PrintToFD(*files_[1], "%s\n", name); } }