1 | // SPDX-License-Identifier: GPL-3.0-or-later |
2 | |
3 | #include "mosapi.h" |
4 | |
5 | #define BUFSIZE 4096 |
6 | |
7 | static const char *type_to_string[] = { |
8 | [FILE_TYPE_DIRECTORY] = "dir" , [FILE_TYPE_REGULAR] = "file" , [FILE_TYPE_CHAR_DEVICE] = "char" , [FILE_TYPE_BLOCK_DEVICE] = "block" , |
9 | [FILE_TYPE_SYMLINK] = "symlink" , [FILE_TYPE_SOCKET] = "socket" , [FILE_TYPE_NAMED_PIPE] = "pipe" , [FILE_TYPE_UNKNOWN] = "unknown" , |
10 | }; |
11 | |
12 | int main(int argc, char *argv[]) |
13 | { |
14 | if (argc > 2) |
15 | { |
16 | fprintf(stderr, format: "too many arguments\n" ); |
17 | fprintf(stderr, format: "usage: %s [path]\n" , argv[0]); |
18 | return 1; |
19 | } |
20 | |
21 | // argv[1] may contain the path to list |
22 | const char *path = argc > 1 ? argv[1] : "." ; |
23 | |
24 | fd_t dirfd = open(path, flags: OPEN_READ | OPEN_DIR); |
25 | if (dirfd < 0) |
26 | { |
27 | fprintf(stderr, format: "failed to open directory '%s'\n" , path); |
28 | return 1; |
29 | } |
30 | |
31 | printf(format: "Directory listing of '%s':\n\n" , path); |
32 | printf(format: "%-10s %-15s %-5s %-5s %-15s %-10s %-10s\n" , "Inode" , "Permission" , "UID" , "GID" , "Size" , "Type" , "Name" ); |
33 | |
34 | char buffer[BUFSIZE]; |
35 | do |
36 | { |
37 | size_t sz = syscall_vfs_list_dir(fd: dirfd, buffer, BUFSIZE); |
38 | if (sz == 0) |
39 | break; |
40 | |
41 | #define dirent_next(d) ((struct dirent *) ((char *) d + d->d_reclen)) |
42 | for (const struct dirent *dirent = (struct dirent *) buffer; (char *) dirent < buffer + sz; dirent = dirent_next(dirent)) |
43 | { |
44 | file_stat_t statbuf = { 0 }; |
45 | if (!lstatat(fd: dirfd, path: dirent->d_name, buf: &statbuf)) |
46 | { |
47 | fprintf(stderr, format: "failed to stat '%s'\n" , dirent->d_name); |
48 | continue; |
49 | } |
50 | |
51 | char perm[10] = "---------" ; |
52 | file_format_perm(perms: statbuf.perm, buf: perm); |
53 | char namebuf[256] = { 0 }; |
54 | snprintf(str: namebuf, size: sizeof(namebuf), format: "%s%s" , dirent->d_name, dirent->d_type == FILE_TYPE_DIRECTORY ? "/" : "" ); |
55 | |
56 | printf(format: "%-10lu %-15s %-5u %-5u %-15zu %-10s %-10s" , dirent->d_ino, perm, statbuf.uid, statbuf.gid, statbuf.size, type_to_string[dirent->d_type], namebuf); |
57 | |
58 | if (dirent->d_type == FILE_TYPE_SYMLINK) |
59 | { |
60 | char link[BUFSIZE] = { 0 }; |
61 | size_t sz = syscall_vfs_readlinkat(dirfd, path: dirent->d_name, buf: link, BUFSIZE); |
62 | bool can_stat = sz > 0 && lstatat(fd: dirfd, path: link, buf: &statbuf); |
63 | if (can_stat) |
64 | { |
65 | link[sz] = '\0'; |
66 | printf(format: " -> %s" , link); |
67 | } |
68 | else |
69 | { |
70 | printf(format: " -> (broken symlink: '%s')" , link); |
71 | } |
72 | } |
73 | |
74 | puts(s: "" ); |
75 | } |
76 | |
77 | } while (true); |
78 | |
79 | syscall_io_close(fd: dirfd); |
80 | |
81 | return 0; |
82 | } |
83 | |