Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ls -l の実装 #48

Merged
merged 1 commit into from
Aug 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions kernel/fat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)) {
Expand Down
8 changes: 8 additions & 0 deletions kernel/fat.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 指定されたクラスタの次のクラスタ番号を返す。
Expand Down
40 changes: 34 additions & 6 deletions kernel/terminal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ Error FreePML4(Task& current_task) {
return FreePageMap(reinterpret_cast<PageMapEntry*>(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);

Expand All @@ -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", "<DIR>");
} 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);
Expand Down Expand Up @@ -447,22 +457,40 @@ 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);
if (post_slash) {
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", "<DIR>");
} 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);
}
}
Expand Down