Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fs: add statfs to fs #31351

Closed
wants to merge 11 commits into from
Closed
124 changes: 124 additions & 0 deletions doc/api/fs.md
Original file line number Diff line number Diff line change
Expand Up @@ -1001,6 +1001,82 @@ 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`

Provides information about a mounted filesystem.

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`

* {number|bigint}

Free blocks available to unprivileged user.

### `statfs.bfree`

* {number|bigint}

Free blocks in filesystem.

### `statfs.blocks`

* {number|bigint}

Total data blocks in filesystem.

### `statfs.bsize`

* {number|bigint}

Optimal transfer block size.

### `statfs.ffree`

* {number|bigint}

Free file nodes in filesystem.

### `statfs.files`

* {number|bigint}

Total file nodes in filesystem.

### `statfs.type`

* {number|bigint}

Type of filesystem.

## Class: `fs.WriteStream`
<!-- YAML
added: v0.1.93
Expand Down Expand Up @@ -3465,6 +3541,39 @@ changes:

Synchronous stat(2).

## `fs.statfs(path[, options], callback)`
<!-- YAML
added: REPLACEME
-->
SheikhSajid marked this conversation as resolved.
Show resolved Hide resolved

* `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). The callback gets two arguments `(err, stats)` where
`stats` is an [`fs.StatFs`][] object.

Returns information about the mounted filesystem which contains `path`.

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

## `fs.statfsSync(path[, options])`
SheikhSajid marked this conversation as resolved.
Show resolved Hide resolved
<!-- YAML
added: REPLACME
-->

* `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).

## `fs.symlink(target, path[, type], callback)`
<!-- YAML
added: v0.1.31
Expand Down Expand Up @@ -5124,6 +5233,19 @@ changes:

The `Promise` is resolved with the [`fs.Stats`][] object for the given `path`.

### `fsPromises.statfs(path[, options])`
<!-- YAML
added: REPLACEME
-->
SheikhSajid marked this conversation as resolved.
Show resolved Hide resolved

* `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}

The `Promise` is resolved with the [`fs.StatFs`][] object for the given `path`.

### `fsPromises.symlink(target, path[, type])`
<!-- YAML
added: v10.0.0
Expand Down Expand Up @@ -5586,6 +5708,7 @@ the file contents.
[`fs.Dirent`]: #fs_class_fs_dirent
[`fs.FSWatcher`]: #fs_class_fs_fswatcher
[`fs.Stats`]: #fs_class_fs_stats
[`fs.StatFs`]: #fs_class_fs_statfs
[`fs.access()`]: #fs_fs_access_path_mode_callback
[`fs.chmod()`]: #fs_fs_chmod_path_mode_callback
[`fs.chown()`]: #fs_fs_chown_path_uid_gid_callback
Expand All @@ -5609,6 +5732,7 @@ the file contents.
[`fs.realpath()`]: #fs_fs_realpath_path_options_callback
[`fs.rmdir()`]: #fs_fs_rmdir_path_options_callback
[`fs.stat()`]: #fs_fs_stat_path_options_callback
[`fs.statfs()`]: #fs_fs_statfs_path_options_callback
[`fs.symlink()`]: #fs_fs_symlink_target_path_type_callback
[`fs.utimes()`]: #fs_fs_utimes_path_atime_mtime_callback
[`fs.watch()`]: #fs_fs_watch_filename_options_listener
Expand Down
30 changes: 30 additions & 0 deletions lib/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const {
Dirent,
getDirents,
getOptions,
getStatFsFromBinding,
getValidatedPath,
getValidMode,
handleErrorFromBinding,
Expand Down Expand Up @@ -936,6 +937,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 = {};
}

callback = maybeCallback(callback);

const oncompleteCallback = (err, statsArray) => {
if (err) return callback(err);
callback(err, getStatFsFromBinding(statsArray));
};
path = getValidatedPath(path);
const req = new FSReqCallback(options.bigint);
req.oncomplete = oncompleteCallback;
binding.statfs(pathModule.toNamespacedPath(path), options.bigint, req);
}

function fstatSync(fd, options = { bigint: false }) {
validateInt32(fd, 'fd', 0);
const ctx = { fd };
Expand All @@ -962,6 +981,15 @@ function statSync(path, options = { bigint: false }) {
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);
}

function readlink(path, options, callback) {
callback = makeCallback(typeof options === 'function' ? options : callback);
options = getOptions(options, {});
Expand Down Expand Up @@ -1920,7 +1948,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
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ const {
getDirents,
getOptions,
getStatsFromBinding,
getStatFsFromBinding,
getValidatedPath,
getValidMode,
nullCheck,
Expand Down Expand Up @@ -405,6 +406,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 @@ -536,6 +544,7 @@ module.exports = {
symlink,
lstat,
stat,
statfs,
link,
unlink,
chmod,
Expand Down
19 changes: 19 additions & 0 deletions lib/internal/fs/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,24 @@ function getStatsFromBinding(stats, offset = 0) {
);
}

function StatFs(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) {
if (typeof flags === 'number') {
return flags;
Expand Down Expand Up @@ -669,6 +687,7 @@ module.exports = {
getDirent,
getDirents,
getOptions,
getStatFsFromBinding,
getValidatedPath,
getValidMode,
handleErrorFromBinding,
Expand Down
8 changes: 8 additions & 0 deletions src/env-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -615,6 +615,14 @@ inline AliasedBigUint64Array* Environment::fs_stats_field_bigint_array() {
return &fs_stats_field_bigint_array_;
}

inline AliasedFloat64Array* Environment::fs_statfs_field_array() {
return &fs_statfs_field_array_;
}

inline AliasedBigUint64Array* Environment::fs_statfs_field_bigint_array() {
return &fs_statfs_field_bigint_array_;
}

inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
Environment::file_handle_read_wrap_freelist() {
return file_handle_read_wrap_freelist_;
Expand Down
5 changes: 5 additions & 0 deletions src/env.cc
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ Environment::Environment(IsolateData* isolate_data,
thread_id_(thread_id == kNoThreadId ? AllocateThreadId() : thread_id),
fs_stats_field_array_(isolate_, kFsStatsBufferLength),
fs_stats_field_bigint_array_(isolate_, kFsStatsBufferLength),
fs_statfs_field_array_(isolate_, kFsStatfsBufferLength),
fs_statfs_field_bigint_array_(isolate_, kFsStatfsBufferLength),
context_(context->GetIsolate(), context) {
// We'll be creating new objects so make sure we've entered the context.
HandleScope handle_scope(isolate());
Expand Down Expand Up @@ -1068,6 +1070,9 @@ void Environment::MemoryInfo(MemoryTracker* tracker) const {
tracker->TrackField("fs_stats_field_array", fs_stats_field_array_);
tracker->TrackField("fs_stats_field_bigint_array",
fs_stats_field_bigint_array_);
tracker->TrackField("fs_statfs_field_array", fs_statfs_field_array_);
tracker->TrackField("fs_statfs_field_bigint_array",
fs_statfs_field_bigint_array_);
tracker->TrackField("cleanup_hooks", cleanup_hooks_);
tracker->TrackField("async_hooks", async_hooks_);
tracker->TrackField("immediate_info", immediate_info_);
Expand Down
20 changes: 20 additions & 0 deletions src/env.h
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,20 @@ enum class FsStatsOffset {
constexpr size_t kFsStatsBufferLength =
static_cast<size_t>(FsStatsOffset::kFsStatsFieldsNumber) * 2;

enum class FsStatfsOffset {
kType = 0,
kBSize,
kBlocks,
kBFree,
kBAvail,
kFiles,
kFFree,
kFsStatFsFieldsNumber
};

constexpr size_t kFsStatfsBufferLength =
static_cast<size_t>(FsStatfsOffset::kFsStatFsFieldsNumber);

// PER_ISOLATE_* macros: We have a lot of per-isolate properties
// and adding and maintaining their getters and setters by hand would be
// difficult so let's make the preprocessor generate them for us.
Expand Down Expand Up @@ -1025,6 +1039,9 @@ class Environment : public MemoryRetainer {
inline AliasedFloat64Array* fs_stats_field_array();
inline AliasedBigUint64Array* fs_stats_field_bigint_array();

inline AliasedFloat64Array* fs_statfs_field_array();
inline AliasedBigUint64Array* fs_statfs_field_bigint_array();

inline std::vector<std::unique_ptr<fs::FileHandleReadWrap>>&
file_handle_read_wrap_freelist();

Expand Down Expand Up @@ -1386,6 +1403,9 @@ class Environment : public MemoryRetainer {
AliasedFloat64Array fs_stats_field_array_;
AliasedBigUint64Array fs_stats_field_bigint_array_;

AliasedFloat64Array fs_statfs_field_array_;
AliasedBigUint64Array fs_statfs_field_bigint_array_;

std::vector<std::unique_ptr<fs::FileHandleReadWrap>>
file_handle_read_wrap_freelist_;

Expand Down
Loading