Newer
Older
ggf / ggf.d
@dd dd on 15 Jul 2018 8 KB README and fixes/tweaks (+)
import core.sys.windows.windows;
import core.stdc.stdio : printf, puts;

extern (C) int putchar(int c);

enum
	PROJECT_VER  = "0.2.1",
	PCNULL = cast(char*)0,	/// Character Pointer NULL constant
	PINULL = cast(uint*)0;	/// Integer Pointer NULL constant

extern (C)
void help() {
    puts(
`Get disk(s) information.
  Usage: ggf [OPTIONS] [DRIVE]
         ggf {-h|-v|-?}

By default, view disk usage by size.

OPTIONS
-P	View usage by progress-bar style.
-F	View features.
-M	View misc. features (serial and maximum size of path)
-b	Use base10 size formatting
-n	Remove header`
	);
}

extern (C)
void version_() {
	printf(
`ggf v` ~ PROJECT_VER~ `  (` ~ __TIMESTAMP__ ~ `)
MIT License: Copyright (c) 2017-2018 dd86k
Project page: <https://github.com/dd86k/ggf>
Compiled `~__FILE__~` with `~__VENDOR__~" v%d\n",
		__VERSION__);
}

__gshared byte base10; /// Use base10 notation

enum : ubyte {
	FEATURE_DEFAULT, // sizes/usage
	FEATURE_POURCENTAGE, // usage%
	FEATURE_FEATURES, // features
	FEATURE_MISC, // serial+max path
}

enum
	FILE_SUPPORTS_HARD_LINKS = 0x00400000,
	FILE_SUPPORTS_EXTENDED_ATTRIBUTES = 0x00800000,
	FILE_SUPPORTS_OPEN_BY_FILE_ID = 0x01000000,
	FILE_SUPPORTS_USN_JOURNAL = 0x02000000,
	FILE_DAX_VOLUME = 0x20000000;

enum
	POURCENTAGE_INNER_WIDTH = 60;

extern (C)
private int main(int argc, char** argv) {
	ubyte feature; // FEATURE_DEFAULT
	ubyte header = 1;
	int drive;

	while (--argc >= 1) {
		char c = argv[argc][0];
		if (c == '-') {
			char* a = argv[argc];
			while (*++a != '\0') {
				switch (*a) {
				case 'h', '?': help; return 0;
				case 'v': version_; return 0;
				case 'b': ++base10; break;
				case 'n': header = 0; break;
				case 'F': feature = FEATURE_FEATURES; break;
				case 'P': feature = FEATURE_POURCENTAGE; break;
				case 'M': feature = FEATURE_MISC; break;
				default:
					printf("ERROR: Unknown parameter: %c\n", *a);
					return 1;
				}
			}
		} else if (c >= 'a' && c <= 'z') {
			drive = c - 32;
		} else if (c >= 'A' && c <= 'Z') {
			drive = c;
		}
	}

	// Empty optical drives in XP shows a windows when an error occurs
	SetErrorMode(SEM_FAILCRITICALERRORS);
	DWORD drives = void;
	uint d = void;

	if (drive) {
		d = drives = getMask(drive);
	} else {
		d = 1;
		drives = GetLogicalDrives;
		if (drives == 0) {
			puts("ERROR: No drives found.");
			return 2;
		}
	}

	if (header)
		switch (feature) {
		case FEATURE_MISC:
			puts("DRIVE  SERIAL     MAX PATH");
			break;
		case FEATURE_FEATURES:
			puts("DRIVE  FEATURES");
			break;
		case FEATURE_POURCENTAGE:
			puts("DRIVE  USAGE");
			break;
		default:
			puts("DRIVE  TYPE           USED      FREE     TOTAL  TYPE    NAME");
		}

	char[3] cdp = ` :\`; /// buffer
	for (; d <= drives; d <<= 1) {
		const uint n = drives & d;

		if (n == 0) continue;

		const char cd = getDrive(n);
		cdp[0] = cd;
		printf("%c:     ", cd);

		switch (feature) {
		case FEATURE_MISC:
			ushort[2] serial = void;
			DWORD maxcomp = void;
			if (GetVolumeInformationA(cast(char*)cdp, PCNULL, 0,
				cast(uint*)&serial, &maxcomp, PINULL, PCNULL, 0)) {
				printf("%04X-%04X  %8d  \n", serial[1], serial[0], maxcomp);
			} else putchar('\n');
			continue;
		case FEATURE_FEATURES:
			DWORD flags = void;
			if (GetVolumeInformationA(cast(char*)cdp, PCNULL, PINULL,
				PINULL, PINULL, &flags, PCNULL, 0) == 0) goto FEATURES_END;
			if (flags & FILE_CASE_SENSITIVE_SEARCH)
				printf("+CASE_SENSITIVE_SEARCH\t");
			if (flags & FILE_CASE_PRESERVED_NAMES)
				printf("+CASE_PRESERVED_NAMES\t");
			if (flags & FILE_PERSISTENT_ACLS)
				printf("+PERSISTENT_ACLS\t");
			if (flags & FILE_READ_ONLY_VOLUME)
				printf("+READ_ONLY\t");
			if (flags & FILE_NAMED_STREAMS)
				printf("+NAMED_STREAMS\t");
			if (flags & FILE_SEQUENTIAL_WRITE_ONCE)
				printf("+SEQ_WRITE_ONCE\t");
			if (flags & FILE_SUPPORTS_EXTENDED_ATTRIBUTES)
				printf("+EXTENDED_ATTRIBUTES\t");
			if (flags & FILE_SUPPORTS_ENCRYPTION)
				printf("+ENCRYPTION\t");
			if (flags & FILE_SUPPORTS_HARD_LINKS)
				printf("+HARD_LINKS\t");
			if (flags & FILE_SUPPORTS_OBJECT_IDS)
				printf("+OBJECT_ID\t");
			if (flags & FILE_SUPPORTS_OPEN_BY_FILE_ID)
				printf("+OPEN_BY_FILE_ID\t");
			if (flags & FILE_SUPPORTS_REPARSE_POINTS)
				printf("+REPARSE_POINTS\t");
			if (flags & FILE_SUPPORTS_SPARSE_FILES)
				printf("+SPARSE_FILES\t");
			if (flags & FILE_SUPPORTS_TRANSACTIONS)
				printf("+TRANSACTIONS\t");
			if (flags & FILE_SUPPORTS_USN_JOURNAL)
				printf("+USN_JOURNAL\t");
			if (flags & FILE_UNICODE_ON_DISK)
				printf("+UNICODE\t");
			if (flags & FILE_FILE_COMPRESSION) {
				if (flags & FILE_VOLUME_IS_COMPRESSED)
					printf("+COMPRESSED\t");
				else
					printf("+COMPRESSION\t");
			}
			if (flags & FILE_VOLUME_QUOTAS)
				printf("+QUOTAS\t");
			if (flags & FILE_DAX_VOLUME) // Added in Windows 10
				printf("+DAX\t");
FEATURES_END:
			putchar('\n');
			continue;
		case FEATURE_POURCENTAGE:
			ubyte p_fb = void, p_tb = void;
			ULARGE_INTEGER fb = void, total = void, free = void;
			if (GetDiskFreeSpaceExA(cast(char*)cdp, &fb, &total, &free)) {
				ulong used = total.QuadPart - free.QuadPart;
				p_tb = cast(ubyte) // used
					((used * POURCENTAGE_INNER_WIDTH) / total.QuadPart);
				p_fb = cast(ubyte) // free
					(((free.QuadPart * POURCENTAGE_INNER_WIDTH) / total.QuadPart) + 1);
				putchar('[');
				while (--p_tb) { putchar('='); }
				while (--p_fb) { putchar(' '); }
				printf("] %.1f%%\n", ((cast(float)used * 100) / total.QuadPart));
			} else putchar('\n');
			continue;
		default:
			switch (GetDriveTypeA(cast(char*)cdp)) { // Lazy alert
			default:	puts("UNKNOWN  "); continue; // 0+1
			case 2:	printf("Removable"); break;
			case 3:	printf("Fixed    "); break;
			case 4:	printf("Network  "); break;
			case 5:	printf("Optical  "); break;
			case 6:	printf("RAM      "); break;
			}

			ULARGE_INTEGER dfb = void, dtotal = void, dfree = void;
			if (GetDiskFreeSpaceExA(cast(char*)cdp, &dfb, &dtotal, &dfree)) {
				_printfd(dtotal.QuadPart - dfree.QuadPart);
				_printfd(dfree.QuadPart);
				_printfd(dtotal.QuadPart);
			}

			ubyte[128] vol, fs; // inits to 0, char inits to 0xFF
			if (GetVolumeInformationA(
				cast(char*)cdp, cast(char*)vol, vol.sizeof,
				NULL, NULL, NULL, cast(char*)fs, fs.sizeof)) {
				printf("  %-7s %s\n", cast(char*)fs, cast(char*)vol);
			} else putchar('\n');
			continue;
		} // switch feature
	} // for

	return 0;
}

enum : float { // for _printfd function
	KB = 1024,
	MB = KB * 1024,
	GB = MB * 1024,
	TB = GB * 1024,
	KiB = 1000,
	MiB = KiB * 1000,
	GiB = MiB * 1000,
	TiB = GiB * 1000,
}

// lazy formatter with spacing
extern (C)
private void _printfd(ulong l) {
	const float f = l;
	if (base10) {
		if (l >= TiB) {
			printf("%8.2fTi", f / TiB);
		} else if (l >= GiB) {
			printf("%8.2fGi", f / GiB);
		} else if (l >= MiB) {
			printf("%8.2fMi", f / MiB);
		} else if (l >= KiB) {
			printf("%8.2fKi", f / KiB);
		} else
			printf("%9llB", l);
	} else {
		if (l >= TB) {
			printf("%9.2fT", f / TB);
		} else if (l >= GB) {
			printf("%9.2fG", f / GB);
		} else if (l >= MB) {
			printf("%9.2fM", f / MB);
		} else if (l >= KB) {
			printf("%9.2fK", f / KB);
		} else
			printf("%9llB", l);
	}
}

/**
 * Cheapest way to get a drive letter by computed mask
 * Params: mask = Drive mask (Windows)
 * Returns: Windows drive letter
 */
extern (C)
char getDrive(uint mask) pure { // This entire thing is lazy
	switch (mask) {
	case 1: return 'A';
	case 2: return 'B';
	case 4: return 'C';
	case 8: return 'D';
	case 16: return 'E';
	case 32: return 'F';
	case 64: return 'G';
	case 128: return 'H';
	case 256: return 'I';
	case 512: return 'J';
	case 1024: return 'K';
	case 2048: return 'L';
	case 4096: return 'M';
	case 8192: return 'N';
	case 16384: return 'O';
	case 32768: return 'P';
	case 65536: return 'Q';
	case 131072: return 'R';
	case 262144: return 'S';
	case 524288: return 'T';
	case 1048576: return 'U';
	case 2097152: return 'V';
	case 4194304: return 'W';
	case 8388608: return 'X';
	case 16777216: return 'Y';
	case 33554432: return 'Z';
	default: return '?';
	}
}

extern (C)
int getMask(int drive) pure { // This entire thing is lazy
	switch (drive) {
	case 'A': return 1;
	case 'B': return 2;
	case 'C': return 4;
	case 'D': return 8;
	case 'E': return 16;
	case 'F': return 32;
	case 'G': return 64;
	case 'H': return 128;
	case 'I': return 256;
	case 'J': return 512;
	case 'K': return 1024;
	case 'L': return 2048;
	case 'M': return 4096;
	case 'N': return 8192;
	case 'O': return 16384;
	case 'P': return 32768;
	case 'Q': return 65536;
	case 'R': return 131072;
	case 'S': return 262144;
	case 'T': return 524288;
	case 'U': return 1048576;
	case 'V': return 2097152;
	case 'W': return 4194304;
	case 'X': return 8388608;
	case 'Y': return 16777216;
	case 'Z': return 33554432;
	default: return 0;
	}
}