Newer
Older
ggf / ggf.d
@dd dd on 24 Jan 2018 6 KB optimizations
import core.sys.windows.windows;
import core.stdc.stdio;

/*
 * MSDN
 * GetVolumeInformation
 * https://msdn.microsoft.com/en-us/library/windows/desktop/aa364993(v=vs.85).aspx
 */

/* SWITCHES
	-b : Use base 10 sizes
	-f : Features page (flags)
	-s : Serial, max component length
*/

enum
	PROJECT_VER  = "0.0.2",
	PCNULL = cast(char*)0;	/// Character Pointer NULL constant

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

extern (C)
void version_() {
	printf(
		cast(char*) // Mostly constant string, only push __VERSION__
(`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 bool base10; /// Use base10 notation

extern (C)
private int main(int argc, char** argv) {
	__gshared bool features;

	while (--argc >= 1) {
		if (argv[argc][0] == '-') {
			char* a = argv[argc];
			while (*++a != '\0') {
				switch (*a) {
				case 'h': help; return 0;
				case 'v': version_; return 0;
				case 'f': features = 1; break;
				case 'b': base10 = 1; break;
				default:
					printf("ERROR: Unknown parameter: %c\n", *a);
					return 1;
				}
			}
		}
	}

	// FDDs/CDs in XP shows a windows when an error occurs
	SetErrorMode(SEM_FAILCRITICALERRORS);
	const DWORD drives = GetLogicalDrives;

	if (drives) {
		if (features)
			puts("DRIVE  SERIAL     MAX PATH  FEATURES");
		else
			puts("DRIVE  TYPE           USED      FREE     TOTAL  TYPE    NAME");
	} else {
		puts("ERROR: No drives found.");
		return 2;
	}

	__gshared char[3] cdp = ` :\`; /// buffer
	for (uint d = 1; d <= drives; d <<= 1) {
		const uint n = drives & d;
		if (n) {
			const char cd = getDrive(n);
			printf("%c:     ", cd);
			cdp[0] = cd;

			if (features) {
				DWORD serial, maxcomp, flags;
				if (GetVolumeInformationA(
						cast(char*)cdp, PCNULL, 0,
						&serial, &maxcomp, &flags, PCNULL, 0)) {
					ushort* sp = cast(ushort*)&serial;
					printf("%04X-%04X  %8d  ", *(sp + 1), *sp, maxcomp);

					if (flags & FILE_CASE_SENSITIVE_SEARCH)
						printf(", CASE_SENSITIVE_SEARCH");
					if (flags & FILE_CASE_PRESERVED_NAMES)
						printf(", CASE_PRESERVED_NAMES");
					if (flags & FILE_PERSISTENT_ACLS)
						printf(", PERSISTENT_ACLS");
					if (flags & FILE_READ_ONLY_VOLUME)
						printf(", READ_ONLY");
					if (flags & FILE_NAMED_STREAMS)
						printf(", NAMED_STREAMS");
					if (flags & FILE_SEQUENTIAL_WRITE_ONCE)
						printf(", SEQ_WRITE_ONCE");
					if (flags & 0x00800000) // FILE_SUPPORTS_EXTENDED_ATTRIBUTES
						printf(", EXTENDED_ATTRIBUTES");
					if (flags & FILE_SUPPORTS_ENCRYPTION)
						printf(", ENCRYPTION");
					if (flags & 0x00400000) // FILE_SUPPORTS_HARD_LINKS
						printf(", HARD_LINKS");
					if (flags & FILE_SUPPORTS_OBJECT_IDS)
						printf(", OBJECT_ID");
					if (flags & 0x01000000) // FILE_SUPPORTS_OPEN_BY_FILE_ID
						printf(", OPEN_BY_FILE_ID");
					if (flags & FILE_SUPPORTS_REPARSE_POINTS)
						printf(", REPARSE_POINTS");
					if (flags & FILE_SUPPORTS_SPARSE_FILES)
						printf(", SPARSE_FILES");
					if (flags & FILE_SUPPORTS_TRANSACTIONS)
						printf(", TRANSACTIONS");
					if (flags & 0x02000000) // FILE_SUPPORTS_USN_JOURNAL
						printf(", USN_JOURNAL");
					if (flags & FILE_UNICODE_ON_DISK)
						printf(", UNICODE");
					if (flags & FILE_FILE_COMPRESSION) {
						if (flags & FILE_VOLUME_IS_COMPRESSED)
							printf(", COMPRESSED");
						else
							printf(", COMPRESSION");
					}
					if (flags & FILE_VOLUME_QUOTAS)
						printf(", QUOTAS");
					if (flags & 0x20000000) // FILE_DAX_VOLUME, added in Windows 10
						printf(", DAX");
				}
			} else { // NO FEATURES, PRINT SIZES
				switch (GetDriveTypeA(cast(char*)cdp)) { // Lazy alert
				default: printf("UNKNOWN  "); break; // 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;
				}

				__gshared ULARGE_INTEGER fb, tb, tfb;
				if (GetDiskFreeSpaceExA(cast(char*)cdp, &fb, &tb, &tfb)) {
					_printfd(tb.QuadPart - tfb.QuadPart);
					_printfd(tfb.QuadPart);
					_printfd(tb.QuadPart);
				}

				char[128] vol, fs;
				if (GetVolumeInformationA(
						cast(char*)cdp, cast(char*)vol, vol.sizeof,
						NULL, NULL, NULL, cast(char*)fs, fs.sizeof)) {
					printf("  %-7s %s", cast(char*)fs, cast(char*)vol);
				}
			}

			puts("");
		} // if (n)
	}

	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,
}

extern (C)
private void _printfd(ulong l) { // LAZY CODE (with spacing!)
	const float f = l; // like those implicit conversions?
	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 {
	final 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';
	}
}