Skip to content

Commit

Permalink
Implements read/write
Browse files Browse the repository at this point in the history
  • Loading branch information
arcanis committed Aug 22, 2019
1 parent 5b8c020 commit d18c5f4
Show file tree
Hide file tree
Showing 8 changed files with 304 additions and 24 deletions.
8 changes: 8 additions & 0 deletions packages/berry-fslib/sources/FakeFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,14 @@ export abstract class FakeFS<P extends Path> {
abstract openPromise(p: P, flags: string, mode?: number): Promise<number>;
abstract openSync(p: P, flags: string, mode?: number): number;

abstract readPromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number | null): Promise<number>;
abstract readSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number | null): number;

abstract writePromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<number>;
abstract writePromise(fd: number, buffer: string, position?: number): Promise<number>;
abstract writeSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): number;
abstract writeSync(fd: number, buffer: string, position?: number): number;

abstract closePromise(fd: number): void;
abstract closeSync(fd: number): void;

Expand Down
38 changes: 38 additions & 0 deletions packages/berry-fslib/sources/NodeFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,44 @@ export class NodeFS extends BasePortableFakeFS {
return this.realFs.openSync(NodeFS.fromPortablePath(p), flags, mode);
}

async readPromise(fd: number, buffer: Buffer, offset: number = 0, length: number = 0, position: number | null = -1) {
return await new Promise<number>((resolve, reject) => {
this.realFs.read(fd, buffer, offset, length, position, (error, bytesRead) => {
if (error) {
reject(error);
} else {
resolve(bytesRead);
}
});
});
}

readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number) {
return this.realFs.readSync(fd, buffer, offset, length, position);
}

writePromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<number>;
writePromise(fd: number, buffer: string, position?: number): Promise<number>;
async writePromise(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): Promise<number> {
return await new Promise<number>((resolve, reject) => {
if (typeof buffer === `string`) {
return this.realFs.write(fd, buffer, offset, this.makeCallback(resolve, reject));
} else {
return this.realFs.write(fd, buffer, offset, length, position, this.makeCallback(resolve, reject));
}
});
}

writeSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): number;
writeSync(fd: number, buffer: string, position?: number): number;
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number) {
if (typeof buffer === `string`) {
return this.realFs.writeSync(fd, buffer, offset);
} else {
return this.realFs.writeSync(fd, buffer, offset, length, position);
}
}

async closePromise(fd: number) {
await new Promise<void>((resolve, reject) => {
this.realFs.close(fd, this.makeCallback(resolve, reject));
Expand Down
28 changes: 28 additions & 0 deletions packages/berry-fslib/sources/ProxiedFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ export abstract class ProxiedFS<P extends Path, IP extends Path> extends FakeFS<
return this.baseFs.openSync(this.mapToBase(p), flags, mode);
}

async readPromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number | null) {
return await this.baseFs.readPromise(fd, buffer, offset, length, position);
}

readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number) {
return this.baseFs.readSync(fd, buffer, offset, length, position);
}

writePromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<number>;
writePromise(fd: number, buffer: string, position?: number): Promise<number>;
async writePromise(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): Promise<number> {
if (typeof buffer === `string`) {
return await this.baseFs.writePromise(fd, buffer, offset);
} else {
return await this.baseFs.writePromise(fd, buffer, offset, length, position);
}
}

writeSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): number;
writeSync(fd: number, buffer: string, position?: number): number;
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number) {
if (typeof buffer === `string`) {
return this.baseFs.writeSync(fd, buffer, offset);
} else {
return this.baseFs.writeSync(fd, buffer, offset, length, position);
}
}

closePromise(fd: number) {
return this.baseFs.closePromise(fd);
}
Expand Down
64 changes: 59 additions & 5 deletions packages/berry-fslib/sources/ZipFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,9 @@ export class ZipFS extends BasePortableFakeFS {
private readonly listings: Map<PortablePath, Set<Filename>> = new Map();
private readonly entries: Map<PortablePath, number> = new Map();

private readonly fds: Map<number, {cursor: number, p: PortablePath}> = new Map();
private nextFd: number = 0;

private ready = false;

constructor(p: PortablePath, opts: ZipPathOptions);
Expand Down Expand Up @@ -248,20 +251,71 @@ export class ZipFS extends BasePortableFakeFS {
this.ready = false;
}

async openPromise(p: string, flags: string, mode?: number) {
async openPromise(p: PortablePath, flags: string, mode?: number) {
return this.openSync(p, flags, mode);
}

openSync(p: string, flags: string, mode?: number): never {
openSync(p: PortablePath, flags: string, mode?: number) {
const fd = this.nextFd++;
this.fds.set(fd, {cursor: 0, p});
return fd;
}

async readPromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number | null) {
return this.readSync(fd, buffer, offset, length, position);
}

readSync(fd: number, buffer: Buffer, offset: number = 0, length: number = 0, position: number | null = -1) {
const entry = this.fds.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), {code: `EBADF`});

let realPosition;
if (position === -1 || position === null)
realPosition = entry.cursor;
else
realPosition = position;

const source = this.readFileSync(entry.p);
source.copy(buffer, offset, realPosition, realPosition + length);

const bytesRead = Math.max(0, Math.min(source.length - realPosition, length));
if (position === -1)
entry.cursor += bytesRead;

return bytesRead;
}

writePromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<number>;
writePromise(fd: number, buffer: string, position?: number): Promise<number>;
async writePromise(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): Promise<number> {
if (typeof buffer === `string`) {
return this.writeSync(fd, buffer, position);
} else {
return this.writeSync(fd, buffer, offset, length, position);
}
}

writeSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): number;
writeSync(fd: number, buffer: string, position?: number): number;
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): never {
const entry = this.fds.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), {code: `EBADF`});

throw new Error(`Unimplemented`);
}

async closePromise(fd: number) {
this.closeSync(fd);
return this.closeSync(fd);
}

closeSync(fd: number): never {
throw new Error(`Unimplemented`);
closeSync(fd: number) {
const entry = this.fds.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), {code: `EBADF`});

this.fds.delete(fd);
}

createReadStream(p: PortablePath | null, {encoding}: CreateReadStreamOptions = {}): ReadStream {
Expand Down
115 changes: 109 additions & 6 deletions packages/berry-fslib/sources/ZipOpenFS.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import {NodeFS} f
import {ZipFS} from './ZipFS';
import {FSPath, PortablePath} from './path';

const ZIP_FD = 0x80000000;

export type ZipOpenFSOptions = {
baseFs?: FakeFS<PortablePath>,
filter?: RegExp | null,
Expand Down Expand Up @@ -36,6 +38,9 @@ export class ZipOpenFS extends BasePortableFakeFS {

private readonly zipInstances: Map<string, ZipFS> | null;

private readonly fdMap: Map<number, [ZipFS, number]> = new Map();
private nextFd = 3;

private readonly filter?: RegExp | null;

private isZip: Set<string> = new Set();
Expand Down Expand Up @@ -76,28 +81,126 @@ export class ZipOpenFS extends BasePortableFakeFS {
}
}

private remapFd(zipFs: ZipFS, fd: number) {
const remappedFd = this.nextFd++ | ZIP_FD;
this.fdMap.set(remappedFd, [zipFs, fd]);
return remappedFd;
}

async openPromise(p: PortablePath, flags: string, mode?: number) {
return await this.makeCallPromise(p, async () => {
return await this.baseFs.openPromise(p, flags, mode);
}, async () => {
throw new Error(`Unsupported action (we wouldn't be able to disambiguate the close)`);
}, async (zipFs, {subPath}) => {
return this.remapFd(zipFs, await zipFs.openPromise(subPath, flags, mode));
});
}

openSync(p: PortablePath, flags: string, mode?: number) {
return this.makeCallSync(p, () => {
return this.baseFs.openSync(p, flags, mode);
}, () => {
throw new Error(`Unsupported action (we wouldn't be able to disambiguate the close)`);
}, (zipFs, {subPath}) => {
return this.remapFd(zipFs, zipFs.openSync(subPath, flags, mode));
});
}

async readPromise(fd: number, buffer: Buffer, offset: number, length: number, position: number) {
if ((fd & ZIP_FD) === 0)
return await this.baseFs.readPromise(fd, buffer, offset, length, position);

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), {code: `EBADF`});

const [zipFs, realFd] = entry;
return await zipFs.readPromise(realFd, buffer, offset, length, position);
}

readSync(fd: number, buffer: Buffer, offset: number, length: number, position: number) {
if ((fd & ZIP_FD) === 0)
return this.baseFs.readSync(fd, buffer, offset, length, position);

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, read`), {code: `EBADF`});

const [zipFs, realFd] = entry;
return zipFs.readSync(realFd, buffer, offset, length, position);
}

writePromise(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): Promise<number>;
writePromise(fd: number, buffer: string, position?: number): Promise<number>;
async writePromise(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): Promise<number> {
if ((fd & ZIP_FD) === 0) {
if (typeof buffer === `string`) {
return await this.baseFs.writePromise(fd, buffer, offset);
} else {
return await this.baseFs.writePromise(fd, buffer, offset, length, position);
}
}

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, write`), {code: `EBADF`});

const [zipFs, realFd] = entry;

if (typeof buffer === `string`) {
return await zipFs.writePromise(realFd, buffer, offset);
} else {
return await zipFs.writePromise(realFd, buffer, offset, length, position);
}
}

writeSync(fd: number, buffer: Buffer, offset?: number, length?: number, position?: number): number;
writeSync(fd: number, buffer: string, position?: number): number;
writeSync(fd: number, buffer: Buffer | string, offset?: number, length?: number, position?: number): number {
if ((fd & ZIP_FD) === 0) {
if (typeof buffer === `string`) {
return this.baseFs.writeSync(fd, buffer, offset);
} else {
return this.baseFs.writeSync(fd, buffer, offset, length, position);
}
}

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, write`), {code: `EBADF`});

const [zipFs, realFd] = entry;

if (typeof buffer === `string`) {
return zipFs.writeSync(realFd, buffer, offset);
} else {
return zipFs.writeSync(realFd, buffer, offset, length, position);
}
}

async closePromise(fd: number) {
return await this.baseFs.closePromise(fd);
if ((fd & ZIP_FD) === 0)
return await this.baseFs.closePromise(fd);

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, close`), {code: `EBADF`});

this.fdMap.delete(fd);

const [zipFs, realFd] = entry;
return await zipFs.closePromise(realFd);
}

closeSync(fd: number) {
return this.baseFs.closeSync(fd);
if ((fd & ZIP_FD) === 0)
return this.baseFs.closeSync(fd);

const entry = this.fdMap.get(fd);
if (typeof entry === `undefined`)
throw Object.assign(new Error(`EBADF: bad file descriptor, close`), {code: `EBADF`});

this.fdMap.delete(fd);

const [zipFs, realFd] = entry;
return zipFs.closeSync(realFd);
}

createReadStream(p: PortablePath | null, opts?: CreateReadStreamOptions) {
Expand Down
Loading

0 comments on commit d18c5f4

Please sign in to comment.