xv6, line by line
user/ls.c

user/ls.c

C · 88 lines · annotated 100% · user program / library · upstream

About this file

ls lists files. ls alone lists the current directory; ls d lists directory d; ls f for an ordinary file prints one line about that file. Each line has four columns: the name (padded to 14 characters), the type (1 directory, 2 file, 3 device), the inode number and the size in bytes. In a freshly booted xv6, ls prints:

.              1 1 1024
..             1 1 1024
README         2 2 2441
cat            2 3 38128
...
console        3 23 0

(Sizes depend on the build.) Notice that . and .. are both inode 1 in the root directory, and that console is a device with size 0.

The program shows two things you cannot see from cat. First, how to ask the kernel about a file without reading it: fstat fills in a struct stat (kernel/stat.h). Second, that in xv6 a directory is an ordinary file whose content is an array of 16-byte struct dirent records (kernel/fs.h); ls reads them with plain read.

Read before: user/cat.c, kernel/stat.h, the dirent definition in kernel/fs.h. Read next: kernel/fs.c (dirlookup reads the same entries inside the kernel).

7char *
8fmtname(char *path)
9{
10 static char buf[DIRSIZ + 1];
11 char *p;
13 // Find first character after last slash.
14 for (p = path + strlen(path); p >= path && *p != '/'; p--)
15 ;
16 p++;
18 // Return blank-padded name.
19 if (strlen(p) >= DIRSIZ)
20 return p;
22 memset(buf + strlen(p), ' ', DIRSIZ - strlen(p));
23 buf[sizeof(buf) - 1] = '\0';
24 return buf;
27void
28ls(char *path)
30 char buf[512], *p;
31 int fd;
32 struct dirent de;
33 struct stat st;
35 if ((fd = open(path, O_RDONLY)) < 0) {
36 fprintf(2, "ls: cannot open %s\n", path);
37 return;
38 }
40 if (fstat(fd, &st) < 0) {
41 fprintf(2, "ls: cannot stat %s\n", path);
43 return;
44 }
46 switch (st.type) {
47 case T_DEVICE:
48 case T_FILE:
49 printf("%s %d %d %d\n", fmtname(path), st.type, st.ino, (int)st.size);
50 break;
52 case T_DIR:
53 if (strlen(path) + 1 + DIRSIZ + 1 > sizeof buf) {
54 printf("ls: path too long\n");
55 break;
56 }
58 p = buf + strlen(buf);
59 *p++ = '/';
60 while (read(fd, &de, sizeof(de)) == sizeof(de)) {
61 if (de.inum == 0)
62 continue;
64 p[DIRSIZ] = 0;
65 if (stat(buf, &st) < 0) {
66 printf("ls: cannot stat %s\n", buf);
67 continue;
68 }
69 printf("%s %d %d %d\n", fmtname(buf), st.type, st.ino, (int)st.size);
70 }
71 break;
72 }
76int
77main(int argc, char *argv[])
79 int i;
81 if (argc < 2) {
82 ls(".");
83 exit(0);
84 }
85 for (i = 1; i < argc; i++)
86 ls(argv[i]);
87 exit(0);