Building a Cross-Platform Disk Usage Analyzer in C

Building a Cross-Platform Disk Usage Analyzer in C

使用 C 语言构建跨平台磁盘空间分析工具

I wanted a low-level C project that touches memory management, recursive filesystem traversal, and platform-specific APIs — so I built a terminal disk usage analyzer from scratch. No external libraries, just the C standard library and OS system calls. 我想要一个涉及内存管理、递归文件系统遍历和特定平台 API 的底层 C 语言项目,因此我从零开始构建了一个终端磁盘空间分析工具。该项目不依赖任何外部库,仅使用 C 标准库和操作系统系统调用。

What it does 功能概述

  • Recursively scans a directory using nftw()
  • Reports total / used / available disk space (cross-platform)
  • Lists every file sorted by size (ascending) with a proportional ASCII bar chart
  • 使用 nftw() 递归扫描目录
  • 报告总磁盘空间、已用空间和可用空间(跨平台)
  • 按大小升序排列所有文件,并显示比例化的 ASCII 条形图
=== Disk Usage Report ===
Total: 512.0 GB
Used: 210.3 GB
Available: 301.7 GB
[                                        ] 2.0 B ./notes.txt
[########################################] 50.0 MB ./video.mp4

The interesting bugs 有趣的 Bug

Bug 1 — realloc without sizeof total_size = total_size * 2; files = realloc(files, total_size); // ❌ bytes, not entries! Should be total_size * sizeof(FileEntry). Without it, the buffer shrinks to almost nothing and every write past the original bound corrupts the heap — a great reminder that realloc takes bytes, always. Bug 1 — realloc 未使用 sizeof total_size = total_size * 2; files = realloc(files, total_size); // ❌ 这是字节数,不是条目数! 应该使用 total_size * sizeof(FileEntry)。如果不这样做,缓冲区会缩减到几乎为零,任何超出原始边界的写入都会破坏堆内存——这很好地提醒了我们:realloc 接收的参数永远是字节数。

Bug 2 — mixing directories into the file list nftw() calls your callback for every entry — files, directories, symlinks. I had to explicitly filter: if (typeflag != FTW_F) return 0; Bug 2 — 将目录混入文件列表 nftw() 会为每个条目(文件、目录、符号链接)调用回调函数。我必须显式过滤:if (typeflag != FTW_F) return 0;

Bug 3 — no cross-platform disk stats statvfs() works great on Linux/macOS but doesn’t exist on Windows. Solved with an #ifdef _WIN32 split: GetDiskFreeSpaceExA on Windows, statvfs everywhere else, unified behind one function signature. Bug 3 — 缺乏跨平台磁盘统计 statvfs() 在 Linux/macOS 上运行良好,但在 Windows 上不存在。我通过 #ifdef _WIN32 分支解决了这个问题:在 Windows 上使用 GetDiskFreeSpaceExA,在其他系统上使用 statvfs,并将它们统一在一个函数签名下。

Bar chart scaling Once all files are captured, I scale each bar relative to the largest file found: int filled = (int)((double) size / (double) max * BAR_WIDTH); Then qsort with a custom comparator sorts everything ascending by size before printing. 条形图缩放 在捕获所有文件后,我根据找到的最大文件来缩放每个条形图:int filled = (int)((double) size / (double) max * BAR_WIDTH); 然后使用带有自定义比较器的 qsort 在打印前按大小升序排列所有内容。

Repo Single C file + CMakeLists, builds on Linux and Windows (MinGW tested): [https://github.com/SecByShresth/Disk-Usage-CLI.git] 代码仓库 包含单个 C 文件和 CMakeLists,可在 Linux 和 Windows 上构建(已通过 MinGW 测试):[https://github.com/SecByShresth/Disk-Usage-CLI.git]

Would love feedback on the traversal/performance side — currently it walks the entire tree with no depth limit or exclusion list (.git, node_modules, etc.), which is next on my list to fix. 非常欢迎大家在遍历和性能方面提供反馈——目前它会遍历整个目录树,没有深度限制或排除列表(如 .git、node_modules 等),这是我接下来要修复的问题。