diff --git a/changelog/std-file-getAvailableDiskSpace.dd b/changelog/std-file-getAvailableDiskSpace.dd new file mode 100644 index 00000000000..763db9ef481 --- /dev/null +++ b/changelog/std-file-getAvailableDiskSpace.dd @@ -0,0 +1,17 @@ +Added the `std.file.getAvailableDiskSpace` functionality. + +$(REF getAvailableDiskSpace, std,file) receives as a parameter the path of a file or +directory in the file system, and returns the available disk space on the mounted filesystem. +If the given path is nonexistent, an exception is thrown. + +--- +import std.file; +ulong size = getAvailableDiskSpace("."); +assert(size > 0); +--- + +--- +import std.file; +assertThrown(getAvailableDiskSpace("NonExistentFile")); +--- + diff --git a/std/file.d b/std/file.d index b8930d95e51..31a626814f8 100644 --- a/std/file.d +++ b/std/file.d @@ -62,6 +62,7 @@ $(TR $(TD Other) $(TD $(LREF FileException) $(LREF PreserveAttributes) $(LREF SpanMode) + $(LREF getAvailableDiskSpace) )) ) @@ -5232,3 +5233,74 @@ string tempDir() @trusted myFile.write("hello"); assert(myFile.readText == "hello"); } + +/** +Returns the available disk space based on a given path. +On Windows, `path` must be a directory; on Posix systems, it can be a file or directory. + +Params: + path = on Windows, it must be a directory; on Posix it can be a file or directory +Returns: + Available space in bytes + +Throws: + $(LREF FileException) in case of failure +*/ +ulong getAvailableDiskSpace(scope const(char)[] path) @safe +{ + version (Windows) + { + import core.sys.windows.winbase : GetDiskFreeSpaceExW; + import core.sys.windows.winnt : ULARGE_INTEGER; + import std.internal.cstring : tempCStringW; + + ULARGE_INTEGER freeBytesAvailable; + auto err = () @trusted { + return GetDiskFreeSpaceExW(path.tempCStringW(), &freeBytesAvailable, null, null); + } (); + cenforce(err != 0, "Cannot get available disk space"); + + return freeBytesAvailable.QuadPart; + } + else version (Posix) + { + import std.internal.cstring : tempCString; + + version (FreeBSD) + { + import core.sys.freebsd.sys.mount : statfs, statfs_t; + + statfs_t stats; + auto err = () @trusted { + return statfs(path.tempCString(), &stats); + } (); + cenforce(err == 0, "Cannot get available disk space"); + + return stats.f_bavail * stats.f_bsize; + } + else + { + import core.sys.posix.sys.statvfs : statvfs, statvfs_t; + + statvfs_t stats; + auto err = () @trusted { + return statvfs(path.tempCString(), &stats); + } (); + cenforce(err == 0, "Cannot get available disk space"); + + return stats.f_bavail * stats.f_frsize; + } + } + else static assert(0, "Unsupported platform"); +} + +/// +@safe unittest +{ + import std.exception : assertThrown; + + auto space = getAvailableDiskSpace("."); + assert(space > 0); + + assertThrown!FileException(getAvailableDiskSpace("ThisFileDoesNotExist123123")); +}