D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 16487 - Add function to obtain the available disk space
Summary: Add function to obtain the available disk space
Status: RESOLVED FIXED
Alias: None
Product: D
Classification: Unclassified
Component: phobos (show other issues)
Version: D2
Hardware: All All
: P1 enhancement
Assignee: alex.jercaianu
URL:
Keywords: pull
Depends on:
Blocks:
 
Reported: 2016-09-11 21:20 UTC by Johan Engelen
Modified: 2019-06-28 06:36 UTC (History)
4 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Johan Engelen 2016-09-11 21:20:54 UTC
Would be nice to have a function that returns the available disk space on a given path (file, directory, server share).

Something like this:
```
// Returns ulong.max when the available disk space could not be determined.
ulong getAvailableDiskSpace(string path)
{
    import std.string: toStringz;
    version (WINDOWS)
    {
        import core.sys.windows.winbase;

        ULARGE_INTEGER freeBytesAvailable;
        auto pathCstr = (driveName(path) ~ dirSeparator).toStringz();
        bool success = GetDiskFreeSpaceExW(path, &freeBytesAvailable, null, null);
        return success ? free_bytes.QuadPart : ulong.max;
    }
    else
    {
        import core.sys.posix.sys.statvfs;

        statvfs_t stats;
        int err = statvfs(path.toStringz(), &stats);
        return !err ? stats.f_bavail * stats.f_frsize : ulong.max;
    }
}
```
Comment 1 anonymous4 2016-09-12 10:10:01 UTC
NTFS supports symbolic links too, so GetDiskFreeSpaceExW should receive the folder path because it can reside on a different partition than the disk it's accessed through.
Comment 2 Johan Engelen 2016-09-12 11:25:34 UTC
Indeed, I misread GetDiskFreeSpaceEx's documentation. Thanks.
Comment 3 Johan Engelen 2016-09-13 08:11:49 UTC
Version that actually compiles on Windows too:
```
// Returns ulong.max when the available disk space could not be determined.
ulong getAvailableDiskSpace(string path)
{
    import std.string: toStringz;
    version (Windows)
    {
        import std.path;
        import core.sys.windows.winbase;
        import core.sys.windows.winnt;
        import std.internal.cstring;

        ULARGE_INTEGER freeBytesAvailable;
        path ~= dirSeparator;
        auto success = GetDiskFreeSpaceExW(path.tempCStringW(), &freeBytesAvailable, null, null);
        return success ? freeBytesAvailable.QuadPart : ulong.max;
    }
    else
    {
        import core.sys.posix.sys.statvfs;

        statvfs_t stats;
        int err = statvfs(path.toStringz(), &stats);
        return !err ? stats.f_bavail * stats.f_frsize : ulong.max;
    }
}
```
Comment 4 basile-z 2016-09-13 08:56:14 UTC
(In reply to Johan Engelen from comment #3)
> Version that actually compiles on Windows too:
> ```
> // Returns ulong.max when the available disk space could not be determined.
> ulong getAvailableDiskSpace(string path)
> {
>     import std.string: toStringz;
>     version (Windows)
>     {
>         import std.path;
>         import core.sys.windows.winbase;
>         import core.sys.windows.winnt;
>         import std.internal.cstring;
> 
>         ULARGE_INTEGER freeBytesAvailable;
>         path ~= dirSeparator;
>         auto success = GetDiskFreeSpaceExW(path.tempCStringW(),
> &freeBytesAvailable, null, null);
>         return success ? freeBytesAvailable.QuadPart : ulong.max;
>     }
>     else
>     {
>         import core.sys.posix.sys.statvfs;
> 
>         statvfs_t stats;
>         int err = statvfs(path.toStringz(), &stats);
>         return !err ? stats.f_bavail * stats.f_frsize : ulong.max;
>     }
> }
> ```

what I would say if it'd be a PR:

1. change declaration to 

    ulong getAvailableDiskSpace(const(char)[] path)

because const(char)[] acts as a wildcard and takes all char[] variants.

2. returns -1 on failure. ulong.max: No way !!!

3. linux version: don't need to init the target so

    statvfs_t stats = void;

Otherwise let's get the merge ;)
Comment 5 Johan Engelen 2016-09-13 09:20:48 UTC
(In reply to b2.temp from comment #4)
> 2. returns -1 on failure. ulong.max: No way !!!

The return type is _unsigned_.
Throwing an exception is also a possibility.
Comment 6 basile-z 2016-09-13 10:35:58 UTC
(In reply to Johan Engelen from comment #5)
> (In reply to b2.temp from comment #4)
> > 2. returns -1 on failure. ulong.max: No way !!!
> 
> The return type is _unsigned_.

Oops, sorry , i must be blind ^^

Anyway...Wouldn't 0 be a possible return type in case of error ? 
It would allow:

if (auto space = getAvailableDiskSpace(root))
{
}
else
{
    throw new Exception("either the disk is full or inaccessible");
}

> Throwing an exception is also a possibility.

No, seriously, delegate this option to the user.
Comment 7 Jack Stouffer 2016-09-13 13:19:07 UTC
(In reply to b2.temp from comment #6)
> Anyway...Wouldn't 0 be a possible return type in case of error

No. What if there's no more space in the drive? Would you return something other than zero?
Comment 8 basile-z 2016-09-13 14:18:15 UTC
In both cases I 'd return 0.

        statvfs_t stats;
        int err = statvfs(path.toStringz(), &stats);
        return err ?  0 : stats.f_bavail * stats.f_frsize;

> "either the disk is full or inaccessible"

Because in both cases you can do nothing. By the way HDD are never full.
Only removable media can be full (bootable USB key, DVD/CD rom, etc).
Comment 9 Seb 2016-12-27 12:54:49 UTC
@Johan: As you have already prepared a nice function & no one disagrees that it wouldn't be useful - I assigned this to you. Looking forward to your PR ;-)
Comment 10 Johan Engelen 2016-12-27 22:19:58 UTC
Unassigning myself. I'm not going to work on this any time soon.
Comment 11 alex.jercaianu 2017-10-09 16:01:25 UTC
Hi,

I'd like to take this task.
In which part of the std do you think it would be best to put this function?

Thanks,
Alex
Comment 12 basile-z 2017-10-09 16:14:57 UTC
std.file makes more sense. User wants available disk space to know if it can create a file or how many byte in disk a cache can use (or whatever else).
Much less useful in std.path.

ideally there would be:

std.filesystem.file
std.filesystem.path
std.filesystem.package <-- i would put it here

but since it's not the case std.file is the best ooption.
Comment 14 Dlang Bot 2019-06-18 23:27:28 UTC
@jercaianu updated dlang/phobos pull request #5776 "Fix Issue 16487 - Add function to obtain the available disk space" fixing this issue:

- Fix Issue 16487 - Add function to obtain the available disk space

- Fix Issue 16487 - Add function to obtain the available disk space

https://github.com/dlang/phobos/pull/5776
Comment 15 Dlang Bot 2019-06-28 06:36:04 UTC
dlang/phobos pull request #5776 "Fix Issue 16487 - Add function to obtain the available disk space" was merged into master:

- d38cbf90cbd66685efa51b5c9a553ff253c7c1a5 by Alexandru Jercaianu:
  Fix Issue 16487 - Add function to obtain the available disk space

https://github.com/dlang/phobos/pull/5776