diff --git a/demo/fsa/main.ts b/demo/fsa/main.ts index c67b0e01c..764f47491 100644 --- a/demo/fsa/main.ts +++ b/demo/fsa/main.ts @@ -85,6 +85,13 @@ const demo = async (dir: fsa.IFileSystemDirectoryHandle) => { const listInDir2 = fs.readdirSync('/dir', {withFileTypes: true}) as any; deepEqual(listInDir2[0].name, 'very-cool.txt'); deepEqual(listInDir2[0].isFile(), true); + + console.log('readSync() - can read a file into a buffer'); + const buf = Buffer.alloc(3); + const readHandle = await fs.promises.open('/cool.txt', 'r'); + const bytesRead = fs.readSync(readHandle.fd, buf, 0, 3, 0); + strictEqual(bytesRead, 3); + strictEqual(buf.toString('utf8'), 'wor'); }; const main = async () => { diff --git a/src/fsa-to-node/FsaNodeFs.ts b/src/fsa-to-node/FsaNodeFs.ts index 9b81e3987..3d23896e3 100644 --- a/src/fsa-to-node/FsaNodeFs.ts +++ b/src/fsa-to-node/FsaNodeFs.ts @@ -958,8 +958,23 @@ export class FsaNodeFs extends FsaNodeCore implements FsCallbackApi, FsSynchrono return strToEncoding(filename, encoding); } + public readonly readSync: FsSynchronousApi['readSync'] = ( + fd: number, + buffer: Buffer | ArrayBufferView | DataView, + offset: number, + length: number, + position: number, + ): number => { + validateFd(fd); + const filename = this.getFileName(fd); + const adapter = this.getSyncAdapter(); + const uint8 = adapter.call('read', [filename, position, length]); + const dest = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); + dest.set(uint8, offset); + return uint8.length; + }; + public readonly openSync: FsSynchronousApi['openSync'] = notSupported; - public readonly readSync: FsSynchronousApi['readSync'] = notSupported; public readonly writeSync: FsSynchronousApi['writeSync'] = notSupported; public readonly chmodSync: FsSynchronousApi['chmodSync'] = noop; diff --git a/src/fsa-to-node/types.ts b/src/fsa-to-node/types.ts index 90b6d0ebd..817e090d8 100644 --- a/src/fsa-to-node/types.ts +++ b/src/fsa-to-node/types.ts @@ -21,6 +21,11 @@ export interface FsaNodeSyncAdapterApi { trunc(req: [filename: string, len: number]): void; unlink(req: [filename: string]): void; readdir(req: [filename: string]): FsaNodeSyncAdapterEntry[]; + read(req: [ + filename: string, + position: number, + length: number, + ]): Uint8Array; } export interface FsaNodeSyncAdapter { diff --git a/src/fsa-to-node/worker/FsaNodeSyncWorker.ts b/src/fsa-to-node/worker/FsaNodeSyncWorker.ts index b539da9b9..6ba1b99a3 100644 --- a/src/fsa-to-node/worker/FsaNodeSyncWorker.ts +++ b/src/fsa-to-node/worker/FsaNodeSyncWorker.ts @@ -11,10 +11,10 @@ import type { FsaNodeWorkerMsgRootSet, } from './types'; import type { FsLocation, FsaNodeSyncAdapterApi, FsaNodeSyncAdapterStats, FsaNodeSyncAdapterEntry } from '../types'; -import { IDirent } from '../../node/types/misc'; +import type { IDirent } from '../../node/types/misc'; export class FsaNodeSyncWorker { - protected readonly sab: SharedArrayBuffer = new SharedArrayBuffer(1024 * 32); + protected readonly sab: SharedArrayBuffer = new SharedArrayBuffer(1024 * 1024); protected readonly messenger = new SyncMessenger(this.sab); protected root!: fsa.IFileSystemDirectoryHandle; protected fs!: FsaNodeFs; @@ -171,5 +171,17 @@ export class FsaNodeSyncWorker { ); return res; }, + read: async ([filename, position, length]): Promise => { + let uint8 = new Uint8Array(length); + const handle = await this.fs.promises.open(filename, 'r'); + const bytesRead = await new Promise((resolve, reject) => { + this.fs.read(handle.fd, uint8, 0, length, position, (err, bytesRead) => { + if (err) return reject(err); + resolve(bytesRead || length); + }); + }); + if (bytesRead < length) uint8 = uint8.slice(0, bytesRead); + return uint8; + }, }; }