Chapter 54. Free disk space

#include <x/df.H>

x::df space;

// ...


// ...


// ...

std::cout << x::fmtsize(space->allocSize() * space->allocFree())
          << " (" << x::fmtsize(space->allocSize())
          << " allocation unit), "
          <<  space->inodeFree() << " inodes left" << std::endl;

// ...


x::df is a reference to a reference-counted object that reports on the amount of free space left on a disk partition. create() takes either an explicit name of any file or directory on the partition, or an open file descriptor.


If a reference to a file descriptor object is specified, a reference to this file descriptor object remains until the last reference to the disk space object goes out of scope, and the underlying file descriptor must remain open to the same file.

The allocFree() method returns the number of free allocation units remaining on the partition. inodeFree() returns the number of free inodes. These methods report the number of allocation units, or inodes, for non-privileged users. allocSize() returns the size of an allocation unit, in bytes.


The amount of free space or inodes gets retrieved initially by x::df::create(), and the referenced object's methods only report on the retrieved usage, they do not recheck it. refresh() reloads the amount of free disk space and inodes, to reflect any changes since the last x::df::create(), or refresh() method was called.

There's a reservation mechanism that temporarily excludes some amount of free disk space or inodes from being reported:

x::df::reservation res(space->reserve(1024 * 1024 / space->allocSize(), 100));

This example excludes one megabyte and 100 inodes from being reported by all subsequent calls to allocFree() and inodeFree(). The first parameter to reserve() is the number of allocation units to exclude, the second parameter is the number of inodes to exclude.

The reserved amount continues to be excluded after subsequent calls to refresh(). x::df::reservation is a reference to a reference-counted object. The reserved amount remains excluded as long as the underlying object remains in scope. When the last x::df::reservation goes out of scope and the object gets destroyed, subsequent calls to allocFree() and inodeFree() no longer exclude the reserved amount.

Invoking the reservation object's commit() method has the effect that the reserved space remains in reserve until the next call to refresh(), rather than until the reservation handle goes out of scope.

Multiple reservations may be instantiated, and are tracked separately. The total number of reserved allocation units and inodes is a long, and cannot exceed the maximum value that may be stored in a long. The reservation object is thread-safe.


If invoking allocFree() and inodeFree() one after another, another thread may make or release a reservation between the two calls. Furthermore, although the allocation unit count and inode count are atomic values, the process of allocating or releasing a reservation is not an atomic; it updates one value, or the other. In a multithreaded context, the amounts reported by allocFree() and inodeFree(), in any order, may include only one value claimed by a reservation and not the other one, either the allocation unit count or the inode count, if another thread is in the middle of making or releasing a reservation.