#if 0 /*─────────────────────────────────────────────────────────────────╗ │ To the extent possible under law, Justine Tunney has waived │ │ all copyright and related or neighboring rights to this file, │ │ as it is written in the following disclaimers: │ │ • http://unlicense.org/ │ │ • http://creativecommons.org/publicdomain/zero/1.0/ │ ╚─────────────────────────────────────────────────────────────────*/ #endif #include "libc/calls/struct/stat.h" #include "libc/assert.h" #include "libc/calls/calls.h" #include "libc/errno.h" #include "libc/fmt/conv.h" #include "libc/log/check.h" #include "libc/log/log.h" #include "libc/mem/gc.h" #include "libc/mem/mem.h" #include "libc/stdio/stdio.h" #include "libc/str/str.h" #include "libc/sysv/consts/s.h" #include "libc/time.h" /** * @fileoverview File metadata viewer. * * This demonstrates the more powerful aspects of the printf() DSL. */ bool numeric; char *xiso8601(struct timespec ts) { struct tm tm; if (!localtime_r(&ts.tv_sec, &tm)) return 0; int len = 128; char *res = malloc(len); char *ptr = res; char *end = res + len; if (!res) return 0; ptr += strftime(ptr, end - ptr, "%Y-%m-%d %H:%M:%S", &tm); ptr += snprintf(ptr, end - ptr, ".%09ld", ts.tv_nsec); ptr += strftime(ptr, end - ptr, "%z %Z", &tm); unassert(ptr + 1 <= end); return res; } const char *DescribeFileType(unsigned mode) { switch (mode & S_IFMT) { case S_IFIFO: return "S_IFIFO"; /* pipe */ case S_IFCHR: return "S_IFCHR"; /* character device */ case S_IFDIR: return "S_IFDIR"; /* directory */ case S_IFBLK: return "S_IFBLK"; /* block device */ case S_IFREG: return "S_IFREG"; /* regular file */ case S_IFLNK: return "S_IFLNK"; /* symbolic link */ case S_IFSOCK: return "S_IFSOCK"; /* socket */ default: return "wut"; } } void PrintFileMetadata(const char *pathname, struct stat *st) { int fd; printf("\n%s:", pathname); if (numeric) { fd = atoi(pathname); CHECK_NE(-1, fstat(fd, st), "fd=%d", fd); } else { CHECK_NE(-1, stat(pathname, st), "pathname=%s", pathname); } printf("\n" "%-32s%,ld\n" "%-32s%,ld\n" "%-32s%#lx\n" "%-32s%#lx\n" "%-32s%ld\n" "%-32s%#o (%s)\n" "%-32s%d\n" "%-32s%d\n" "%-32s%d\n" "%-32s%d\n" "%-32s%ld\n" "%-32s%ld\n" "%-32s%s\n" "%-32s%s\n" "%-32s%s\n" "%-32s%s\n", "bytes in file:", st->st_size, "physical bytes:", st->st_blocks * 512, "device id w/ file:", st->st_dev, "inode:", st->st_ino, "hard link count:", st->st_nlink, "mode / permissions:", st->st_mode, DescribeFileType(st->st_mode), "owner id:", st->st_uid, "group id:", st->st_gid, "flags:", st->st_flags, "gen:", st->st_gen, "device id (if special):", st->st_rdev, "block size:", st->st_blksize, "access time:", gc(xiso8601(st->st_atim)), "modified time:", gc(xiso8601(st->st_mtim)), "c[omplicated]time:", gc(xiso8601(st->st_ctim)), "[birthtime]:", gc(xiso8601(st->st_birthtim))); } int main(int argc, char *argv[]) { size_t i; struct stat st; if (argc <= 1) { PrintFileMetadata(".", &st); return 0; } for (i = 1; i < argc; ++i) { if (!strcmp(argv[i], "-n")) { numeric = true; } else { PrintFileMetadata(argv[i], &st); } } return 0; }