@zenfs/core
Version:
A filesystem, anywhere
243 lines (242 loc) • 6.53 kB
JavaScript
import { pick } from 'utilium';
import { _inode_fields, hasAccess } from '../internal/inode.js';
import * as c from '../constants.js';
const n1000 = BigInt(1000);
/**
* Provides information about a particular entry in the file system.
* Common code used by both Stats and BigIntStats.
*/
export class StatsCommon {
_convert(arg) {
return (this._isBigint ? BigInt(arg) : Number(arg));
}
get blocks() {
return this._convert(Math.ceil(Number(this.size) / 512));
}
set blocks(value) { }
/**
* Unix-style file mode (e.g. 0o644) that includes the type of the item.
*/
mode;
/**
* ID of device containing file
*/
dev = this._convert(0);
/**
* Inode number
*/
ino = this._convert(0);
/**
* Device ID (if special file)
*/
rdev = this._convert(0);
/**
* Number of hard links
*/
nlink = this._convert(1);
/**
* Block size for file system I/O
*/
blksize = this._convert(4096);
/**
* User ID of owner
*/
uid = this._convert(0);
/**
* Group ID of owner
*/
gid = this._convert(0);
/**
* Time of last access, since epoch
*/
atimeMs;
get atime() {
return new Date(Number(this.atimeMs));
}
set atime(value) {
this.atimeMs = this._convert(value.getTime());
}
/**
* Time of last modification, since epoch
*/
mtimeMs;
get mtime() {
return new Date(Number(this.mtimeMs));
}
set mtime(value) {
this.mtimeMs = this._convert(value.getTime());
}
/**
* Time of last time file status was changed, since epoch
*/
ctimeMs;
get ctime() {
return new Date(Number(this.ctimeMs));
}
set ctime(value) {
this.ctimeMs = this._convert(value.getTime());
}
/**
* Time of file creation, since epoch
*/
birthtimeMs;
get birthtime() {
return new Date(Number(this.birthtimeMs));
}
set birthtime(value) {
this.birthtimeMs = this._convert(value.getTime());
}
/**
* Size of the item in bytes.
* For directories/symlinks, this is normally the size of the struct that represents the item.
*/
size;
/**
* @internal Used by inodes
*/
data;
/**
* @internal Used by inodes
*/
flags;
/**
* @internal Used by inodes
*/
version;
/**
* Creates a new stats instance from a stats-like object. Can be used to copy stats (note)
*/
constructor({ atimeMs, mtimeMs, ctimeMs, birthtimeMs, uid, gid, size, mode, ino, ...rest } = {}) {
const now = Date.now();
this.atimeMs = this._convert(atimeMs ?? now);
this.mtimeMs = this._convert(mtimeMs ?? now);
this.ctimeMs = this._convert(ctimeMs ?? now);
this.birthtimeMs = this._convert(birthtimeMs ?? now);
this.uid = this._convert(uid ?? 0);
this.gid = this._convert(gid ?? 0);
this.size = this._convert(size ?? 0);
this.ino = this._convert(ino ?? 0);
this.mode = this._convert(mode ?? 0o644 & c.S_IFREG);
if ((this.mode & c.S_IFMT) == 0) {
this.mode = (this.mode | this._convert(c.S_IFREG));
}
Object.assign(this, rest);
}
isFile() {
return (this.mode & c.S_IFMT) === c.S_IFREG;
}
isDirectory() {
return (this.mode & c.S_IFMT) === c.S_IFDIR;
}
isSymbolicLink() {
return (this.mode & c.S_IFMT) === c.S_IFLNK;
}
isSocket() {
return (this.mode & c.S_IFMT) === c.S_IFSOCK;
}
isBlockDevice() {
return (this.mode & c.S_IFMT) === c.S_IFBLK;
}
isCharacterDevice() {
return (this.mode & c.S_IFMT) === c.S_IFCHR;
}
isFIFO() {
return (this.mode & c.S_IFMT) === c.S_IFIFO;
}
toJSON() {
return pick(this, _inode_fields);
}
/**
* Checks if a given user/group has access to this item
* @param mode The requested access, combination of W_OK, R_OK, and X_OK
* @returns True if the request has access, false if the request does not
* @internal
*/
hasAccess(mode, context) {
return hasAccess(context, this._isBigint ? new Stats(this) : this, mode);
}
get atimeNs() {
return BigInt(this.atimeMs) * n1000;
}
get mtimeNs() {
return BigInt(this.mtimeMs) * n1000;
}
get ctimeNs() {
return BigInt(this.ctimeMs) * n1000;
}
get birthtimeNs() {
return BigInt(this.birthtimeMs) * n1000;
}
}
/**
* Implementation of Node's `Stats`.
*
* Attribute descriptions are from `man 2 stat'
* @see http://nodejs.org/api/fs.html#fs_class_fs_stats
* @see http://man7.org/linux/man-pages/man2/stat.2.html
*/
export class Stats extends StatsCommon {
_isBigint = false;
}
Stats;
/**
* Stats with bigint
*/
export class BigIntStats extends StatsCommon {
_isBigint = true;
}
/**
* Determines if the file stats have changed by comparing relevant properties.
*
* @param left The previous stats.
* @param right The current stats.
* @returns `true` if stats have changed; otherwise, `false`.
* @internal
*/
export function isStatsEqual(left, right) {
return (left.size == right.size
&& +left.atime == +right.atime
&& +left.mtime == +right.mtime
&& +left.ctime == +right.ctime
&& left.mode == right.mode);
}
/** @internal */
export const ZenFsType = 0x7a656e6673; // 'z' 'e' 'n' 'f' 's'
/**
* @hidden
*/
export class StatsFs {
/** Type of file system. */
type = 0x7a656e6673;
/** Optimal transfer block size. */
bsize = 4096;
/** Total data blocks in file system. */
blocks = 0;
/** Free blocks in file system. */
bfree = 0;
/** Available blocks for unprivileged users */
bavail = 0;
/** Total file nodes in file system. */
files = c.size_max;
/** Free file nodes in file system. */
ffree = c.size_max;
}
/**
* @hidden
*/
export class BigIntStatsFs {
/** Type of file system. */
type = BigInt('0x7a656e6673');
/** Optimal transfer block size. */
bsize = BigInt(4096);
/** Total data blocks in file system. */
blocks = BigInt(0);
/** Free blocks in file system. */
bfree = BigInt(0);
/** Available blocks for unprivileged users */
bavail = BigInt(0);
/** Total file nodes in file system. */
files = BigInt(c.size_max);
/** Free file nodes in file system. */
ffree = BigInt(c.size_max);
}