import core.sys.windows.windows; import core.stdc.stdio : printf, puts; extern (C): int putchar(int c); enum PROJECT_VER = "0.2.2"; 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; 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, MAX_PATH) -b Use base10 size formatting -n Remove header` ); } void version_() { printf( `ggf v` ~ PROJECT_VER~ ` (` ~ __TIMESTAMP__ ~ `) MIT License: Copyright (c) 2017-2019 dd86k Project page: <https://github.com/dd86k/ggf> Compiled `~__FILE__~` with `~__VENDOR__~" v%d\n", __VERSION__ ); } int main(int argc, char** argv) { bool base10; /// Use base10 notation bool header = true; ubyte feature; // FEATURE_DEFAULT int drive; while (--argc >= 1) { const 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 = 1; 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; /// bit mask to use against drives uint count = void; /// disk count, avoids using big switches if (drive) { d = drives = getMask(drive); count = drive - 0x41; } else { d = 1; count = 0; drives = GetLogicalDrives; if (drives == 0) { puts("ERROR: No drives found."); return 2; } } int swidth = void; /// screen width for % if (feature == FEATURE_POURCENTAGE) { CONSOLE_SCREEN_BUFFER_INFO csbi = void; HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); GetConsoleScreenBufferInfo(hOut, &csbi); swidth = csbi.srWindow.Right - csbi.srWindow.Left - 15; // 14 char buf } if (header) switch (feature) { case FEATURE_DEFAULT: puts("DRIVE TYPE USED FREE TOTAL TYPE NAME"); break; 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("Unknown feature selected"); return 1; } char [3]cd = ` :\`; // buffer char *cdp = cast(char*)cd; for (; d <= drives; d <<= 1, ++count) { const uint n = drives & d; if (n == 0) continue; const char c = getDrive(count); cd[0] = c; printf("%c: ", c); switch (feature) { case FEATURE_DEFAULT: switch (GetDriveTypeA(cdp)) { // Lazy alert case 2: printf("Removable"); break; case 3: printf("Fixed "); break; case 4: printf("Network "); break; case 5: printf("Optical "); break; case 6: printf("RAMDISK "); break; default: puts("UNKNOWN "); continue; // 0+1 } ULARGE_INTEGER dfb = void, dtotal = void, dfree = void; if (GetDiskFreeSpaceExA(cdp, &dfb, &dtotal, &dfree)) { _printfd(dtotal.QuadPart - dfree.QuadPart, base10); _printfd(dfree.QuadPart, base10); _printfd(dtotal.QuadPart, base10); } ubyte [256]vol, fs; // inits to 0, char inits to 0xFF if (GetVolumeInformationA(cdp, cast(char*)vol, vol.length, NULL, NULL, NULL, cast(char*)fs, fs.length)) { printf(" %-7s %s\n", cast(char*)fs, cast(char*)vol); } else putchar('\n'); continue; case FEATURE_FEATURES: DWORD flags = void; if (GetVolumeInformationA(cdp, cast(char*)0, 0, NULL, NULL, &flags, NULL, 0) == 0) goto FEATURES_END; 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 & FILE_SUPPORTS_EXTENDED_ATTRIBUTES) printf("EXTENDED_ATTRIBUTES "); if (flags & FILE_SUPPORTS_ENCRYPTION) printf("ENCRYPTION "); if (flags & FILE_SUPPORTS_HARD_LINKS) printf("HARD_LINKS "); if (flags & FILE_SUPPORTS_OBJECT_IDS) printf("OBJECT_ID "); if (flags & 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 & FILE_SUPPORTS_USN_JOURNAL) printf("USN_JOURNAL "); if (flags & FILE_UNICODE_ON_DISK) printf("UNICODE "); if (flags & FILE_FILE_COMPRESSION) { printf(flags & FILE_VOLUME_IS_COMPRESSED ? "COMPRESSED " : "COMPRESSION "); } if (flags & FILE_VOLUME_QUOTAS) printf("QUOTAS "); if (flags & FILE_DAX_VOLUME) // Added in Windows 10 printf("DAX "); FEATURES_END: putchar('\n'); continue; case FEATURE_POURCENTAGE: ULARGE_INTEGER fb = void, total = void, free = void; if (GetDiskFreeSpaceExA(cdp, &fb, &total, &free)) { const ulong used = total.QuadPart - free.QuadPart; ubyte p_ub = cast(ubyte) // used ((used * swidth) / total.QuadPart); ubyte p_fb = cast(ubyte) // free ((free.QuadPart * swidth) / total.QuadPart); putchar('['); while (--p_ub) putchar('='); while (--p_fb) putchar(' '); printf("] %4.2f%%\n", ((cast(float)used * 100) / total.QuadPart)); } else putchar('\n'); continue; case FEATURE_MISC: ushort[2] serial = void; DWORD maxpath = void; if (GetVolumeInformationA(cdp, NULL, 0, cast(uint*)serial, &maxpath, NULL, NULL, 0)) { printf("%04X-%04X %8d\n", serial[1], serial[0], maxpath); } else putchar('\n'); continue; default: } // 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 private void _printfd(ulong l, bool base10 = false) { 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); } } /** * Converts a drive number to a drive letter * Params: drive = driver number (starting at 0) * Returns: drive letter */ char getDrive(int d) pure { return cast(char)(d + 0x41); } /** * Converts a drive letter to a mask * Params: d = Drive letter ('A' to 'Z') * Returns: Windows drive mask, e.g. 'C' returns 4 */ int getMask(int d) { return 1 << (d - 0x41); }