C# 文件系统配额查询 C#如何获取Windows或Linux用户的磁盘配额信息

7次阅读

getdiskfreespaceex 和 driveinfo 不返回用户配额信息,因windows配额是ntfs卷级sid策略;需用wmi(win32_quotasetting/win32_diskquota)或netapi32查询,且须管理员权限。

C# 文件系统配额查询 C#如何获取Windows或Linux用户的磁盘配额信息

windows 下用 GetDiskFreeSpaceEx 只能看总量,不返回配额

很多人调用 GetDiskFreeSpaceExDriveInfo 后发现 AvailableFreeSpace 和磁盘实际“剩余额度”对不上——不是 bug,是它压根不感知用户配额。Windows 配额是 NTFS 卷级策略,按用户 SID 限制,和卷总空间无关。

真正要查配额,得走 WMI 或 Win32 API 的 Win32_QuotaSetting + Win32_DiskQuota。但注意:Win32_DiskQuota 在 Windows 10/11 默认禁用,且仅对启用了配额的 NTFS 卷有效。

  • 必须以管理员权限运行,否则查询返回空或拒绝访问
  • Win32_DiskQuotaLimitUsage 字段单位是字节,不是 KB/MB,别直接除 1024 搞错量级
  • 查当前用户配额,得先用 WindowsIdentity.GetCurrent().User.Value 拿 SID,再匹配 QuotaEntryUserId

linux 下没有统一“用户磁盘配额”API,靠 quotactl 系统调用

.NET 6+ 的 System.IO.DriveInfo 在 Linux 上完全忽略配额——它只读 /proc/mountsstatvfs,而配额信息存在 /aquota.user/quota.user 文件里,需用 quotactl

C# 没有内置封装,得 P/Invoke libcquotactl 函数。参数极易出错:比如 cmdQCMD(Q_GETQUOTA, USRQUOTA) 而不是硬编码数字;id 是 uid_t 类型(32 位),不是 .NET 的 int(可能溢出)。

  • 必须确保文件系统挂载时带 usrquotagrpquota 选项,否则 quotactl 返回 ENOSYS
  • 目标路径得是挂载点(如 /home),不是任意目录;传 /home/user 会失败
  • Struct dqblk 的字段顺序、填充字节与 libc 版本强相关,建议用 Marshal.SizeOf<dqblk>()</dqblk> 校验,别手写偏移

跨平台抽象层别硬造,配额逻辑天然不兼容

试图写一个 IQuotaProvider.GetQuota(String path, string user) 并让它在 Windows/Linux 都工作,大概率掉坑里。两边模型根本不同:Windows 配额绑定 SID + 卷,Linux 绑定 uid + 挂载点 + quota 文件位置,且 Linux 还分 v1/v2 quota 格式。

更现实的做法是分环境实现,用 #if WINDOWS / #if LINUX 隔离。别把配额当“文件系统属性”去泛化,它其实是操作系统策略子系统的一部分。

  • Windows 侧优先用 WMI(可读性强),性能差就换 NetApi32.dllNetUserGetInfo 查配额状态(但不返回用量)
  • Linux 侧不要依赖 quota 命令行工具输出——格式随 locale 变,解析不可靠;坚持用 quotactl
  • 没配额时,Windows 返回 Limit = 0,Linux 返回 dqb_bsoftlimit = 0,别当成“无限”,得结合 dqb_bhardlimit 判断是否启用

权限和错误处理比逻辑本身更关键

配额查询失败,90% 不是代码写错,而是权限或配置问题。Windows 报 UnauthorizedaccessException,大概率没管理员权限;Linux 报 EPERM,八成是没开 quota 或进程没 CAP_SYS_ADMIN

别在 catch 里吞掉异常然后返回 “0 bytes available”。真实场景中,配额未启用、服务未启动、路径不在配额卷上,都该区分反馈。

  • Windows:检查 Win32_QuotaSetting.QuotaState == true 再查配额项,否则直接跳过
  • Linux:先 access("/path/aquota.user", F_OK) 确认 quota 文件存在,再调 quotactl
  • 所有路径输入必须做 Path.GetFullPath 归一化,Linux 下 /home/../home 可能绕过挂载点判断

配额不是文件系统自带能力,它是额外开启的策略控制模块。查不到数据时,先确认它是否真的被启用,而不是急着改代码。

text=ZqhQzanResources