Skip to content

Commit

Permalink
fs: add statfs() functions
Browse files Browse the repository at this point in the history
This commit adds statfs() and statfsSync() to the fs module, and
statfs() to the fsPromises module.

Co-authored-by: cjihrig <cjihrig@gmail.com>
Fixes: #10745
Refs: #31351
PR-URL: #46358
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
  • Loading branch information
cjihrig authored and juanarbol committed Mar 5, 2023
1 parent 129dccf commit 643545a
Show file tree
Hide file tree
Showing 10 changed files with 457 additions and 12 deletions.
159 changes: 159 additions & 0 deletions doc/api/fs.md
Expand Up @@ -1525,6 +1525,19 @@ changes:
* Returns: {Promise} Fulfills with the {fs.Stats} object for the
given `path`.
### `fsPromises.statfs(path[, options])`
<!-- YAML
added: REPLACEME
-->
* `path` {string|Buffer|URL}
* `options` {Object}
* `bigint` {boolean} Whether the numeric values in the returned
{fs.StatFs} object should be `bigint`. **Default:** `false`.
* Returns: {Promise} Fulfills with the {fs.StatFs} object for the
given `path`.
### `fsPromises.symlink(target, path[, type])`
<!-- YAML
Expand Down Expand Up @@ -4082,6 +4095,26 @@ Stats {
}
```

### `fs.statfs(path[, options], callback)`

<!-- YAML
added: REPLACEME
-->

* `path` {string|Buffer|URL}
* `options` {Object}
* `bigint` {boolean} Whether the numeric values in the returned
{fs.StatFs} object should be `bigint`. **Default:** `false`.
* `callback` {Function}
* `err` {Error}
* `stats` {fs.StatFs}

Asynchronous statfs(2). Returns information about the mounted file system which
contains `path`. The callback gets two arguments `(err, stats)` where `stats`
is an {fs.StatFs} object.

In case of an error, the `err.code` will be one of [Common System Errors][].

### `fs.symlink(target, path[, type], callback)`

<!-- YAML
Expand Down Expand Up @@ -5822,6 +5855,23 @@ changes:

Retrieves the {fs.Stats} for the path.

### `fs.statfsSync(path[, options])`

<!-- YAML
added: REPLACEME
-->

* `path` {string|Buffer|URL}
* `options` {Object}
* `bigint` {boolean} Whether the numeric values in the returned
{fs.StatFs} object should be `bigint`. **Default:** `false`.
* Returns: {fs.StatFs}

Synchronous statfs(2). Returns information about the mounted file system which
contains `path`.

In case of an error, the `err.code` will be one of [Common System Errors][].

### `fs.symlinkSync(target, path[, type])`

<!-- YAML
Expand Down Expand Up @@ -6908,6 +6958,114 @@ The times in the stat object have the following semantics:
Prior to Node.js 0.12, the `ctime` held the `birthtime` on Windows systems. As
of 0.12, `ctime` is not "creation time", and on Unix systems, it never was.

### Class: `fs.StatFs`

<!-- YAML
added: REPLACEME
-->

Provides information about a mounted file system.

Objects returned from [`fs.statfs()`][] and its synchronous counterpart are of
this type. If `bigint` in the `options` passed to those methods is `true`, the
numeric values will be `bigint` instead of `number`.

```console
StatFs {
type: 1397114950,
bsize: 4096,
blocks: 121938943,
bfree: 61058895,
bavail: 61058895,
files: 999,
ffree: 1000000
}
```

`bigint` version:

```console
StatFs {
type: 1397114950n,
bsize: 4096n,
blocks: 121938943n,
bfree: 61058895n,
bavail: 61058895n,
files: 999n,
ffree: 1000000n
}
```

#### `statfs.bavail`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Free blocks available to unprivileged users.

#### `statfs.bfree`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Free blocks in file system.

#### `statfs.blocks`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Total data blocks in file system.

#### `statfs.bsize`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Optimal transfer block size.

#### `statfs.ffree`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Free file nodes in file system.

#### `statfs.files`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Total file nodes in file system.

#### `statfs.type`

<!-- YAML
added: REPLACEME
-->

* {number|bigint}

Type of file system.

### Class: `fs.WriteStream`

<!-- YAML
Expand Down Expand Up @@ -7751,6 +7909,7 @@ the file contents.
[`fs.rmSync()`]: #fsrmsyncpath-options
[`fs.rmdir()`]: #fsrmdirpath-options-callback
[`fs.stat()`]: #fsstatpath-options-callback
[`fs.statfs()`]: #fsstatfspath-options-callback
[`fs.symlink()`]: #fssymlinktarget-path-type-callback
[`fs.utimes()`]: #fsutimespath-atime-mtime-callback
[`fs.watch()`]: #fswatchfilename-options-listener
Expand Down
30 changes: 30 additions & 0 deletions lib/fs.js
Expand Up @@ -104,6 +104,7 @@ const {
nullCheck,
preprocessSymlinkDestination,
Stats,
getStatFsFromBinding,
getStatsFromBinding,
realpathCacheKey,
stringToFlags,
Expand Down Expand Up @@ -1523,6 +1524,24 @@ function stat(path, options = { bigint: false }, callback) {
binding.stat(pathModule.toNamespacedPath(path), options.bigint, req);
}

function statfs(path, options = { bigint: false }, callback) {
if (typeof options === 'function') {
callback = options;
options = kEmptyObject;
}
callback = maybeCallback(callback);
path = getValidatedPath(path);
const req = new FSReqCallback(options.bigint);
req.oncomplete = (err, stats) => {
if (err) {
return callback(err);
}

callback(err, getStatFsFromBinding(stats));
};
binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req);
}

function hasNoEntryError(ctx) {
if (ctx.errno) {
const uvErr = uvErrmapGet(ctx.errno);
Expand Down Expand Up @@ -1597,6 +1616,15 @@ function statSync(path, options = { bigint: false, throwIfNoEntry: true }) {
return getStatsFromBinding(stats);
}

function statfsSync(path, options = { bigint: false }) {
path = getValidatedPath(path);
const ctx = { path };
const stats = binding.statfs(pathModule.toNamespacedPath(path),
options.bigint, undefined, ctx);
handleErrorFromBinding(ctx);
return getStatFsFromBinding(stats);
}

/**
* Reads the contents of a symbolic link
* referred to by `path`.
Expand Down Expand Up @@ -3025,7 +3053,9 @@ module.exports = fs = {
rmdir,
rmdirSync,
stat,
statfs,
statSync,
statfsSync,
symlink,
symlinkSync,
truncate,
Expand Down
9 changes: 9 additions & 0 deletions lib/internal/fs/promises.js
Expand Up @@ -52,6 +52,7 @@ const {
emitRecursiveRmdirWarning,
getDirents,
getOptions,
getStatFsFromBinding,
getStatsFromBinding,
getValidatedPath,
getValidMode,
Expand Down Expand Up @@ -767,6 +768,13 @@ async function stat(path, options = { bigint: false }) {
return getStatsFromBinding(result);
}

async function statfs(path, options = { bigint: false }) {
path = getValidatedPath(path);
const result = await binding.statfs(pathModule.toNamespacedPath(path),
options.bigint, kUsePromises);
return getStatFsFromBinding(result);
}

async function link(existingPath, newPath) {
existingPath = getValidatedPath(existingPath, 'existingPath');
newPath = getValidatedPath(newPath, 'newPath');
Expand Down Expand Up @@ -919,6 +927,7 @@ module.exports = {
symlink,
lstat,
stat,
statfs,
link,
unlink,
chmod,
Expand Down
19 changes: 19 additions & 0 deletions lib/internal/fs/utils.js
Expand Up @@ -557,6 +557,24 @@ function getStatsFromBinding(stats, offset = 0) {
);
}

class StatFs {
constructor(type, bsize, blocks, bfree, bavail, files, ffree) {
this.type = type;
this.bsize = bsize;
this.blocks = blocks;
this.bfree = bfree;
this.bavail = bavail;
this.files = files;
this.ffree = ffree;
}
}

function getStatFsFromBinding(stats) {
return new StatFs(
stats[0], stats[1], stats[2], stats[3], stats[4], stats[5], stats[6]
);
}

function stringToFlags(flags, name = 'flags') {
if (typeof flags === 'number') {
validateInt32(flags, name);
Expand Down Expand Up @@ -934,6 +952,7 @@ module.exports = {
nullCheck,
preprocessSymlinkDestination,
realpathCacheKey: Symbol('realpathCacheKey'),
getStatFsFromBinding,
getStatsFromBinding,
stringToFlags,
stringToSymlinkType,
Expand Down

0 comments on commit 643545a

Please sign in to comment.