NfsFsFileHandle.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.NfsFsFileHandle = void 0;
  4. const events_1 = require("events");
  5. const stream_1 = require("stream");
  6. const builder_1 = require("../builder");
  7. class NfsFsFileHandle extends events_1.EventEmitter {
  8. constructor(fd, path, client, stateid, openOwner) {
  9. super();
  10. this.path = path;
  11. this.client = client;
  12. this.stateid = stateid;
  13. this.openOwner = openOwner;
  14. this.closed = false;
  15. this.fd = fd;
  16. }
  17. getAsyncId() {
  18. return this.fd;
  19. }
  20. async close() {
  21. if (this.closed)
  22. return;
  23. this.closed = true;
  24. await this.client.closeStateid(this.openOwner, this.stateid);
  25. this.emit('close');
  26. }
  27. async stat(options) {
  28. if (this.closed)
  29. throw new Error('File handle is closed');
  30. return this.client.stat(this.path, options);
  31. }
  32. async appendFile(data, options) {
  33. if (this.closed)
  34. throw new Error('File handle is closed');
  35. return this.client.appendFile(this.path, data, options);
  36. }
  37. async chmod(mode) {
  38. if (this.closed)
  39. throw new Error('File handle is closed');
  40. return this.client.chmod(this.path, mode);
  41. }
  42. async chown(uid, gid) {
  43. if (this.closed)
  44. throw new Error('File handle is closed');
  45. return this.client.chown(this.path, uid, gid);
  46. }
  47. async datasync() {
  48. if (this.closed)
  49. throw new Error('File handle is closed');
  50. }
  51. async read(buffer, offset, length, position) {
  52. if (this.closed)
  53. throw new Error('File handle is closed');
  54. const readPos = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
  55. const readOps = [builder_1.nfs.READ(readPos, length, this.stateid)];
  56. const response = await this.client.fs.compound(readOps);
  57. if (response.status !== 0) {
  58. throw new Error(`Failed to read file: ${response.status}`);
  59. }
  60. const readRes = response.resarray[0];
  61. if (readRes.status !== 0 || !readRes.resok) {
  62. throw new Error(`Failed to read file: ${readRes.status}`);
  63. }
  64. const data = readRes.resok.data;
  65. const bytesToCopy = Math.min(data.length, length);
  66. for (let i = 0; i < bytesToCopy; i++) {
  67. buffer[offset + i] = data[i];
  68. }
  69. return { bytesRead: bytesToCopy, buffer };
  70. }
  71. async readFile(options) {
  72. if (this.closed)
  73. throw new Error('File handle is closed');
  74. return this.client.readFile(this.path, options);
  75. }
  76. async truncate(len) {
  77. if (this.closed)
  78. throw new Error('File handle is closed');
  79. return this.client.truncate(this.path, len);
  80. }
  81. async utimes(atime, mtime) {
  82. if (this.closed)
  83. throw new Error('File handle is closed');
  84. return this.client.utimes(this.path, atime, mtime);
  85. }
  86. async write(buffer, offset, length, position) {
  87. if (this.closed)
  88. throw new Error('File handle is closed');
  89. const actualOffset = offset ?? 0;
  90. const actualLength = length ?? buffer.byteLength - actualOffset;
  91. const writePos = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
  92. let data;
  93. if (buffer instanceof Uint8Array) {
  94. data = Uint8Array.prototype.slice.call(buffer, actualOffset, actualOffset + actualLength);
  95. }
  96. else if (Buffer.isBuffer(buffer)) {
  97. data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
  98. }
  99. else if (buffer instanceof DataView) {
  100. data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
  101. }
  102. else {
  103. data = new Uint8Array(buffer.buffer, buffer.byteOffset + actualOffset, actualLength);
  104. }
  105. const writeOps = [builder_1.nfs.WRITE(this.stateid, writePos, 2, data)];
  106. const response = await this.client.fs.compound(writeOps);
  107. if (response.status !== 0) {
  108. throw new Error(`Failed to write file: ${response.status}`);
  109. }
  110. const writeRes = response.resarray[0];
  111. if (writeRes.status !== 0 || !writeRes.resok) {
  112. throw new Error(`Failed to write file: ${writeRes.status}`);
  113. }
  114. const resultBuffer = buffer instanceof Uint8Array || Buffer.isBuffer(buffer) ? buffer : new Uint8Array(buffer.buffer);
  115. return { bytesWritten: writeRes.resok.count, buffer: resultBuffer };
  116. }
  117. async writeFile(data, options) {
  118. if (this.closed)
  119. throw new Error('File handle is closed');
  120. return this.client.writeFile(this.path, data, options);
  121. }
  122. async readv(buffers, position) {
  123. if (this.closed)
  124. throw new Error('File handle is closed');
  125. let currentPosition = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
  126. let totalBytesRead = 0;
  127. for (const buffer of buffers) {
  128. const readOps = [builder_1.nfs.READ(currentPosition, buffer.byteLength, this.stateid)];
  129. const response = await this.client.fs.compound(readOps);
  130. if (response.status !== 0) {
  131. throw new Error(`Failed to read file: ${response.status}`);
  132. }
  133. const readRes = response.resarray[0];
  134. if (readRes.status !== 0 || !readRes.resok) {
  135. throw new Error(`Failed to read file: ${readRes.status}`);
  136. }
  137. const data = readRes.resok.data;
  138. const bytesToCopy = Math.min(data.length, buffer.byteLength);
  139. const uint8View = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  140. for (let i = 0; i < bytesToCopy; i++) {
  141. uint8View[i] = data[i];
  142. }
  143. totalBytesRead += bytesToCopy;
  144. currentPosition += BigInt(bytesToCopy);
  145. if (readRes.resok.eof || bytesToCopy < buffer.byteLength)
  146. break;
  147. }
  148. return { bytesRead: totalBytesRead, buffers };
  149. }
  150. async writev(buffers, position) {
  151. if (this.closed)
  152. throw new Error('File handle is closed');
  153. let currentPosition = position !== null && position !== undefined ? BigInt(position) : BigInt(0);
  154. let totalBytesWritten = 0;
  155. for (const buffer of buffers) {
  156. const data = new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength);
  157. const writeOps = [builder_1.nfs.WRITE(this.stateid, currentPosition, 2, data)];
  158. const response = await this.client.fs.compound(writeOps);
  159. if (response.status !== 0) {
  160. throw new Error(`Failed to write file: ${response.status}`);
  161. }
  162. const writeRes = response.resarray[0];
  163. if (writeRes.status !== 0 || !writeRes.resok) {
  164. throw new Error(`Failed to write file: ${writeRes.status}`);
  165. }
  166. totalBytesWritten += writeRes.resok.count;
  167. currentPosition += BigInt(writeRes.resok.count);
  168. }
  169. return { bytesWritten: totalBytesWritten, buffers };
  170. }
  171. readableWebStream(options) {
  172. if (this.closed)
  173. throw new Error('File handle is closed');
  174. const stream = this.createReadStream(options);
  175. return stream_1.Readable.toWeb(stream);
  176. }
  177. createReadStream(options) {
  178. if (this.closed)
  179. throw new Error('File handle is closed');
  180. const start = options?.start ?? 0;
  181. const end = options?.end;
  182. const highWaterMark = options?.highWaterMark ?? 64 * 1024;
  183. let position = typeof start === 'number' ? start : 0;
  184. const endPosition = typeof end === 'number' ? end : Infinity;
  185. let reading = false;
  186. const self = this;
  187. const stream = new stream_1.Readable({
  188. highWaterMark,
  189. async read(size) {
  190. if (reading)
  191. return;
  192. reading = true;
  193. try {
  194. while (true) {
  195. if (position >= endPosition) {
  196. this.push(null);
  197. break;
  198. }
  199. const bytesToRead = Math.min(size, endPosition - position);
  200. if (bytesToRead <= 0) {
  201. this.push(null);
  202. break;
  203. }
  204. const buffer = Buffer.alloc(bytesToRead);
  205. const result = await self.read(buffer, 0, bytesToRead, position);
  206. if (result.bytesRead === 0) {
  207. this.push(null);
  208. break;
  209. }
  210. position += result.bytesRead;
  211. const chunk = buffer.slice(0, result.bytesRead);
  212. if (!this.push(chunk))
  213. break;
  214. if (result.bytesRead < bytesToRead) {
  215. this.push(null);
  216. break;
  217. }
  218. }
  219. }
  220. catch (err) {
  221. this.destroy(err);
  222. }
  223. finally {
  224. reading = false;
  225. }
  226. },
  227. });
  228. stream.path = this.path;
  229. return stream;
  230. }
  231. createWriteStream(options) {
  232. if (this.closed)
  233. throw new Error('File handle is closed');
  234. const start = options?.start ?? 0;
  235. const highWaterMark = options?.highWaterMark ?? 64 * 1024;
  236. let position = typeof start === 'number' ? start : 0;
  237. const self = this;
  238. const stream = new stream_1.Writable({
  239. highWaterMark,
  240. async write(chunk, encoding, callback) {
  241. try {
  242. const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
  243. const result = await self.write(buffer, 0, buffer.length, position);
  244. position += result.bytesWritten;
  245. callback();
  246. }
  247. catch (err) {
  248. callback(err);
  249. }
  250. },
  251. async writev(chunks, callback) {
  252. try {
  253. const buffers = chunks.map(({ chunk }) => (Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)));
  254. const result = await self.writev(buffers, position);
  255. position += result.bytesWritten;
  256. callback();
  257. }
  258. catch (err) {
  259. callback(err);
  260. }
  261. },
  262. });
  263. stream.path = this.path;
  264. return stream;
  265. }
  266. }
  267. exports.NfsFsFileHandle = NfsFsFileHandle;
  268. //# sourceMappingURL=NfsFsFileHandle.js.map