aboutsummaryrefslogtreecommitdiff
path: root/semestr-5/so/lista5/so21_lista_5/listdir.c
diff options
context:
space:
mode:
Diffstat (limited to 'semestr-5/so/lista5/so21_lista_5/listdir.c')
-rw-r--r--semestr-5/so/lista5/so21_lista_5/listdir.c118
1 files changed, 118 insertions, 0 deletions
diff --git a/semestr-5/so/lista5/so21_lista_5/listdir.c b/semestr-5/so/lista5/so21_lista_5/listdir.c
new file mode 100644
index 0000000..9ae906c
--- /dev/null
+++ b/semestr-5/so/lista5/so21_lista_5/listdir.c
@@ -0,0 +1,118 @@
+#include "csapp.h"
+
+#define DIRBUFSZ 256
+
+static void print_mode(mode_t m) {
+ char t;
+
+ if (S_ISDIR(m))
+ t = 'd';
+ else if (S_ISCHR(m))
+ t = 'c';
+ else if (S_ISBLK(m))
+ t = 'b';
+ else if (S_ISREG(m))
+ t = '-';
+ else if (S_ISFIFO(m))
+ t = 'f';
+ else if (S_ISLNK(m))
+ t = 'l';
+ else if (S_ISSOCK(m))
+ t = 's';
+ else
+ t = '?';
+
+ char ur = (m & S_IRUSR) ? 'r' : '-';
+ char uw = (m & S_IWUSR) ? 'w' : '-';
+ char ux = (m & S_IXUSR) ? 'x' : '-';
+ char gr = (m & S_IRGRP) ? 'r' : '-';
+ char gw = (m & S_IWGRP) ? 'w' : '-';
+ char gx = (m & S_IXGRP) ? 'x' : '-';
+ char or = (m & S_IROTH) ? 'r' : '-';
+ char ow = (m & S_IWOTH) ? 'w' : '-';
+ char ox = (m & S_IXOTH) ? 'x' : '-';
+
+ /* TODO: Fix code to report set-uid/set-gid/sticky bit as 'ls' does. */
+ if (m & S_ISUID) ux = 's';
+ if (m & S_ISGID) gx = 's';
+ if (m & S_ISVTX) ox = 't';
+
+ printf("%c%c%c%c%c%c%c%c%c%c", t, ur, uw, ux, gr, gw, gx, or, ow, ox);
+}
+
+static void print_uid(uid_t uid) {
+ struct passwd *pw = getpwuid(uid);
+ if (pw)
+ printf(" %10s", pw->pw_name);
+ else
+ printf(" %10d", uid);
+}
+
+static void print_gid(gid_t gid) {
+ struct group *gr = getgrgid(gid);
+ if (gr)
+ printf(" %10s", gr->gr_name);
+ else
+ printf(" %10d", gid);
+}
+
+static void file_info(int dirfd, const char *name) {
+ struct stat sb[1];
+
+ /* TODO: Read file metadata. */
+ fstatat(dirfd, name, sb, AT_SYMLINK_NOFOLLOW);
+
+ print_mode(sb->st_mode);
+ printf("%4ld", sb->st_nlink);
+ print_uid(sb->st_uid);
+ print_gid(sb->st_gid);
+
+ /* TODO: For devices: print major/minor pair; for other files: size. */
+ if (S_ISCHR(sb->st_mode) || S_ISBLK(sb->st_mode)) {
+ int mi = minor(sb->st_rdev);
+ int ma = major(sb->st_rdev);
+ printf(" %d,\t%d", mi, ma);
+ }
+ else {
+ printf("\t%ld", sb->st_size);
+ }
+
+ char *now = ctime(&sb->st_mtime);
+ now[strlen(now) - 1] = '\0';
+ printf("%26s", now);
+
+ printf(" %s", name);
+
+ if (S_ISLNK(sb->st_mode)) {
+ /* TODO: Read where symlink points to and print '-> destination' string. */
+ char buf[300];
+ size_t len = readlinkat(dirfd, name, buf, sizeof(buf));
+ buf[len] = 0;
+ printf("-> %s", buf);
+ }
+
+ putchar('\n');
+}
+
+int main(int argc, char *argv[]) {
+ if (!argv[1])
+ argv[1] = ".";
+
+ int dirfd = Open(argv[1], O_RDONLY | O_DIRECTORY, 0);
+ char buf[DIRBUFSZ];
+ int n;
+
+ while ((n = Getdents(dirfd, (void *)buf, DIRBUFSZ))) {
+ struct linux_dirent *d;
+ /* TODO: Iterate over directory entries and call file_info on them. */
+ int offset = 0;
+ while (offset < n) {
+ d = (struct linux_dirent *)(buf + offset);
+ offset += d->d_reclen;
+ file_info(dirfd, d->d_name);
+ }
+ }
+
+ Close(dirfd);
+ return EXIT_SUCCESS;
+}