diff --git a/src/backends/port/fs.ts b/src/backends/port/fs.ts index e6e6b00c..99a7a2a8 100644 --- a/src/backends/port/fs.ts +++ b/src/backends/port/fs.ts @@ -6,7 +6,7 @@ import { Errno, ErrnoError } from '../../error.js'; import { File } from '../../file.js'; import { FileSystem, type FileSystemMetadata } from '../../filesystem.js'; import { Async } from '../../mixins/async.js'; -import { Stats, type FileType } from '../../stats.js'; +import { Stats } from '../../stats.js'; import type { Backend, FilesystemOf } from '../backend.js'; import { InMemory } from '../memory.js'; import * as RPC from './rpc.js'; @@ -104,10 +104,6 @@ export class PortFile extends File { this._throwNoSync('utimes'); } - public _setType(type: FileType): Promise { - return this.rpc('_setType', type); - } - public _setTypeSync(): void { this._throwNoSync('_setType'); } diff --git a/src/emulation/promises.ts b/src/emulation/promises.ts index 59cae005..933704c4 100644 --- a/src/emulation/promises.ts +++ b/src/emulation/promises.ts @@ -822,7 +822,7 @@ export async function symlink(target: fs.PathLike, path: fs.PathLike, type: fs.s await using handle = await _open(path, 'w+', 0o644, false); await handle.writeFile(target.toString()); - await handle.file._setType(constants.S_IFLNK); + await handle.file.chmod(constants.S_IFLNK); } symlink satisfies typeof promises.symlink; diff --git a/src/emulation/sync.ts b/src/emulation/sync.ts index f5869d5a..4e5a5349 100644 --- a/src/emulation/sync.ts +++ b/src/emulation/sync.ts @@ -550,7 +550,7 @@ export function symlinkSync(target: fs.PathLike, path: fs.PathLike, type: fs.sym writeFileSync(path, target.toString()); const file = _openSync(path, 'r+', 0o644, false); - file._setTypeSync(constants.S_IFLNK); + file.chmodSync(constants.S_IFLNK); } symlinkSync satisfies typeof fs.symlinkSync; diff --git a/src/file.ts b/src/file.ts index d82d1397..97294b55 100644 --- a/src/file.ts +++ b/src/file.ts @@ -4,7 +4,7 @@ import { O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_SYNC, O_TRUNC, O_WRONLY, import { Errno, ErrnoError } from './error.js'; import type { FileSystem } from './filesystem.js'; import './polyfills.js'; -import { Stats, type FileType } from './stats.js'; +import { _chown, Stats } from './stats.js'; /** Typescript does not include a type declaration for resizable array buffers. @@ -251,18 +251,6 @@ export abstract class File { * Change the file timestamps of the file. */ public abstract utimesSync(atime: Date, mtime: Date): void; - - /** - * Set the file type - * @internal - */ - public abstract _setType(type: FileType): Promise; - - /** - * Set the file type - * @internal - */ - public abstract _setTypeSync(type: FileType): void; } /** @@ -573,8 +561,8 @@ export class PreloadFile extends File { throw ErrnoError.With('EBADF', this.path, 'File.chmod'); } this.dirty = true; - this.stats.chmod(mode); - if (config.syncImmediately) await this.sync(); + this.stats.mode = (this.stats.mode & (mode > S_IFMT ? ~S_IFMT : S_IFMT)) | mode; + if (config.syncImmediately || mode > S_IFMT) await this.sync(); } public chmodSync(mode: number): void { @@ -582,8 +570,8 @@ export class PreloadFile extends File { throw ErrnoError.With('EBADF', this.path, 'File.chmod'); } this.dirty = true; - this.stats.chmod(mode); - if (config.syncImmediately) this.syncSync(); + this.stats.mode = (this.stats.mode & (mode > S_IFMT ? ~S_IFMT : S_IFMT)) | mode; + if (config.syncImmediately || mode > S_IFMT) this.syncSync(); } public async chown(uid: number, gid: number): Promise { @@ -591,7 +579,7 @@ export class PreloadFile extends File { throw ErrnoError.With('EBADF', this.path, 'File.chown'); } this.dirty = true; - this.stats.chown(uid, gid); + _chown(this.stats, uid, gid); if (config.syncImmediately) await this.sync(); } @@ -600,7 +588,7 @@ export class PreloadFile extends File { throw ErrnoError.With('EBADF', this.path, 'File.chown'); } this.dirty = true; - this.stats.chown(uid, gid); + _chown(this.stats, uid, gid); if (config.syncImmediately) this.syncSync(); } @@ -623,24 +611,6 @@ export class PreloadFile extends File { this.stats.mtime = mtime; if (config.syncImmediately) this.syncSync(); } - - public async _setType(type: FileType): Promise { - if (this.closed) { - throw ErrnoError.With('EBADF', this.path, 'File._setType'); - } - this.dirty = true; - this.stats.mode = (this.stats.mode & ~S_IFMT) | type; - await this.sync(); - } - - public _setTypeSync(type: FileType): void { - if (this.closed) { - throw ErrnoError.With('EBADF', this.path, 'File._setType'); - } - this.dirty = true; - this.stats.mode = (this.stats.mode & ~S_IFMT) | type; - this.syncSync(); - } } /** diff --git a/src/stats.ts b/src/stats.ts index a0c4d33f..9db3453a 100644 --- a/src/stats.ts +++ b/src/stats.ts @@ -67,6 +67,10 @@ export interface StatsLike { * Inode number */ ino: T; + /** + * Number of hard links + */ + nlink: T; } /** @@ -277,6 +281,7 @@ export abstract class StatsCommon implements Node.Sta * Change the mode of the file. * We use this helper function to prevent messing up the type of the file. * @internal + * @deprecated This will be removed in the next minor release since it is internal */ public chmod(mode: number): void { this.mode = this._convert((this.mode & S_IFMT) | mode); @@ -286,8 +291,9 @@ export abstract class StatsCommon implements Node.Sta * Change the owner user/group of the file. * This function makes sure it is a valid UID/GID (that is, a 32 unsigned int) * @internal + * @deprecated This will be removed in the next minor release since it is internal */ - public chown(uid: number | bigint, gid: number | bigint): void { + public chown(uid: number, gid: number): void { uid = Number(uid); gid = Number(gid); if (!isNaN(uid) && 0 <= uid && uid < 2 ** 32) { @@ -315,6 +321,18 @@ export abstract class StatsCommon implements Node.Sta } } +/** + * @hidden @internal + */ +export function _chown(stats: Partial>, uid: number, gid: number) { + if (!isNaN(uid) && 0 <= uid && uid < 2 ** 32) { + stats.uid = uid; + } + if (!isNaN(gid) && 0 <= gid && gid < 2 ** 32) { + stats.gid = gid; + } +} + /** * Implementation of Node's `Stats`. *