aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorzlg <zlg@zlg.space>2022-01-18 21:58:37 -0800
committerzlg <zlg@zlg.space>2022-01-18 21:58:37 -0800
commitb1805ae57e314be9d56c099a282206053043fa4b (patch)
treeeb97213f00e0dda50867009a5c76055481f1ef77
parentSolve Exercise 8-4: fseek() implementation (diff)
downloadknr-b1805ae57e314be9d56c099a282206053043fa4b.tar.gz
knr-b1805ae57e314be9d56c099a282206053043fa4b.tar.bz2
knr-b1805ae57e314be9d56c099a282206053043fa4b.tar.xz
knr-b1805ae57e314be9d56c099a282206053043fa4b.zip
Solve Exercise 8-05: fsize extended
This exercise uses the standard library instead of the homegrown dirent.h outlined in the book. This is due to misbehavior in outputting the file or directory names. This pointed to a data mismatch between the data model supplied by the book and the data model actually used by my operating system (GNU/Linux).
-rw-r--r--ch8/8-05_fsize-extended.c77
1 files changed, 77 insertions, 0 deletions
diff --git a/ch8/8-05_fsize-extended.c b/ch8/8-05_fsize-extended.c
new file mode 100644
index 0000000..c296104
--- /dev/null
+++ b/ch8/8-05_fsize-extended.c
@@ -0,0 +1,77 @@
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+/* The C Programming Language: 2nd Edition
+ *
+ * Exercise 8-5: Modify the fsize program to print the other information
+ * contained in the inode entry.
+ *
+ * Notes: The supplied header file examples don't really work well on a
+ * GNU/Linux system in 2022. :) This makes 8-5 the only exercise in the book
+ * that's broken enough to nearly require the standard library to complete.
+ * Despite lacking the homegrown headers, this exercise is still a good example
+ * of callbacks.
+ *
+ * Not all of the information within the stat struct is displayed by this
+ * program; this is mostly due to the information not being terribly useful
+ * on all systems. Modification time and permission information is relevant
+ * to all platforms.
+ */
+
+void fsize(char *);
+void dirwalk(char *, void (*fcn)(char *));
+
+int main(int argc, char **argv) {
+ if (argc == 1) {
+ fsize(".");
+ } else {
+ while (--argc > 0) {
+ fsize(*++argv);
+ }
+ }
+ return 0;
+}
+
+void fsize(char *name) {
+ struct stat stbuf;
+ if (stat(name, &stbuf) == -1) {
+ fprintf(stderr, "fsize: can't access %s\n", name);
+ return;
+ }
+ if ((stbuf.st_mode & S_IFMT) == S_IFDIR) {
+ dirwalk(name, fsize);
+ }
+ /*
+ * Size, Mode, UID, GID, ModifiedTime, FileName
+ */
+ printf("%8ld %6o %d %d %ld %s\n", stbuf.st_size, stbuf.st_mode, stbuf.st_uid, stbuf.st_gid, stbuf.st_mtime, name);
+}
+
+void dirwalk(char *dir, void (*fcn)(char *)) {
+ char name[PATH_MAX];
+ struct dirent *dp;
+ DIR *dfd;
+ if ((dfd = opendir(dir)) == NULL) {
+ fprintf(stderr, "dirwalk: can't open %s\n", dir);
+ return;
+ }
+ while ((dp = readdir(dfd)) != NULL) {
+ if (strcmp(dp->d_name, ".") == 0 || strcmp(dp->d_name, "..") == 0) {
+ continue;
+ }
+ if (strlen(dir)+strlen(dp->d_name)+2 > sizeof (name)) {
+ fprintf(stderr, "dirwalk: name %s/%s too long\n", dir, dp->d_name);
+ } else {
+ sprintf(name, "%s/%s", dir, dp->d_name);
+ (*fcn)(name);
+ }
+ }
+ closedir(dfd);
+}