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 | 66x 66x 66x 66x 4936x 4936x 4936x 4936x 14359x 5721x 5721x 22x 14x 8x 4936x 4936x 4936x 4936x 4936x 4936x 4936x 169551x 3766x 3766x 3766x 1247x 1247x 3766x 3766x 6877x 6877x 6877x 6877x 6877x 3585x 3585x 6877x 6877x 6877x 1104x 1104x 66x 66x 1104x 1104x 1104x 1104x 44857x 44857x 4502x 511x 2397x 4944x | import { EventEmitter } from 'events'; import { constants, PATH } from '../constants'; import type { Node } from './Node'; import type { Superblock } from './Superblock'; const { S_IFREG } = constants; /** * Represents a hard link that points to an i-node `node`. */ export class Link extends EventEmitter { vol: Superblock; parent: Link | undefined; children = new Map<string, Link | undefined>(); // Path to this node as Array: ['usr', 'bin', 'node']. private _steps: string[] = []; // "i-node" of this hard link. node: Node; // "i-node" number of the node. ino: number = 0; // Number of children. length: number = 0; name: string; get steps() { return this._steps; } // Recursively sync children steps, e.g. in case of dir rename set steps(val) { this._steps = val; for (const [child, link] of this.children.entries()) { if (child === '.' || child === '..') { continue; } link?.syncSteps(); } } constructor(vol: Superblock, parent: Link | undefined, name: string) { super(); this.vol = vol; this.parent = parent; this.name = name; this.syncSteps(); } setNode(node: Node) { this.node = node; this.ino = node.ino; } getNode(): Node { return this.node; } createChild(name: string, node: Node = this.vol.createNode(S_IFREG | 0o666)): Link { const link = new Link(this.vol, this, name); link.setNode(node); if (node.isDirectory()) { link.children.set('.', link); link.getNode().nlink++; } this.setChild(name, link); return link; } setChild(name: string, link: Link = new Link(this.vol, this, name)): Link { this.children.set(name, link); link.parent = this; this.length++; const node = link.getNode(); if (node.isDirectory()) { link.children.set('..', this); this.getNode().nlink++; } this.getNode().mtime = new Date(); this.emit('child:add', link, this); return link; } deleteChild(link: Link) { const node = link.getNode(); if (node.isDirectory()) { link.children.delete('..'); this.getNode().nlink--; } this.children.delete(link.getName()); this.length--; this.getNode().mtime = new Date(); this.emit('child:delete', link, this); } getChild(name: string): Link | undefined { this.getNode().mtime = new Date(); return this.children.get(name); } getPath(): string { return this.steps.join(PATH.SEP); } getParentPath(): string { return this.steps.slice(0, -1).join(PATH.SEP); } getName(): string { return this.steps[this.steps.length - 1]; } toJSON() { return { steps: this.steps, ino: this.ino, children: Array.from(this.children.keys()), }; } syncSteps() { this.steps = this.parent ? this.parent.steps.concat([this.name]) : [this.name]; } } |