Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | 2x 2x 2x 2x 2x 6x 6x 6x 6x 6x 6x 7x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 5x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 9x 288x 9x 9x 9x 9x 6x 6x 6x 6x 5x 5x 1x 1x 1x 4x 4x 1x 1x 3x 3x 3x 1x 1x 1x 1x 1x 3x 3x 5x | import type * as misc from 'memfs/lib/node/types/misc';
import type {Nfsv4Client} from './types';
import {NfsFsDirent} from './NfsFsDirent';
import {nfs} from '../builder';
import type * as msg from '../messages';
import {Nfsv4Stat, Nfsv4Attr, Nfsv4FType} from '../constants';
import {Reader} from '@jsonjoy.com/buffers/lib/Reader';
import {XdrDecoder} from '../../../xdr/XdrDecoder';
/**
* Implements Node.js-like Dir interface for NFS v4 directory iteration.
*/
export class NfsFsDir implements misc.IDir {
private entries: NfsFsDirent[] = [];
private position: number = 0;
private closed: boolean = false;
constructor(
public readonly path: string,
private readonly nfs: Nfsv4Client,
private readonly operations: msg.Nfsv4Request[],
) {}
private async ensureLoaded(): Promise<void> {
if (this.entries.length > 0 || this.closed) return;
const attrNums = [Nfsv4Attr.FATTR4_TYPE];
const attrMask: number[] = [];
for (const attrNum of attrNums) {
const wordIndex = Math.floor(attrNum / 32);
const bitIndex = attrNum % 32;
while (attrMask.length <= wordIndex) attrMask.push(0);
attrMask[wordIndex] |= 1 << bitIndex;
}
const operations = [...this.operations];
operations.push(nfs.READDIR(attrMask));
const response = await this.nfs.compound(operations);
Iif (response.status !== Nfsv4Stat.NFS4_OK) throw new Error(`Failed to read directory: ${response.status}`);
const readdirRes = response.resarray[response.resarray.length - 1] as msg.Nfsv4ReaddirResponse;
Iif (readdirRes.status !== Nfsv4Stat.NFS4_OK || !readdirRes.resok)
throw new Error(`Failed to read directory: ${readdirRes.status}`);
const entryList = readdirRes.resok.entries;
for (let i = 0; i < entryList.length; i++) {
const entry = entryList[i];
const name = entry.name;
const fattr = entry.attrs;
const reader = new Reader();
reader.reset(fattr.attrVals);
const xdr = new XdrDecoder(reader);
let fileType = Nfsv4FType.NF4REG;
const returnedMask = fattr.attrmask.mask;
for (let i = 0; i < returnedMask.length; i++) {
const word = returnedMask[i];
Iif (!word) continue;
for (let bit = 0; bit < 32; bit++) {
if (!(word & (1 << bit))) continue;
const attrNum = i * 32 + bit;
if (attrNum === Nfsv4Attr.FATTR4_TYPE) {
fileType = xdr.readUnsignedInt();
}
}
}
this.entries.push(new NfsFsDirent(name, fileType));
}
}
public async close(): Promise<void>;
public async close(callback?: (err?: Error) => void): Promise<void>;
public async close(callback?: (err?: Error) => void): Promise<void> {
this.closed = true;
this.entries = [];
this.position = 0;
Iif (callback) {
try {
callback();
} catch (err) {
callback(err as Error);
}
}
}
public closeSync(): void {
this.closed = true;
this.entries = [];
this.position = 0;
}
public async read(): Promise<misc.IDirent | null>;
public async read(callback?: (err: Error | null, dir?: misc.IDirent | null) => void): Promise<misc.IDirent | null>;
public async read(callback?: (err: Error | null, dir?: misc.IDirent | null) => void): Promise<misc.IDirent | null> {
try {
if (this.closed) {
const err = new Error('Directory is closed');
Iif (callback) {
callback(err, null);
return null;
}
throw err;
}
await this.ensureLoaded();
if (this.position >= this.entries.length) {
Iif (callback) {
callback(null, null);
}
return null;
}
const entry = this.entries[this.position++];
Iif (callback) {
callback(null, entry);
}
return entry;
} catch (err) {
Iif (callback) {
callback(err as Error, null);
return null;
}
throw err;
}
}
public readSync(): misc.IDirent | null {
Iif (this.closed) {
throw new Error('Directory is closed');
}
Iif (this.position >= this.entries.length) {
return null;
}
return this.entries[this.position++];
}
public async *[Symbol.asyncIterator](): AsyncIterableIterator<misc.IDirent> {
await this.ensureLoaded();
for (const entry of this.entries) {
yield entry;
}
}
}
|