about summary refs log tree commit diff stats
path: root/dirent/examples/du.c
diff options
context:
space:
mode:
Diffstat (limited to 'dirent/examples/du.c')
-rw-r--r--dirent/examples/du.c199
1 files changed, 199 insertions, 0 deletions
diff --git a/dirent/examples/du.c b/dirent/examples/du.c
new file mode 100644
index 0000000..a5832c4
--- /dev/null
+++ b/dirent/examples/du.c
@@ -0,0 +1,199 @@
+/*
+ * Compute disk usage of files and sub-directories in bytes.
+ *
+ * Compile this file with Visual Studio and run the produced command in
+ * console with a directory name argument.  For example, command
+ *
+ *     du "c:\Program Files"
+ *
+ * might produce listing such as
+ *
+ *     5204927     7-Zip
+ *     140046882   CCleaner
+ *     83140342    CMake
+ *     2685264     Internet Explorer
+ *     686314712   LibreOffice
+ *     214025459   Mozilla Firefox
+ *     174753900   VideoLAN
+ *
+ * If you compare this program to a genuine du command in Linux, then be ware
+ * directories themselves consume some space in Linux.  This program, however,
+ * only counts the files and hence the size will always be smaller than that
+ * reported by Linux du.
+ *
+ * Copyright (C) 1998-2019 Toni Ronkko
+ * This file is part of dirent.  Dirent may be freely distributed
+ * under the MIT license.  For all details and documentation, see
+ * https://github.com/tronkko/dirent
+ */
+#define _CRT_SECURE_NO_WARNINGS
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <locale.h>
+
+static long long list_directory(const char *dirname, int level);
+static int _main(int argc, char *argv[]);
+
+static int
+_main(int argc, char *argv[])
+{
+	/* For each directory in command line */
+	int i = 1;
+	while (i < argc) {
+		list_directory(argv[i], 0);
+		i++;
+	}
+
+	/* List current working directory if no arguments on command line */
+	if (argc == 1)
+		list_directory(".", 0);
+
+	return EXIT_SUCCESS;
+}
+
+/* Find files and subdirectories recursively; list their sizes */
+static long long
+list_directory(const char *dirname, int level)
+{
+	char buffer[PATH_MAX + 2];
+	char *p = buffer;
+	char *end = &buffer[PATH_MAX];
+	
+	/* Copy directory name to buffer */
+	const char *src = dirname;
+	while (p < end && *src != '\0') {
+		*p++ = *src++;
+	}
+	*p = '\0';
+
+	/* Get final character of directory name */
+	char c;
+	if (buffer < p)
+		c = p[-1];
+	else
+		c = ':';
+
+	/* Append directory separator if not already there */
+	if (c != ':' && c != '/' && c != '\\')
+		*p++ = '/';
+
+	/* Open directory stream */
+	DIR *dir = opendir(dirname);
+	if (!dir) {
+		fprintf(stderr,
+			"Cannot open %s (%s)\n", dirname, strerror(errno));
+		return 0LL;
+	}
+
+	/* Compute total disk usage of all files and directories */
+	struct stat stbuf;
+	struct dirent *ent;
+	long long total = 0;
+	while ((ent = readdir(dir)) != NULL) {
+		/* Skip pseudo directories . and .. */
+		if (strcmp(ent->d_name, ".") == 0
+			|| strcmp(ent->d_name, "..") == 0)
+			continue;
+
+		/* Skip links as they consume no space */
+		if (ent->d_type == DT_LNK)
+			continue;
+
+		/* Skip device entries */
+		if (ent->d_type != DT_REG && ent->d_type != DT_DIR)
+			continue;
+
+		/* Append file name to buffer */
+		src = ent->d_name;
+		char *q = p;
+		while (q < end && *src != '\0') {
+			*q++ = *src++;
+		}
+		*q = '\0';
+
+		/* Add file size */
+		long long size = 0;
+		if (ent->d_type == DT_REG) {
+			if (stat(buffer, &stbuf) == /*Error*/-1) {
+				fprintf(stderr, "Cannot access %s\n", buffer);
+				continue;
+			}
+			size += (long long) stbuf.st_size;
+		}
+
+		/* Compute size of subdirectories recursively */
+		if (ent->d_type == DT_DIR)
+			size += list_directory(buffer, level + 1);
+
+		/* Update total size of directory */
+		total += size;
+
+		/* Output file/directory size in bytes */
+		if (level == 0)
+			printf("%-10lld  %s\n", size, ent->d_name);
+	}
+
+	closedir(dir);
+
+	/* Return total size of directory */
+	return total;
+}
+
+/* Stub for converting arguments to UTF-8 on Windows */
+#ifdef _MSC_VER
+int
+wmain(int argc, wchar_t *argv[])
+{
+	/* Select UTF-8 locale */
+	setlocale(LC_ALL, ".utf8");
+	SetConsoleCP(CP_UTF8);
+	SetConsoleOutputCP(CP_UTF8);
+
+	/* Allocate memory for multi-byte argv table */
+	char **mbargv;
+	mbargv = (char**) malloc(argc * sizeof(char*));
+	if (!mbargv) {
+		puts("Out of memory");
+		exit(3);
+	}
+
+	/* Convert each argument in argv to UTF-8 */
+	for (int i = 0; i < argc; i++) {
+		size_t n;
+		wcstombs_s(&n, NULL, 0, argv[i], 0);
+
+		/* Allocate room for ith argument */
+		mbargv[i] = (char*) malloc(n + 1);
+		if (!mbargv[i]) {
+			puts("Out of memory");
+			exit(3);
+		}
+
+		/* Convert ith argument to utf-8 */
+		wcstombs_s(NULL, mbargv[i], n + 1, argv[i], n);
+	}
+
+	/* Pass UTF-8 converted arguments to the main program */
+	int errorcode = _main(argc, mbargv);
+
+	/* Release UTF-8 arguments */
+	for (int i = 0; i < argc; i++) {
+		free(mbargv[i]);
+	}
+
+	/* Release the argument table */
+	free(mbargv);
+	return errorcode;
+}
+#else
+int
+main(int argc, char *argv[])
+{
+	return _main(argc, argv);
+}
+#endif
+