node.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.File = exports.Link = exports.Node = exports.SEP = void 0;
  4. const process_1 = require("./process");
  5. const buffer_1 = require("./internal/buffer");
  6. const constants_1 = require("./constants");
  7. const events_1 = require("events");
  8. const Stats_1 = require("./Stats");
  9. const { S_IFMT, S_IFDIR, S_IFREG, S_IFLNK, S_IFCHR, O_APPEND } = constants_1.constants;
  10. const getuid = () => { var _a, _b; return (_b = (_a = process_1.default.getuid) === null || _a === void 0 ? void 0 : _a.call(process_1.default)) !== null && _b !== void 0 ? _b : 0; };
  11. const getgid = () => { var _a, _b; return (_b = (_a = process_1.default.getgid) === null || _a === void 0 ? void 0 : _a.call(process_1.default)) !== null && _b !== void 0 ? _b : 0; };
  12. exports.SEP = '/';
  13. /**
  14. * Node in a file system (like i-node, v-node).
  15. */
  16. class Node extends events_1.EventEmitter {
  17. constructor(ino, mode = 0o666) {
  18. super();
  19. // User ID and group ID.
  20. this._uid = getuid();
  21. this._gid = getgid();
  22. this._atime = new Date();
  23. this._mtime = new Date();
  24. this._ctime = new Date();
  25. this.rdev = 0;
  26. // Number of hard links pointing at this Node.
  27. this._nlink = 1;
  28. this.mode = mode;
  29. this.ino = ino;
  30. }
  31. set ctime(ctime) {
  32. this._ctime = ctime;
  33. }
  34. get ctime() {
  35. return this._ctime;
  36. }
  37. set uid(uid) {
  38. this._uid = uid;
  39. this.ctime = new Date();
  40. }
  41. get uid() {
  42. return this._uid;
  43. }
  44. set gid(gid) {
  45. this._gid = gid;
  46. this.ctime = new Date();
  47. }
  48. get gid() {
  49. return this._gid;
  50. }
  51. set atime(atime) {
  52. this._atime = atime;
  53. this.ctime = new Date();
  54. }
  55. get atime() {
  56. return this._atime;
  57. }
  58. set mtime(mtime) {
  59. this._mtime = mtime;
  60. this.ctime = new Date();
  61. }
  62. get mtime() {
  63. return this._mtime;
  64. }
  65. get perm() {
  66. return this.mode & ~S_IFMT;
  67. }
  68. set perm(perm) {
  69. this.mode = (this.mode & S_IFMT) | (perm & ~S_IFMT);
  70. this.ctime = new Date();
  71. }
  72. set nlink(nlink) {
  73. this._nlink = nlink;
  74. this.ctime = new Date();
  75. }
  76. get nlink() {
  77. return this._nlink;
  78. }
  79. getString(encoding = 'utf8') {
  80. this.atime = new Date();
  81. return this.getBuffer().toString(encoding);
  82. }
  83. setString(str) {
  84. // this.setBuffer(bufferFrom(str, 'utf8'));
  85. this.buf = (0, buffer_1.bufferFrom)(str, 'utf8');
  86. this.touch();
  87. }
  88. getBuffer() {
  89. this.atime = new Date();
  90. if (!this.buf)
  91. this.setBuffer((0, buffer_1.bufferAllocUnsafe)(0));
  92. return (0, buffer_1.bufferFrom)(this.buf); // Return a copy.
  93. }
  94. setBuffer(buf) {
  95. this.buf = (0, buffer_1.bufferFrom)(buf); // Creates a copy of data.
  96. this.touch();
  97. }
  98. getSize() {
  99. return this.buf ? this.buf.length : 0;
  100. }
  101. setModeProperty(property) {
  102. this.mode = property;
  103. }
  104. isFile() {
  105. return (this.mode & S_IFMT) === S_IFREG;
  106. }
  107. isDirectory() {
  108. return (this.mode & S_IFMT) === S_IFDIR;
  109. }
  110. isSymlink() {
  111. // return !!this.symlink;
  112. return (this.mode & S_IFMT) === S_IFLNK;
  113. }
  114. isCharacterDevice() {
  115. return (this.mode & S_IFMT) === S_IFCHR;
  116. }
  117. makeSymlink(symlink) {
  118. this.mode = S_IFLNK | 0o666;
  119. this.symlink = symlink;
  120. }
  121. write(buf, off = 0, len = buf.length, pos = 0) {
  122. if (!this.buf)
  123. this.buf = (0, buffer_1.bufferAllocUnsafe)(0);
  124. if (pos + len > this.buf.length) {
  125. const newBuf = (0, buffer_1.bufferAllocUnsafe)(pos + len);
  126. this.buf.copy(newBuf, 0, 0, this.buf.length);
  127. this.buf = newBuf;
  128. }
  129. buf.copy(this.buf, pos, off, off + len);
  130. this.touch();
  131. return len;
  132. }
  133. // Returns the number of bytes read.
  134. read(buf, off = 0, len = buf.byteLength, pos = 0) {
  135. this.atime = new Date();
  136. if (!this.buf)
  137. this.buf = (0, buffer_1.bufferAllocUnsafe)(0);
  138. let actualLen = len;
  139. if (actualLen > buf.byteLength) {
  140. actualLen = buf.byteLength;
  141. }
  142. if (actualLen + pos > this.buf.length) {
  143. actualLen = this.buf.length - pos;
  144. }
  145. const buf2 = buf instanceof buffer_1.Buffer ? buf : buffer_1.Buffer.from(buf.buffer);
  146. this.buf.copy(buf2, off, pos, pos + actualLen);
  147. return actualLen;
  148. }
  149. truncate(len = 0) {
  150. if (!len)
  151. this.buf = (0, buffer_1.bufferAllocUnsafe)(0);
  152. else {
  153. if (!this.buf)
  154. this.buf = (0, buffer_1.bufferAllocUnsafe)(0);
  155. if (len <= this.buf.length) {
  156. this.buf = this.buf.slice(0, len);
  157. }
  158. else {
  159. const buf = (0, buffer_1.bufferAllocUnsafe)(len);
  160. this.buf.copy(buf);
  161. buf.fill(0, this.buf.length);
  162. this.buf = buf;
  163. }
  164. }
  165. this.touch();
  166. }
  167. chmod(perm) {
  168. this.mode = (this.mode & S_IFMT) | (perm & ~S_IFMT);
  169. this.touch();
  170. }
  171. chown(uid, gid) {
  172. this.uid = uid;
  173. this.gid = gid;
  174. this.touch();
  175. }
  176. touch() {
  177. this.mtime = new Date();
  178. this.emit('change', this);
  179. }
  180. canRead(uid = getuid(), gid = getgid()) {
  181. if (this.perm & 4 /* S.IROTH */) {
  182. return true;
  183. }
  184. if (gid === this.gid) {
  185. if (this.perm & 32 /* S.IRGRP */) {
  186. return true;
  187. }
  188. }
  189. if (uid === this.uid) {
  190. if (this.perm & 256 /* S.IRUSR */) {
  191. return true;
  192. }
  193. }
  194. return false;
  195. }
  196. canWrite(uid = getuid(), gid = getgid()) {
  197. if (this.perm & 2 /* S.IWOTH */) {
  198. return true;
  199. }
  200. if (gid === this.gid) {
  201. if (this.perm & 16 /* S.IWGRP */) {
  202. return true;
  203. }
  204. }
  205. if (uid === this.uid) {
  206. if (this.perm & 128 /* S.IWUSR */) {
  207. return true;
  208. }
  209. }
  210. return false;
  211. }
  212. canExecute(uid = getuid(), gid = getgid()) {
  213. if (this.perm & 1 /* S.IXOTH */) {
  214. return true;
  215. }
  216. if (gid === this.gid) {
  217. if (this.perm & 8 /* S.IXGRP */) {
  218. return true;
  219. }
  220. }
  221. if (uid === this.uid) {
  222. if (this.perm & 64 /* S.IXUSR */) {
  223. return true;
  224. }
  225. }
  226. return false;
  227. }
  228. del() {
  229. this.emit('delete', this);
  230. }
  231. toJSON() {
  232. return {
  233. ino: this.ino,
  234. uid: this.uid,
  235. gid: this.gid,
  236. atime: this.atime.getTime(),
  237. mtime: this.mtime.getTime(),
  238. ctime: this.ctime.getTime(),
  239. perm: this.perm,
  240. mode: this.mode,
  241. nlink: this.nlink,
  242. symlink: this.symlink,
  243. data: this.getString(),
  244. };
  245. }
  246. }
  247. exports.Node = Node;
  248. /**
  249. * Represents a hard link that points to an i-node `node`.
  250. */
  251. class Link extends events_1.EventEmitter {
  252. get steps() {
  253. return this._steps;
  254. }
  255. // Recursively sync children steps, e.g. in case of dir rename
  256. set steps(val) {
  257. this._steps = val;
  258. for (const [child, link] of this.children.entries()) {
  259. if (child === '.' || child === '..') {
  260. continue;
  261. }
  262. link === null || link === void 0 ? void 0 : link.syncSteps();
  263. }
  264. }
  265. constructor(vol, parent, name) {
  266. super();
  267. this.children = new Map();
  268. // Path to this node as Array: ['usr', 'bin', 'node'].
  269. this._steps = [];
  270. // "i-node" number of the node.
  271. this.ino = 0;
  272. // Number of children.
  273. this.length = 0;
  274. this.vol = vol;
  275. this.parent = parent;
  276. this.name = name;
  277. this.syncSteps();
  278. }
  279. setNode(node) {
  280. this.node = node;
  281. this.ino = node.ino;
  282. }
  283. getNode() {
  284. return this.node;
  285. }
  286. createChild(name, node = this.vol.createNode(S_IFREG | 0o666)) {
  287. const link = new Link(this.vol, this, name);
  288. link.setNode(node);
  289. if (node.isDirectory()) {
  290. link.children.set('.', link);
  291. link.getNode().nlink++;
  292. }
  293. this.setChild(name, link);
  294. return link;
  295. }
  296. setChild(name, link = new Link(this.vol, this, name)) {
  297. this.children.set(name, link);
  298. link.parent = this;
  299. this.length++;
  300. const node = link.getNode();
  301. if (node.isDirectory()) {
  302. link.children.set('..', this);
  303. this.getNode().nlink++;
  304. }
  305. this.getNode().mtime = new Date();
  306. this.emit('child:add', link, this);
  307. return link;
  308. }
  309. deleteChild(link) {
  310. const node = link.getNode();
  311. if (node.isDirectory()) {
  312. link.children.delete('..');
  313. this.getNode().nlink--;
  314. }
  315. this.children.delete(link.getName());
  316. this.length--;
  317. this.getNode().mtime = new Date();
  318. this.emit('child:delete', link, this);
  319. }
  320. getChild(name) {
  321. this.getNode().mtime = new Date();
  322. return this.children.get(name);
  323. }
  324. getPath() {
  325. return this.steps.join(exports.SEP);
  326. }
  327. getParentPath() {
  328. return this.steps.slice(0, -1).join(exports.SEP);
  329. }
  330. getName() {
  331. return this.steps[this.steps.length - 1];
  332. }
  333. // del() {
  334. // const parent = this.parent;
  335. // if(parent) {
  336. // parent.deleteChild(link);
  337. // }
  338. // this.parent = null;
  339. // this.vol = null;
  340. // }
  341. toJSON() {
  342. return {
  343. steps: this.steps,
  344. ino: this.ino,
  345. children: Array.from(this.children.keys()),
  346. };
  347. }
  348. syncSteps() {
  349. this.steps = this.parent ? this.parent.steps.concat([this.name]) : [this.name];
  350. }
  351. }
  352. exports.Link = Link;
  353. /**
  354. * Represents an open file (file descriptor) that points to a `Link` (Hard-link) and a `Node`.
  355. */
  356. class File {
  357. /**
  358. * Open a Link-Node pair. `node` is provided separately as that might be a different node
  359. * rather the one `link` points to, because it might be a symlink.
  360. * @param link
  361. * @param node
  362. * @param flags
  363. * @param fd
  364. */
  365. constructor(link, node, flags, fd) {
  366. this.link = link;
  367. this.node = node;
  368. this.flags = flags;
  369. this.fd = fd;
  370. this.position = 0;
  371. if (this.flags & O_APPEND)
  372. this.position = this.getSize();
  373. }
  374. getString(encoding = 'utf8') {
  375. return this.node.getString();
  376. }
  377. setString(str) {
  378. this.node.setString(str);
  379. }
  380. getBuffer() {
  381. return this.node.getBuffer();
  382. }
  383. setBuffer(buf) {
  384. this.node.setBuffer(buf);
  385. }
  386. getSize() {
  387. return this.node.getSize();
  388. }
  389. truncate(len) {
  390. this.node.truncate(len);
  391. }
  392. seekTo(position) {
  393. this.position = position;
  394. }
  395. stats() {
  396. return Stats_1.default.build(this.node);
  397. }
  398. write(buf, offset = 0, length = buf.length, position) {
  399. if (typeof position !== 'number')
  400. position = this.position;
  401. const bytes = this.node.write(buf, offset, length, position);
  402. this.position = position + bytes;
  403. return bytes;
  404. }
  405. read(buf, offset = 0, length = buf.byteLength, position) {
  406. if (typeof position !== 'number')
  407. position = this.position;
  408. const bytes = this.node.read(buf, offset, length, position);
  409. this.position = position + bytes;
  410. return bytes;
  411. }
  412. chmod(perm) {
  413. this.node.chmod(perm);
  414. }
  415. chown(uid, gid) {
  416. this.node.chown(uid, gid);
  417. }
  418. }
  419. exports.File = File;
  420. //# sourceMappingURL=node.js.map