From: Tulio A M Mendes Date: Tue, 9 Jun 2026 02:59:34 +0000 (-0300) Subject: fs: fix ext2 readdir visibility and ls single-file output X-Git-Url: https://projects.tadryanom.me/?a=commitdiff_plain;h=db16681b75cb07e939610a45db8f195dc0216cac;p=AdrOS.git fs: fix ext2 readdir visibility and ls single-file output Corrected: - fix ext2 directory iteration so readdir accepts valid exact-fit ext2 dirents instead of rejecting entries where name_len == rec_len - 8 - restore visibility of pre-existing files on ext2 mounts when listing directories with ls/getdents - fix the userland ls command so path arguments are stat'ed first and handled as either directories or standalone files - make 'ls -l /disk/outro.txt' and 'ls -l /disk2/outro.txt' print the expected single-file output instead of treating regular files like directories and producing no output Changed: - refactor ls formatting through a shared print_entry() helper reused by both directory listings and direct file-path listings Validation: - ext2 directory listing regression reproduced from mounted host image and corrected in src/kernel/ext2.c - make test passes after the changes --- diff --git a/src/kernel/ext2.c b/src/kernel/ext2.c index f6dd10b9..448fa4fd 100644 --- a/src/kernel/ext2.c +++ b/src/kernel/ext2.c @@ -961,7 +961,7 @@ static int ext2_readdir_impl(struct fs_node* node, uint32_t* inout_index, void* if (de->rec_len % 4 != 0) goto done; if (off + de->rec_len > bs) goto done; /* F01: Validate name_len */ - if (de->name_len >= de->rec_len - 8) goto done; + if (de->name_len > de->rec_len - 8) goto done; if (de->inode != 0) { /* Skip . and .. */ diff --git a/user/cmds/ls/ls.c b/user/cmds/ls/ls.c index c62716c0..99c8dc65 100644 --- a/user/cmds/ls/ls.c +++ b/user/cmds/ls/ls.c @@ -53,6 +53,64 @@ static void gid_to_name(unsigned gid, char* buf, size_t bufsz) { else { snprintf(buf, bufsz, "%u", gid); } } +static void print_entry(const char* path, const char* display_name, unsigned char type_hint) { + if (lflag) { + struct stat st; + int have_stat = (stat(path, &st) == 0); + + char type = '-'; + if (have_stat) { + unsigned m = (unsigned)st.st_mode; + if (S_ISDIR(m)) type = 'd'; + else if (S_ISCHR(m)) type = 'c'; + else if (S_ISLNK(m)) type = 'l'; + else if (S_ISBLK(m)) type = 'b'; + } else { + if (type_hint == DT_DIR) type = 'd'; + else if (type_hint == DT_CHR) type = 'c'; + else if (type_hint == DT_LNK) type = 'l'; + else if (type_hint == DT_BLK) type = 'b'; + } + + char perms[10]; + if (have_stat) { + unsigned m = (unsigned)st.st_mode; + perms[0] = (m & S_IRUSR) ? 'r' : '-'; + perms[1] = (m & S_IWUSR) ? 'w' : '-'; + perms[2] = (m & S_IXUSR) ? 'x' : '-'; + perms[3] = (m & S_IRGRP) ? 'r' : '-'; + perms[4] = (m & S_IWGRP) ? 'w' : '-'; + perms[5] = (m & S_IXGRP) ? 'x' : '-'; + perms[6] = (m & S_IROTH) ? 'r' : '-'; + perms[7] = (m & S_IWOTH) ? 'w' : '-'; + perms[8] = (m & S_IXOTH) ? 'x' : '-'; + perms[9] = '\0'; + } else { + strcpy(perms, "---------"); + } + + unsigned long sz = have_stat ? (unsigned long)st.st_size : 0; + unsigned nlink = have_stat ? (unsigned)st.st_nlink : 1; + + char owner[32], group[32]; + uid_to_name(have_stat ? (unsigned)st.st_uid : 0, owner, sizeof(owner)); + gid_to_name(have_stat ? (unsigned)st.st_gid : 0, group, sizeof(group)); + + char timebuf[32]; + if (have_stat) { + time_t mtime = (time_t)st.st_mtime; + strftime(timebuf, sizeof(timebuf), "%b %d %H:%M", localtime(&mtime)); + } else { + strcpy(timebuf, "?"); + } + + printf("%c%s %2u %-8s %-8s %8lu %s %s\n", + type, perms, nlink, owner, group, sz, timebuf, display_name); + } else { + printf("%s\n", display_name); + } +} + static void ls_dir(const char* path) { int fd = open(path, O_RDONLY); if (fd < 0) { @@ -88,61 +146,27 @@ static void ls_dir(const char* path) { qsort(entries, count, sizeof(struct ls_entry), cmp_entry); for (int i = 0; i < count; i++) { - if (lflag) { - char fullpath[512]; - size_t plen = strlen(path); - if (plen > 0 && path[plen - 1] == '/') - snprintf(fullpath, sizeof(fullpath), "%s%s", path, entries[i].name); - else - snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entries[i].name); - - struct stat st; - int have_stat = (stat(fullpath, &st) == 0); - - char type = '-'; - if (entries[i].type == DT_DIR) type = 'd'; - else if (entries[i].type == DT_CHR) type = 'c'; - else if (entries[i].type == DT_LNK) type = 'l'; - else if (entries[i].type == DT_BLK) type = 'b'; - - char perms[10]; - if (have_stat) { - unsigned m = (unsigned)st.st_mode; - perms[0] = (m & S_IRUSR) ? 'r' : '-'; - perms[1] = (m & S_IWUSR) ? 'w' : '-'; - perms[2] = (m & S_IXUSR) ? 'x' : '-'; - perms[3] = (m & S_IRGRP) ? 'r' : '-'; - perms[4] = (m & S_IWGRP) ? 'w' : '-'; - perms[5] = (m & S_IXGRP) ? 'x' : '-'; - perms[6] = (m & S_IROTH) ? 'r' : '-'; - perms[7] = (m & S_IWOTH) ? 'w' : '-'; - perms[8] = (m & S_IXOTH) ? 'x' : '-'; - perms[9] = '\0'; - } else { - strcpy(perms, "---------"); - } - - unsigned long sz = have_stat ? (unsigned long)st.st_size : 0; - unsigned nlink = have_stat ? (unsigned)st.st_nlink : 1; - - char owner[32], group[32]; - uid_to_name(have_stat ? (unsigned)st.st_uid : 0, owner, sizeof(owner)); - gid_to_name(have_stat ? (unsigned)st.st_gid : 0, group, sizeof(group)); - - char timebuf[32]; - if (have_stat) { - time_t mtime = (time_t)st.st_mtime; - strftime(timebuf, sizeof(timebuf), "%b %d %H:%M", localtime(&mtime)); - } else { - strcpy(timebuf, "?"); - } + char fullpath[512]; + size_t plen = strlen(path); + if (plen > 0 && path[plen - 1] == '/') + snprintf(fullpath, sizeof(fullpath), "%s%s", path, entries[i].name); + else + snprintf(fullpath, sizeof(fullpath), "%s/%s", path, entries[i].name); + print_entry(fullpath, entries[i].name, entries[i].type); + } +} - printf("%c%s %2u %-8s %-8s %8lu %s %s\n", - type, perms, nlink, owner, group, sz, timebuf, entries[i].name); - } else { - printf("%s\n", entries[i].name); - } +static void ls_path(const char* path) { + struct stat st; + if (stat(path, &st) < 0) { + fprintf(stderr, "ls: cannot access '%s': No such file or directory\n", path); + return; + } + if (S_ISDIR(st.st_mode)) { + ls_dir(path); + return; } + print_entry(path, path, 0); } int main(int argc, char** argv) { @@ -168,11 +192,11 @@ int main(int argc, char** argv) { } if (npath == 0) { - ls_dir("."); + ls_path("."); } else { for (int i = 0; i < npath; i++) { if (npath > 1) printf("%s:\n", paths[i]); - ls_dir(paths[i]); + ls_path(paths[i]); if (npath > 1 && i < npath - 1) printf("\n"); } }