@jsonjoy.com/json-pack 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/lib/JsonPackMpint.d.ts +8 -0
  2. package/lib/JsonPackMpint.js +74 -0
  3. package/lib/JsonPackMpint.js.map +1 -0
  4. package/lib/json/JsonEncoder.js +9 -3
  5. package/lib/json/JsonEncoder.js.map +1 -1
  6. package/lib/nfs/v4/Nfsv4Decoder.d.ts +14 -10
  7. package/lib/nfs/v4/Nfsv4Decoder.js +156 -74
  8. package/lib/nfs/v4/Nfsv4Decoder.js.map +1 -1
  9. package/lib/nfs/v4/Nfsv4Encoder.d.ts +4 -91
  10. package/lib/nfs/v4/Nfsv4Encoder.js +7 -823
  11. package/lib/nfs/v4/Nfsv4Encoder.js.map +1 -1
  12. package/lib/nfs/v4/Nfsv4FullEncoder.d.ts +32 -0
  13. package/lib/nfs/v4/Nfsv4FullEncoder.js +72 -0
  14. package/lib/nfs/v4/Nfsv4FullEncoder.js.map +1 -0
  15. package/lib/nfs/v4/attributes.d.ts +17 -0
  16. package/lib/nfs/v4/attributes.js +203 -0
  17. package/lib/nfs/v4/attributes.js.map +1 -0
  18. package/lib/nfs/v4/builder.d.ts +60 -0
  19. package/lib/nfs/v4/builder.js +187 -0
  20. package/lib/nfs/v4/builder.js.map +1 -0
  21. package/lib/nfs/v4/client/NfsFsDir.d.ts +20 -0
  22. package/lib/nfs/v4/client/NfsFsDir.js +129 -0
  23. package/lib/nfs/v4/client/NfsFsDir.js.map +1 -0
  24. package/lib/nfs/v4/client/NfsFsDirent.d.ts +14 -0
  25. package/lib/nfs/v4/client/NfsFsDirent.js +32 -0
  26. package/lib/nfs/v4/client/NfsFsDirent.js.map +1 -0
  27. package/lib/nfs/v4/client/NfsFsFileHandle.d.ts +34 -0
  28. package/lib/nfs/v4/client/NfsFsFileHandle.js +268 -0
  29. package/lib/nfs/v4/client/NfsFsFileHandle.js.map +1 -0
  30. package/lib/nfs/v4/client/NfsFsStats.d.ts +31 -0
  31. package/lib/nfs/v4/client/NfsFsStats.js +49 -0
  32. package/lib/nfs/v4/client/NfsFsStats.js.map +1 -0
  33. package/lib/nfs/v4/client/Nfsv4FsClient.d.ts +54 -0
  34. package/lib/nfs/v4/client/Nfsv4FsClient.js +812 -0
  35. package/lib/nfs/v4/client/Nfsv4FsClient.js.map +1 -0
  36. package/lib/nfs/v4/client/Nfsv4TcpClient.d.ts +41 -0
  37. package/lib/nfs/v4/client/Nfsv4TcpClient.js +216 -0
  38. package/lib/nfs/v4/client/Nfsv4TcpClient.js.map +1 -0
  39. package/lib/nfs/v4/client/types.d.ts +9 -0
  40. package/lib/nfs/v4/client/types.js +3 -0
  41. package/lib/nfs/v4/client/types.js.map +1 -0
  42. package/lib/nfs/v4/constants.d.ts +3 -0
  43. package/lib/nfs/v4/constants.js +4 -0
  44. package/lib/nfs/v4/constants.js.map +1 -1
  45. package/lib/nfs/v4/format.d.ts +23 -0
  46. package/lib/nfs/v4/format.js +870 -0
  47. package/lib/nfs/v4/format.js.map +1 -0
  48. package/lib/nfs/v4/index.d.ts +3 -1
  49. package/lib/nfs/v4/index.js +3 -1
  50. package/lib/nfs/v4/index.js.map +1 -1
  51. package/lib/nfs/v4/messages.d.ts +208 -90
  52. package/lib/nfs/v4/messages.js +585 -1
  53. package/lib/nfs/v4/messages.js.map +1 -1
  54. package/lib/nfs/v4/server/Nfsv4CompoundProcCtx.d.ts +11 -0
  55. package/lib/nfs/v4/server/Nfsv4CompoundProcCtx.js +155 -0
  56. package/lib/nfs/v4/server/Nfsv4CompoundProcCtx.js.map +1 -0
  57. package/lib/nfs/v4/server/Nfsv4Connection.d.ts +42 -0
  58. package/lib/nfs/v4/server/Nfsv4Connection.js +160 -0
  59. package/lib/nfs/v4/server/Nfsv4Connection.js.map +1 -0
  60. package/lib/nfs/v4/server/Nfsv4TcpServer.d.ts +26 -0
  61. package/lib/nfs/v4/server/Nfsv4TcpServer.js +91 -0
  62. package/lib/nfs/v4/server/Nfsv4TcpServer.js.map +1 -0
  63. package/lib/nfs/v4/server/operations/ByteRangeLock.d.ts +11 -0
  64. package/lib/nfs/v4/server/operations/ByteRangeLock.js +21 -0
  65. package/lib/nfs/v4/server/operations/ByteRangeLock.js.map +1 -0
  66. package/lib/nfs/v4/server/operations/ClientRecord.d.ts +13 -0
  67. package/lib/nfs/v4/server/operations/ClientRecord.js +17 -0
  68. package/lib/nfs/v4/server/operations/ClientRecord.js.map +1 -0
  69. package/lib/nfs/v4/server/operations/FilesystemStats.d.ts +9 -0
  70. package/lib/nfs/v4/server/operations/FilesystemStats.js +15 -0
  71. package/lib/nfs/v4/server/operations/FilesystemStats.js.map +1 -0
  72. package/lib/nfs/v4/server/operations/LockOwnerState.d.ts +9 -0
  73. package/lib/nfs/v4/server/operations/LockOwnerState.js +15 -0
  74. package/lib/nfs/v4/server/operations/LockOwnerState.js.map +1 -0
  75. package/lib/nfs/v4/server/operations/LockStateid.d.ts +10 -0
  76. package/lib/nfs/v4/server/operations/LockStateid.js +22 -0
  77. package/lib/nfs/v4/server/operations/LockStateid.js.map +1 -0
  78. package/lib/nfs/v4/server/operations/Nfsv4Operations.d.ts +44 -0
  79. package/lib/nfs/v4/server/operations/Nfsv4Operations.js +3 -0
  80. package/lib/nfs/v4/server/operations/Nfsv4Operations.js.map +1 -0
  81. package/lib/nfs/v4/server/operations/Nfsv4OperationsNotImpl.d.ts +42 -0
  82. package/lib/nfs/v4/server/operations/Nfsv4OperationsNotImpl.js +159 -0
  83. package/lib/nfs/v4/server/operations/Nfsv4OperationsNotImpl.js.map +1 -0
  84. package/lib/nfs/v4/server/operations/OpenFileState.d.ts +14 -0
  85. package/lib/nfs/v4/server/operations/OpenFileState.js +17 -0
  86. package/lib/nfs/v4/server/operations/OpenFileState.js.map +1 -0
  87. package/lib/nfs/v4/server/operations/OpenOwnerState.d.ts +9 -0
  88. package/lib/nfs/v4/server/operations/OpenOwnerState.js +15 -0
  89. package/lib/nfs/v4/server/operations/OpenOwnerState.js.map +1 -0
  90. package/lib/nfs/v4/server/operations/node/Nfsv4OperationsNode.d.ts +99 -0
  91. package/lib/nfs/v4/server/operations/node/Nfsv4OperationsNode.js +1400 -0
  92. package/lib/nfs/v4/server/operations/node/Nfsv4OperationsNode.js.map +1 -0
  93. package/lib/nfs/v4/server/operations/node/attrs.d.ts +5 -0
  94. package/lib/nfs/v4/server/operations/node/attrs.js +262 -0
  95. package/lib/nfs/v4/server/operations/node/attrs.js.map +1 -0
  96. package/lib/nfs/v4/server/operations/node/fh.d.ts +28 -0
  97. package/lib/nfs/v4/server/operations/node/fh.js +147 -0
  98. package/lib/nfs/v4/server/operations/node/fh.js.map +1 -0
  99. package/lib/nfs/v4/server/operations/node/util.d.ts +4 -0
  100. package/lib/nfs/v4/server/operations/node/util.js +17 -0
  101. package/lib/nfs/v4/server/operations/node/util.js.map +1 -0
  102. package/lib/nfs/v4/server/types.d.ts +4 -0
  103. package/lib/nfs/v4/server/types.js +3 -0
  104. package/lib/nfs/v4/server/types.js.map +1 -0
  105. package/lib/nfs/v4/server/util.d.ts +6 -0
  106. package/lib/nfs/v4/server/util.js +184 -0
  107. package/lib/nfs/v4/server/util.js.map +1 -0
  108. package/lib/nfs/v4/structs.d.ts +106 -51
  109. package/lib/nfs/v4/structs.js +237 -16
  110. package/lib/nfs/v4/structs.js.map +1 -1
  111. package/lib/rm/RmRecordDecoder.js.map +1 -1
  112. package/lib/rm/RmRecordEncoder.d.ts +2 -0
  113. package/lib/rm/RmRecordEncoder.js +25 -0
  114. package/lib/rm/RmRecordEncoder.js.map +1 -1
  115. package/lib/rpc/RpcMessageDecoder.js +3 -1
  116. package/lib/rpc/RpcMessageDecoder.js.map +1 -1
  117. package/lib/ssh/SshDecoder.d.ts +20 -0
  118. package/lib/ssh/SshDecoder.js +87 -0
  119. package/lib/ssh/SshDecoder.js.map +1 -0
  120. package/lib/ssh/SshEncoder.d.ts +27 -0
  121. package/lib/ssh/SshEncoder.js +144 -0
  122. package/lib/ssh/SshEncoder.js.map +1 -0
  123. package/lib/ssh/index.d.ts +2 -0
  124. package/lib/ssh/index.js +6 -0
  125. package/lib/ssh/index.js.map +1 -0
  126. package/lib/xdr/types.d.ts +6 -0
  127. package/package.json +4 -2
  128. package/lib/nfs/v4/FullNfsv4Encoder.d.ts +0 -28
  129. package/lib/nfs/v4/FullNfsv4Encoder.js +0 -73
  130. package/lib/nfs/v4/FullNfsv4Encoder.js.map +0 -1
@@ -0,0 +1,1400 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Nfsv4OperationsNode = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const NodePath = tslib_1.__importStar(require("node:path"));
6
+ const node_crypto_1 = require("node:crypto");
7
+ const msg = tslib_1.__importStar(require("../../../messages"));
8
+ const struct = tslib_1.__importStar(require("../../../structs"));
9
+ const cmpUint8Array_1 = require("@jsonjoy.com/buffers/lib/cmpUint8Array");
10
+ const ClientRecord_1 = require("../ClientRecord");
11
+ const OpenFileState_1 = require("../OpenFileState");
12
+ const OpenOwnerState_1 = require("../OpenOwnerState");
13
+ const LockOwnerState_1 = require("../LockOwnerState");
14
+ const ByteRangeLock_1 = require("../ByteRangeLock");
15
+ const LockStateid_1 = require("../LockStateid");
16
+ const FilesystemStats_1 = require("../FilesystemStats");
17
+ const fh_1 = require("./fh");
18
+ const util_1 = require("./util");
19
+ const attrs_1 = require("./attrs");
20
+ const attributes_1 = require("../../../attributes");
21
+ const Writer_1 = require("@jsonjoy.com/buffers/lib/Writer");
22
+ const XdrEncoder_1 = require("../../../../../xdr/XdrEncoder");
23
+ const XdrDecoder_1 = require("../../../../../xdr/XdrDecoder");
24
+ class Nfsv4OperationsNode {
25
+ constructor(opts) {
26
+ this.leaseTime = 90;
27
+ this.clients = new Map();
28
+ this.pendingClients = new Map();
29
+ this.nextClientId = 1n;
30
+ this.bootStamp = Math.round(Math.random() * 0xffff);
31
+ this.nextStateidSeqid = 1;
32
+ this.openFiles = new Map();
33
+ this.openOwners = new Map();
34
+ this.locks = new Map();
35
+ this.lockOwners = new Map();
36
+ this.lockStateids = new Map();
37
+ this.changeCounter = 0n;
38
+ this.defaultFsStats = async () => {
39
+ const twoTB = BigInt(2 * 1024 * 1024 * 1024 * 1024);
40
+ const twoM = BigInt(2 * 1000 * 1000);
41
+ return new FilesystemStats_1.FilesystemStats(twoTB, twoTB, twoTB * 2n, twoM, twoM, twoM * 2n);
42
+ };
43
+ this.fs = opts.fs;
44
+ this.promises = this.fs.promises;
45
+ this.dir = opts.dir;
46
+ this.fh = new fh_1.FileHandleMapper(this.bootStamp, this.dir);
47
+ this.maxClients = opts.maxClients ?? 1000;
48
+ this.maxPendingClients = opts.maxPendingClients ?? 1000;
49
+ this.fsStats = opts.fsStats ?? this.defaultFsStats;
50
+ }
51
+ findClientByIdString(map, clientIdString) {
52
+ for (const entry of map.entries())
53
+ if ((0, cmpUint8Array_1.cmpUint8Array)(entry[1].clientIdString, clientIdString))
54
+ return entry;
55
+ return;
56
+ }
57
+ enforceClientLimit() {
58
+ if (this.clients.size <= this.maxClients)
59
+ return;
60
+ const firstKey = this.clients.keys().next().value;
61
+ if (firstKey !== undefined)
62
+ this.clients.delete(firstKey);
63
+ }
64
+ enforcePendingClientLimit() {
65
+ if (this.pendingClients.size < this.maxPendingClients)
66
+ return;
67
+ const firstKey = this.pendingClients.keys().next().value;
68
+ if (firstKey !== undefined)
69
+ this.pendingClients.delete(firstKey);
70
+ }
71
+ makeOpenOwnerKey(clientid, owner) {
72
+ return `${clientid}:${Buffer.from(owner).toString('hex')}`;
73
+ }
74
+ validateSeqid(requestSeqid, ownerSeqid) {
75
+ const nextSeqid = ownerSeqid === 0xffffffff ? 1 : ownerSeqid + 1;
76
+ if (requestSeqid === nextSeqid)
77
+ return 'valid';
78
+ if (requestSeqid === ownerSeqid)
79
+ return 'replay';
80
+ return 'invalid';
81
+ }
82
+ renewClientLease(clientid) {
83
+ const client = this.clients.get(clientid);
84
+ if (client) {
85
+ client.lastRenew = Date.now();
86
+ }
87
+ }
88
+ makeStateidKey(stateid) {
89
+ return `${stateid.seqid}:${Buffer.from(stateid.other).toString('hex')}`;
90
+ }
91
+ createStateid() {
92
+ const seqid = this.nextStateidSeqid++;
93
+ const other = (0, node_crypto_1.randomBytes)(12);
94
+ return new struct.Nfsv4Stateid(seqid, other);
95
+ }
96
+ canAccessFile(path, shareAccess, shareDeny) {
97
+ for (const openFile of this.openFiles.values()) {
98
+ if (openFile.path !== path)
99
+ continue;
100
+ if ((openFile.shareDeny & shareAccess) !== 0)
101
+ return false;
102
+ if ((shareDeny & openFile.shareAccess) !== 0)
103
+ return false;
104
+ }
105
+ return true;
106
+ }
107
+ makeLockOwnerKey(clientid, owner) {
108
+ return `${clientid}:${Buffer.from(owner).toString('hex')}`;
109
+ }
110
+ makeOpenRequestKey(ownerKey, currentPath, request) {
111
+ const writer = new Writer_1.Writer(256);
112
+ const encoder = new XdrEncoder_1.XdrEncoder(writer);
113
+ request.encode(encoder);
114
+ const requestBytes = writer.flush();
115
+ const requestHex = Buffer.from(requestBytes).toString('hex');
116
+ return `OPEN:${ownerKey}:${currentPath}:${requestHex}`;
117
+ }
118
+ makeLockRequestKey(lockOwnerKey, filePath, locktype, offset, length, seqid) {
119
+ return `LOCK:${lockOwnerKey}:${filePath}:${locktype}:${offset.toString()}:${length.toString()}:${seqid}`;
120
+ }
121
+ makeLockuRequestKey(lockOwnerKey, stateid, offset, length, seqid) {
122
+ const stateidKey = this.makeStateidKey(stateid);
123
+ return `LOCKU:${lockOwnerKey}:${stateidKey}:${offset.toString()}:${length.toString()}:${seqid}`;
124
+ }
125
+ makeLockKey(stateid, offset, length) {
126
+ return `${this.makeStateidKey(stateid)}:${offset}:${length}`;
127
+ }
128
+ makeLockStateidKey(lockOwnerKey, path) {
129
+ return `${lockOwnerKey}:${path}`;
130
+ }
131
+ getOrCreateLockStateid(lockOwnerKey, path) {
132
+ const key = this.makeLockStateidKey(lockOwnerKey, path);
133
+ let lockStateid = this.lockStateids.get(key);
134
+ if (!lockStateid) {
135
+ const other = (0, node_crypto_1.randomBytes)(12);
136
+ lockStateid = new LockStateid_1.LockStateid(other, 1, lockOwnerKey, path);
137
+ this.lockStateids.set(key, lockStateid);
138
+ const otherKey = Buffer.from(other).toString('hex');
139
+ this.lockStateids.set(otherKey, lockStateid);
140
+ }
141
+ return lockStateid;
142
+ }
143
+ findLockStateidByOther(other) {
144
+ const otherKey = Buffer.from(other).toString('hex');
145
+ return this.lockStateids.get(otherKey);
146
+ }
147
+ hasConflictingLock(path, locktype, offset, length, ownerKey) {
148
+ const isWriteLock = locktype === 2;
149
+ for (const lock of this.locks.values()) {
150
+ if (lock.path !== path)
151
+ continue;
152
+ if (!lock.overlaps(offset, length))
153
+ continue;
154
+ if (lock.lockOwnerKey === ownerKey)
155
+ continue;
156
+ if (isWriteLock || lock.locktype === 2)
157
+ return true;
158
+ }
159
+ return false;
160
+ }
161
+ async SETCLIENTID(request, ctx) {
162
+ const principal = ctx.getPrincipal();
163
+ const verifier = request.client.verifier.data;
164
+ const clientIdString = request.client.id;
165
+ const callback = request.callback;
166
+ const callbackIdent = request.callbackIdent;
167
+ const confirmedClientEntry = this.findClientByIdString(this.clients, clientIdString);
168
+ let clientid = 0n;
169
+ if (confirmedClientEntry) {
170
+ const existingRecord = confirmedClientEntry[1];
171
+ if (existingRecord.principal !== principal)
172
+ return new msg.Nfsv4SetclientidResponse(10017);
173
+ this.pendingClients.delete(clientid);
174
+ clientid = confirmedClientEntry[0];
175
+ const verifierMatch = (0, cmpUint8Array_1.cmpUint8Array)(existingRecord.verifier, verifier);
176
+ if (verifierMatch) {
177
+ }
178
+ else {
179
+ clientid = this.nextClientId++;
180
+ }
181
+ }
182
+ else {
183
+ const pendingClientEntry = this.findClientByIdString(this.pendingClients, clientIdString);
184
+ if (pendingClientEntry) {
185
+ const existingRecord = pendingClientEntry[1];
186
+ if (existingRecord.principal !== principal)
187
+ return new msg.Nfsv4SetclientidResponse(10017);
188
+ const verifierMatch = (0, cmpUint8Array_1.cmpUint8Array)(existingRecord.verifier, verifier);
189
+ if (verifierMatch && existingRecord.cache) {
190
+ return existingRecord.cache;
191
+ }
192
+ }
193
+ clientid = this.nextClientId++;
194
+ }
195
+ const setclientidConfirm = (0, node_crypto_1.randomBytes)(8);
196
+ const verifierStruct = new struct.Nfsv4Verifier(setclientidConfirm);
197
+ const body = new msg.Nfsv4SetclientidResOk(clientid, verifierStruct);
198
+ const response = new msg.Nfsv4SetclientidResponse(0, body);
199
+ const newRecord = new ClientRecord_1.ClientRecord(principal, verifier, clientIdString, callback, callbackIdent, setclientidConfirm, response);
200
+ for (const [id, entry] of this.pendingClients.entries())
201
+ if ((0, cmpUint8Array_1.cmpUint8Array)(entry.clientIdString, clientIdString))
202
+ this.pendingClients.delete(id);
203
+ this.enforcePendingClientLimit();
204
+ this.pendingClients.set(clientid, newRecord);
205
+ return response;
206
+ }
207
+ async SETCLIENTID_CONFIRM(request, ctx) {
208
+ const { clients, pendingClients } = this;
209
+ const clientid = request.clientid;
210
+ const setclientidConfirm = request.setclientidConfirm.data;
211
+ const pendingRecord = pendingClients.get(clientid);
212
+ if (!pendingRecord) {
213
+ const confirmedRecord = this.clients.get(clientid);
214
+ if (confirmedRecord && (0, cmpUint8Array_1.cmpUint8Array)(confirmedRecord.setclientidConfirm, setclientidConfirm))
215
+ return new msg.Nfsv4SetclientidConfirmResponse(0);
216
+ return new msg.Nfsv4SetclientidConfirmResponse(10022);
217
+ }
218
+ const principal = ctx.getPrincipal();
219
+ if (pendingRecord.principal !== principal)
220
+ return new msg.Nfsv4SetclientidConfirmResponse(10017);
221
+ if (!(0, cmpUint8Array_1.cmpUint8Array)(pendingRecord.setclientidConfirm, setclientidConfirm))
222
+ return new msg.Nfsv4SetclientidConfirmResponse(10022);
223
+ const oldConfirmed = this.findClientByIdString(this.clients, pendingRecord.clientIdString);
224
+ if (oldConfirmed) {
225
+ const clientid2 = oldConfirmed[0];
226
+ this.clients.delete(clientid2);
227
+ pendingClients.delete(clientid2);
228
+ }
229
+ this.clients.delete(clientid);
230
+ pendingClients.delete(clientid);
231
+ const clientIdString = pendingRecord.clientIdString;
232
+ for (const [id, entry] of pendingClients.entries())
233
+ if ((0, cmpUint8Array_1.cmpUint8Array)(entry.clientIdString, clientIdString))
234
+ pendingClients.delete(id);
235
+ for (const [id, entry] of clients.entries())
236
+ if ((0, cmpUint8Array_1.cmpUint8Array)(entry.clientIdString, clientIdString))
237
+ clients.delete(id);
238
+ this.enforceClientLimit();
239
+ clients.set(clientid, pendingRecord);
240
+ return new msg.Nfsv4SetclientidConfirmResponse(0);
241
+ }
242
+ async ILLEGAL(request, ctx) {
243
+ ctx.connection.logger.log('ILLEGAL', request);
244
+ return new msg.Nfsv4IllegalResponse(10044);
245
+ }
246
+ async PUTROOTFH(request, ctx) {
247
+ ctx.cfh = fh_1.ROOT_FH;
248
+ return new msg.Nfsv4PutrootfhResponse(0);
249
+ }
250
+ async PUTPUBFH(request, ctx) {
251
+ ctx.cfh = fh_1.ROOT_FH;
252
+ return new msg.Nfsv4PutpubfhResponse(0);
253
+ }
254
+ async PUTFH(request, ctx) {
255
+ const fh = request.object.data;
256
+ if (fh.length > 128)
257
+ throw 10001;
258
+ const valid = this.fh.validate(fh);
259
+ if (!valid)
260
+ throw 10001;
261
+ ctx.cfh = fh;
262
+ return new msg.Nfsv4PutfhResponse(0);
263
+ }
264
+ async GETFH(request, ctx) {
265
+ const cfh = ctx.cfh;
266
+ if (!cfh)
267
+ throw 10020;
268
+ const fh = new struct.Nfsv4Fh(cfh);
269
+ const body = new msg.Nfsv4GetfhResOk(fh);
270
+ return new msg.Nfsv4GetfhResponse(0, body);
271
+ }
272
+ async RESTOREFH(request, ctx) {
273
+ if (!ctx.sfh)
274
+ throw 10030;
275
+ ctx.cfh = ctx.sfh;
276
+ return new msg.Nfsv4RestorefhResponse(0);
277
+ }
278
+ async SAVEFH(request, ctx) {
279
+ if (!ctx.cfh)
280
+ throw 10020;
281
+ ctx.sfh = ctx.cfh;
282
+ return new msg.Nfsv4SavefhResponse(0);
283
+ }
284
+ absolutePath(path) {
285
+ const dir = this.dir;
286
+ if (path === dir)
287
+ return dir;
288
+ if (path.startsWith(dir + NodePath.sep) || path.startsWith(dir + '/'))
289
+ return path;
290
+ const absolutePath = NodePath.join(dir, path);
291
+ if (absolutePath.length < dir.length)
292
+ throw 2;
293
+ if (!absolutePath.startsWith(dir))
294
+ throw 2;
295
+ return absolutePath;
296
+ }
297
+ async LOOKUP(request, ctx) {
298
+ const fh = this.fh;
299
+ const currentPath = fh.currentPath(ctx);
300
+ const currentPathAbsolute = this.absolutePath(currentPath);
301
+ const component = request.objname;
302
+ if (component.length === 0)
303
+ throw 22;
304
+ const promises = this.promises;
305
+ let stats;
306
+ try {
307
+ stats = await promises.stat(currentPathAbsolute);
308
+ }
309
+ catch (err) {
310
+ if ((0, util_1.isErrCode)('ENOENT', err))
311
+ throw 2;
312
+ throw 5;
313
+ }
314
+ if (stats.isSymbolicLink())
315
+ throw 10029;
316
+ if (!stats.isDirectory())
317
+ throw 20;
318
+ const targetAbsolutePath = NodePath.join(currentPathAbsolute, component);
319
+ try {
320
+ const targetStats = await promises.stat(targetAbsolutePath);
321
+ if (!targetStats)
322
+ throw 2;
323
+ }
324
+ catch (err) {
325
+ if ((0, util_1.isErrCode)('ENOENT', err))
326
+ throw 2;
327
+ if ((0, util_1.isErrCode)('EACCES', err))
328
+ throw 13;
329
+ throw 5;
330
+ }
331
+ fh.setCfh(ctx, targetAbsolutePath);
332
+ return new msg.Nfsv4LookupResponse(0);
333
+ }
334
+ async LOOKUPP(request, ctx) {
335
+ const fh = this.fh;
336
+ const currentPath = fh.currentPath(ctx);
337
+ const currentPathAbsolute = this.absolutePath(currentPath);
338
+ const promises = this.promises;
339
+ let stats;
340
+ try {
341
+ stats = await promises.stat(currentPathAbsolute);
342
+ }
343
+ catch (err) {
344
+ if ((0, util_1.isErrCode)('ENOENT', err))
345
+ throw 2;
346
+ throw 5;
347
+ }
348
+ if (!stats.isDirectory())
349
+ throw 20;
350
+ const parentAbsolutePath = NodePath.dirname(currentPathAbsolute);
351
+ if (parentAbsolutePath.length < this.dir.length)
352
+ throw 2;
353
+ fh.setCfh(ctx, parentAbsolutePath);
354
+ return new msg.Nfsv4LookuppResponse(0);
355
+ }
356
+ async GETATTR(request, ctx) {
357
+ const currentPath = this.fh.currentPath(ctx);
358
+ const currentPathAbsolute = this.absolutePath(currentPath);
359
+ const requestedAttrNums = (0, attributes_1.parseBitmask)(request.attrRequest.mask);
360
+ let stats;
361
+ if ((0, attributes_1.requiresLstat)(requestedAttrNums)) {
362
+ try {
363
+ if (ctx.connection.debug)
364
+ ctx.connection.logger.log('lstat', currentPathAbsolute);
365
+ stats = await this.promises.lstat(currentPathAbsolute);
366
+ }
367
+ catch (error) {
368
+ throw (0, util_1.normalizeNodeFsError)(error, ctx.connection.logger);
369
+ }
370
+ }
371
+ let fsStats;
372
+ if ((0, attributes_1.requiresFsStats)(requestedAttrNums)) {
373
+ try {
374
+ fsStats = await this.fsStats();
375
+ }
376
+ catch (error) {
377
+ ctx.connection.logger.error(error);
378
+ }
379
+ }
380
+ const attrs = (0, attrs_1.encodeAttrs)(request.attrRequest, stats, currentPath, ctx.cfh, this.leaseTime, fsStats);
381
+ return new msg.Nfsv4GetattrResponse(0, new msg.Nfsv4GetattrResOk(attrs));
382
+ }
383
+ async ACCESS(request, ctx) {
384
+ const currentPath = this.fh.currentPath(ctx);
385
+ const currentPathAbsolute = this.absolutePath(currentPath);
386
+ const promises = this.promises;
387
+ let stats;
388
+ try {
389
+ stats = await promises.lstat(currentPathAbsolute);
390
+ }
391
+ catch (error) {
392
+ throw (0, util_1.normalizeNodeFsError)(error, ctx.connection.logger);
393
+ }
394
+ const requestedAccess = request.access;
395
+ const isDirectory = stats.isDirectory();
396
+ const mode = stats.mode;
397
+ let supported = 0;
398
+ let access = 0;
399
+ if (requestedAccess & 1) {
400
+ supported |= 1;
401
+ if (mode & 0o444)
402
+ access |= 1;
403
+ }
404
+ if (requestedAccess & 2) {
405
+ supported |= 2;
406
+ if (isDirectory && mode & 0o111)
407
+ access |= 2;
408
+ }
409
+ if (requestedAccess & 4) {
410
+ supported |= 4;
411
+ if (mode & 0o222)
412
+ access |= 4;
413
+ }
414
+ if (requestedAccess & 8) {
415
+ supported |= 8;
416
+ if (mode & 0o222)
417
+ access |= 8;
418
+ }
419
+ if (requestedAccess & 16) {
420
+ if (!isDirectory) {
421
+ supported |= 0;
422
+ }
423
+ else {
424
+ supported |= 16;
425
+ if (mode & 0o222)
426
+ access |= 16;
427
+ }
428
+ }
429
+ if (requestedAccess & 32) {
430
+ supported |= 32;
431
+ if (!isDirectory && mode & 0o111)
432
+ access |= 32;
433
+ }
434
+ const body = new msg.Nfsv4AccessResOk(supported, access);
435
+ return new msg.Nfsv4AccessResponse(0, body);
436
+ }
437
+ async READDIR(request, ctx) {
438
+ const fh = this.fh;
439
+ const currentPath = fh.currentPath(ctx);
440
+ const currentPathAbsolute = this.absolutePath(currentPath);
441
+ const promises = this.promises;
442
+ let stats;
443
+ try {
444
+ stats = await promises.lstat(currentPathAbsolute);
445
+ }
446
+ catch (error) {
447
+ throw (0, util_1.normalizeNodeFsError)(error, ctx.connection.logger);
448
+ }
449
+ if (!stats.isDirectory())
450
+ throw 20;
451
+ const cookie = request.cookie;
452
+ const requestedCookieverf = request.cookieverf.data;
453
+ const maxcount = request.maxcount;
454
+ const attrRequest = request.attrRequest;
455
+ let cookieverf;
456
+ if (cookie === 0n) {
457
+ cookieverf = new Uint8Array(8);
458
+ const changeTime = BigInt(Math.floor(stats.mtimeMs * 1000000));
459
+ const view = new DataView(cookieverf.buffer);
460
+ view.setBigUint64(0, changeTime, false);
461
+ }
462
+ else {
463
+ cookieverf = new Uint8Array(8);
464
+ const changeTime = BigInt(Math.floor(stats.mtimeMs * 1000000));
465
+ const view = new DataView(cookieverf.buffer);
466
+ view.setBigUint64(0, changeTime, false);
467
+ if (!(0, cmpUint8Array_1.cmpUint8Array)(requestedCookieverf, cookieverf))
468
+ throw 10027;
469
+ }
470
+ let dirents;
471
+ try {
472
+ dirents = await promises.readdir(currentPathAbsolute, { withFileTypes: true });
473
+ }
474
+ catch (error) {
475
+ throw (0, util_1.normalizeNodeFsError)(error, ctx.connection.logger);
476
+ }
477
+ const entries = [];
478
+ let totalBytes = 0;
479
+ const overheadPerEntry = 32;
480
+ let startIndex = 0;
481
+ if (cookie > 0n) {
482
+ startIndex = Number(cookie) - 2;
483
+ if (startIndex < 0)
484
+ startIndex = 0;
485
+ if (startIndex > dirents.length)
486
+ startIndex = dirents.length;
487
+ }
488
+ let eof = true;
489
+ const fsStats = await this.fsStats();
490
+ for (let i = startIndex; i < dirents.length; i++) {
491
+ const dirent = dirents[i];
492
+ const name = dirent.name;
493
+ const entryCookie = BigInt(i + 3);
494
+ const entryPath = NodePath.join(currentPathAbsolute, name);
495
+ let entryStats;
496
+ try {
497
+ entryStats = await promises.lstat(entryPath);
498
+ }
499
+ catch (error) {
500
+ continue;
501
+ }
502
+ const entryFh = fh.encode(entryPath);
503
+ const attrs = (0, attrs_1.encodeAttrs)(attrRequest, entryStats, entryPath, entryFh, this.leaseTime, fsStats);
504
+ const nameBytes = Buffer.byteLength(name, 'utf8');
505
+ const attrBytes = attrs.attrVals.length;
506
+ const entryBytes = overheadPerEntry + nameBytes + attrBytes;
507
+ if (totalBytes + entryBytes > maxcount && entries.length > 0) {
508
+ eof = false;
509
+ break;
510
+ }
511
+ const entry = new struct.Nfsv4Entry(entryCookie, name, attrs);
512
+ entries.push(entry);
513
+ totalBytes += entryBytes;
514
+ }
515
+ const cookieverf2 = new struct.Nfsv4Verifier(cookieverf);
516
+ const body = new msg.Nfsv4ReaddirResOk(cookieverf2, entries, eof);
517
+ return new msg.Nfsv4ReaddirResponse(0, body);
518
+ }
519
+ async OPEN(request, ctx) {
520
+ const currentPath = this.fh.currentPath(ctx);
521
+ const currentPathAbsolute = this.absolutePath(currentPath);
522
+ const ownerKey = this.makeOpenOwnerKey(request.owner.clientid, request.owner.owner);
523
+ this.renewClientLease(request.owner.clientid);
524
+ let ownerState = this.openOwners.get(ownerKey);
525
+ let replayCandidate = false;
526
+ let previousSeqid = ownerState?.seqid ?? 0;
527
+ if (!ownerState) {
528
+ ownerState = new OpenOwnerState_1.OpenOwnerState(request.owner.clientid, request.owner.owner, 0);
529
+ this.openOwners.set(ownerKey, ownerState);
530
+ previousSeqid = 0;
531
+ }
532
+ else {
533
+ const seqidValidation = this.validateSeqid(request.seqid, ownerState.seqid);
534
+ if (seqidValidation === 'invalid') {
535
+ if (request.seqid === 0) {
536
+ ownerState.seqid = 0;
537
+ previousSeqid = 0;
538
+ }
539
+ else {
540
+ return new msg.Nfsv4OpenResponse(10026);
541
+ }
542
+ }
543
+ else if (seqidValidation === 'replay') {
544
+ replayCandidate = true;
545
+ }
546
+ }
547
+ if (request.claim.claimType !== 0) {
548
+ return new msg.Nfsv4OpenResponse(10004);
549
+ }
550
+ const claimNull = request.claim.claim;
551
+ const filename = claimNull.file;
552
+ const filePath = NodePath.join(currentPathAbsolute, filename);
553
+ const requestKey = this.makeOpenRequestKey(ownerKey, filePath, request);
554
+ if (replayCandidate) {
555
+ if (ownerState.lastRequestKey === requestKey && ownerState.lastResponse) {
556
+ return ownerState.lastResponse;
557
+ }
558
+ return new msg.Nfsv4OpenResponse(10026);
559
+ }
560
+ ownerState.seqid = request.seqid;
561
+ const opentype = request.openhow.opentype;
562
+ const isCreate = opentype === 1;
563
+ let fileExists = false;
564
+ try {
565
+ const stats = await this.promises.lstat(filePath);
566
+ if (!stats.isFile()) {
567
+ const response = new msg.Nfsv4OpenResponse(21);
568
+ ownerState.lastResponse = response;
569
+ ownerState.lastRequestKey = requestKey;
570
+ return response;
571
+ }
572
+ fileExists = true;
573
+ }
574
+ catch (err) {
575
+ if ((0, util_1.isErrCode)('ENOENT', err)) {
576
+ if (!isCreate) {
577
+ const response = new msg.Nfsv4OpenResponse(2);
578
+ ownerState.lastResponse = response;
579
+ ownerState.lastRequestKey = requestKey;
580
+ return response;
581
+ }
582
+ }
583
+ else {
584
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
585
+ const response = new msg.Nfsv4OpenResponse(status);
586
+ ownerState.lastResponse = response;
587
+ ownerState.lastRequestKey = requestKey;
588
+ return response;
589
+ }
590
+ }
591
+ if (fileExists && !this.canAccessFile(filePath, request.shareAccess, request.shareDeny)) {
592
+ ownerState.seqid = previousSeqid;
593
+ const response = new msg.Nfsv4OpenResponse(10015);
594
+ ownerState.lastResponse = response;
595
+ ownerState.lastRequestKey = requestKey;
596
+ return response;
597
+ }
598
+ let flags = 0;
599
+ const isWrite = (request.shareAccess & 2) !== 0;
600
+ const isRead = (request.shareAccess & 1) !== 0;
601
+ if (isCreate) {
602
+ flags = this.fs.constants.O_CREAT;
603
+ const createHow = request.openhow.how;
604
+ if (createHow && createHow.mode === 2) {
605
+ flags |= this.fs.constants.O_EXCL;
606
+ }
607
+ }
608
+ if (isRead && isWrite) {
609
+ flags |= this.fs.constants.O_RDWR;
610
+ }
611
+ else if (isWrite) {
612
+ flags |= this.fs.constants.O_WRONLY;
613
+ }
614
+ else {
615
+ flags |= this.fs.constants.O_RDONLY;
616
+ }
617
+ try {
618
+ const fd = await this.promises.open(filePath, flags, 0o644);
619
+ const stateid = this.createStateid();
620
+ const stateidKey = this.makeStateidKey(stateid);
621
+ const openFile = new OpenFileState_1.OpenFileState(stateid, filePath, fd, request.shareAccess, request.shareDeny, ownerKey, ownerState.seqid, false);
622
+ this.openFiles.set(stateidKey, openFile);
623
+ ownerState.opens.add(stateidKey);
624
+ const fh = this.fh.encode(filePath);
625
+ ctx.cfh = fh;
626
+ const before = this.changeCounter;
627
+ const after = ++this.changeCounter;
628
+ const cinfo = new struct.Nfsv4ChangeInfo(true, before, after);
629
+ const attrset = new struct.Nfsv4Bitmap([]);
630
+ const delegation = new struct.Nfsv4OpenDelegation(0);
631
+ const resok = new msg.Nfsv4OpenResOk(stateid, cinfo, 0, attrset, delegation);
632
+ const response = new msg.Nfsv4OpenResponse(0, resok);
633
+ ownerState.lastResponse = response;
634
+ ownerState.lastRequestKey = requestKey;
635
+ return response;
636
+ }
637
+ catch (err) {
638
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
639
+ const response = new msg.Nfsv4OpenResponse(status);
640
+ ownerState.lastResponse = response;
641
+ ownerState.lastRequestKey = requestKey;
642
+ return response;
643
+ }
644
+ }
645
+ async OPENATTR(request, ctx) {
646
+ return new msg.Nfsv4OpenattrResponse(10004);
647
+ }
648
+ async OPEN_CONFIRM(request, ctx) {
649
+ const stateidKey = this.makeStateidKey(request.openStateid);
650
+ const openFile = this.openFiles.get(stateidKey);
651
+ if (!openFile)
652
+ throw 10025;
653
+ const ownerState = this.openOwners.get(openFile.openOwnerKey);
654
+ if (!ownerState)
655
+ throw 10025;
656
+ const seqidValidation = this.validateSeqid(request.seqid, ownerState.seqid);
657
+ if (seqidValidation === 'invalid')
658
+ throw 10026;
659
+ if (seqidValidation === 'replay') {
660
+ const newStateid = new struct.Nfsv4Stateid(openFile.stateid.seqid, openFile.stateid.other);
661
+ const resok = new msg.Nfsv4OpenConfirmResOk(newStateid);
662
+ return new msg.Nfsv4OpenConfirmResponse(0, resok);
663
+ }
664
+ ownerState.seqid = request.seqid;
665
+ openFile.confirmed = true;
666
+ const newSeqid = this.nextStateidSeqid++;
667
+ const newStateid = new struct.Nfsv4Stateid(newSeqid, openFile.stateid.other);
668
+ const oldKey = stateidKey;
669
+ const newKey = this.makeStateidKey(newStateid);
670
+ const updatedOpenFile = new OpenFileState_1.OpenFileState(newStateid, openFile.path, openFile.fd, openFile.shareAccess, openFile.shareDeny, openFile.openOwnerKey, ownerState.seqid, true);
671
+ this.openFiles.delete(oldKey);
672
+ this.openFiles.set(newKey, updatedOpenFile);
673
+ ownerState.opens.delete(oldKey);
674
+ ownerState.opens.add(newKey);
675
+ const resok = new msg.Nfsv4OpenConfirmResOk(newStateid);
676
+ return new msg.Nfsv4OpenConfirmResponse(0, resok);
677
+ }
678
+ async OPEN_DOWNGRADE(request, ctx) {
679
+ const stateidKey = this.makeStateidKey(request.openStateid);
680
+ const openFile = this.openFiles.get(stateidKey);
681
+ if (!openFile)
682
+ throw 10025;
683
+ const ownerState = this.openOwners.get(openFile.openOwnerKey);
684
+ if (!ownerState)
685
+ throw 10025;
686
+ const seqidValidation = this.validateSeqid(request.seqid, ownerState.seqid);
687
+ if (seqidValidation === 'invalid')
688
+ throw 10026;
689
+ if (seqidValidation === 'replay') {
690
+ const newStateid = new struct.Nfsv4Stateid(openFile.stateid.seqid, openFile.stateid.other);
691
+ const resok = new msg.Nfsv4OpenDowngradeResOk(newStateid);
692
+ return new msg.Nfsv4OpenDowngradeResponse(0, resok);
693
+ }
694
+ ownerState.seqid = request.seqid;
695
+ if ((request.shareAccess & ~openFile.shareAccess) !== 0)
696
+ throw 22;
697
+ if ((request.shareDeny & ~openFile.shareDeny) !== 0)
698
+ throw 22;
699
+ const newSeqid = this.nextStateidSeqid++;
700
+ const newStateid = new struct.Nfsv4Stateid(newSeqid, openFile.stateid.other);
701
+ const oldKey = stateidKey;
702
+ const newKey = this.makeStateidKey(newStateid);
703
+ const updatedOpenFile = new OpenFileState_1.OpenFileState(newStateid, openFile.path, openFile.fd, request.shareAccess, request.shareDeny, openFile.openOwnerKey, ownerState.seqid, openFile.confirmed);
704
+ this.openFiles.delete(oldKey);
705
+ this.openFiles.set(newKey, updatedOpenFile);
706
+ ownerState.opens.delete(oldKey);
707
+ ownerState.opens.add(newKey);
708
+ const resok = new msg.Nfsv4OpenDowngradeResOk(newStateid);
709
+ return new msg.Nfsv4OpenDowngradeResponse(0, resok);
710
+ }
711
+ async CLOSE(request, ctx) {
712
+ const stateidKey = this.makeStateidKey(request.openStateid);
713
+ const openFile = this.openFiles.get(stateidKey);
714
+ if (!openFile) {
715
+ return new msg.Nfsv4CloseResponse(0, new msg.Nfsv4CloseResOk(request.openStateid));
716
+ }
717
+ const ownerState = this.openOwners.get(openFile.openOwnerKey);
718
+ if (!ownerState) {
719
+ return new msg.Nfsv4CloseResponse(10025);
720
+ }
721
+ this.renewClientLease(ownerState.clientid);
722
+ const seqidValidation = this.validateSeqid(request.seqid, ownerState.seqid);
723
+ if (seqidValidation === 'invalid') {
724
+ return new msg.Nfsv4CloseResponse(10026);
725
+ }
726
+ if (seqidValidation === 'replay') {
727
+ const newStateid = new struct.Nfsv4Stateid(openFile.stateid.seqid, openFile.stateid.other);
728
+ const resok = new msg.Nfsv4CloseResOk(newStateid);
729
+ return new msg.Nfsv4CloseResponse(0, resok);
730
+ }
731
+ ownerState.seqid = request.seqid;
732
+ try {
733
+ const handle = openFile.fd;
734
+ if (handle && typeof handle.close === 'function') {
735
+ await handle.close();
736
+ }
737
+ }
738
+ catch (err) {
739
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
740
+ if (status !== 2) {
741
+ return new msg.Nfsv4CloseResponse(status);
742
+ }
743
+ }
744
+ ownerState.opens.delete(stateidKey);
745
+ if (ownerState.opens.size === 0) {
746
+ this.openOwners.delete(openFile.openOwnerKey);
747
+ }
748
+ this.openFiles.delete(stateidKey);
749
+ const newSeqid = this.nextStateidSeqid++;
750
+ const newStateid = new struct.Nfsv4Stateid(newSeqid, openFile.stateid.other);
751
+ const resok = new msg.Nfsv4CloseResOk(newStateid);
752
+ return new msg.Nfsv4CloseResponse(0, resok);
753
+ }
754
+ async SECINFO(request, ctx) {
755
+ const currentPath = this.fh.currentPath(ctx);
756
+ const currentPathAbsolute = this.absolutePath(currentPath);
757
+ const filePath = NodePath.join(currentPathAbsolute, request.name);
758
+ try {
759
+ await this.promises.lstat(filePath);
760
+ }
761
+ catch (err) {
762
+ if ((0, util_1.isErrCode)(err, 'ENOENT')) {
763
+ return new msg.Nfsv4SecinfoResponse(2);
764
+ }
765
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
766
+ return new msg.Nfsv4SecinfoResponse(status);
767
+ }
768
+ const flavors = [new struct.Nfsv4SecInfoFlavor(1)];
769
+ const resok = new msg.Nfsv4SecinfoResOk(flavors);
770
+ return new msg.Nfsv4SecinfoResponse(0, resok);
771
+ }
772
+ async LOCK(request, ctx) {
773
+ const currentPath = this.fh.currentPath(ctx);
774
+ const { locktype, offset, length, locker } = request;
775
+ if (!locker.newLockOwner) {
776
+ const existingOwner = locker.owner;
777
+ const stateidKey = this.makeStateidKey(existingOwner.lockStateid);
778
+ let existingLockOwnerKey;
779
+ for (const lock of this.locks.values()) {
780
+ if (this.makeStateidKey(lock.stateid) === stateidKey) {
781
+ existingLockOwnerKey = lock.lockOwnerKey;
782
+ break;
783
+ }
784
+ }
785
+ if (!existingLockOwnerKey) {
786
+ return new msg.Nfsv4LockResponse(10025);
787
+ }
788
+ const lockOwnerState = this.lockOwners.get(existingLockOwnerKey);
789
+ if (!lockOwnerState) {
790
+ return new msg.Nfsv4LockResponse(10025);
791
+ }
792
+ this.renewClientLease(lockOwnerState.clientid);
793
+ const seqidValidation = this.validateSeqid(existingOwner.lockSeqid, lockOwnerState.seqid);
794
+ const requestKey = this.makeLockRequestKey(existingLockOwnerKey, currentPath, locktype, offset, length, existingOwner.lockSeqid);
795
+ if (seqidValidation === 'invalid') {
796
+ return new msg.Nfsv4LockResponse(10026);
797
+ }
798
+ if (seqidValidation === 'replay') {
799
+ if (lockOwnerState.lastRequestKey !== requestKey) {
800
+ return new msg.Nfsv4LockResponse(10026);
801
+ }
802
+ if (lockOwnerState.lastResponse)
803
+ return lockOwnerState.lastResponse;
804
+ return new msg.Nfsv4LockResponse(10026);
805
+ }
806
+ lockOwnerState.seqid = existingOwner.lockSeqid;
807
+ if (this.hasConflictingLock(currentPath, locktype, offset, length, existingLockOwnerKey)) {
808
+ const conflictOwner = new struct.Nfsv4LockOwner(BigInt(0), new Uint8Array());
809
+ const denied = new msg.Nfsv4LockResDenied(offset, length, locktype, conflictOwner);
810
+ return new msg.Nfsv4LockResponse(10010, undefined, denied);
811
+ }
812
+ const lockStateid = this.getOrCreateLockStateid(existingLockOwnerKey, currentPath);
813
+ const stateid = lockStateid.incrementAndGetStateid();
814
+ const lock = new ByteRangeLock_1.ByteRangeLock(stateid, currentPath, locktype, offset, length, existingLockOwnerKey);
815
+ const lockKey = this.makeLockKey(stateid, offset, length);
816
+ this.locks.set(lockKey, lock);
817
+ lockOwnerState.locks.add(lockKey);
818
+ const resok = new msg.Nfsv4LockResOk(stateid);
819
+ const response = new msg.Nfsv4LockResponse(0, resok);
820
+ lockOwnerState.lastResponse = response;
821
+ lockOwnerState.lastRequestKey = requestKey;
822
+ return response;
823
+ }
824
+ const newOwner = locker.owner;
825
+ const openToLock = newOwner.openToLockOwner;
826
+ const lockOwnerData = openToLock.lockOwner;
827
+ const openStateidKey = this.makeStateidKey(openToLock.openStateid);
828
+ const openFile = this.openFiles.get(openStateidKey);
829
+ if (!openFile) {
830
+ return new msg.Nfsv4LockResponse(10025);
831
+ }
832
+ const openOwnerKey = openFile.openOwnerKey;
833
+ const openOwnerState = this.openOwners.get(openOwnerKey);
834
+ if (!openOwnerState) {
835
+ return new msg.Nfsv4LockResponse(10025);
836
+ }
837
+ this.renewClientLease(lockOwnerData.clientid);
838
+ const seqidValidation = this.validateSeqid(openToLock.openSeqid, openOwnerState.seqid);
839
+ if (seqidValidation === 'invalid') {
840
+ return new msg.Nfsv4LockResponse(10026);
841
+ }
842
+ if (seqidValidation === 'replay') {
843
+ for (const [key, lock] of this.locks.entries()) {
844
+ if (lock.lockOwnerKey === this.makeLockOwnerKey(lockOwnerData.clientid, lockOwnerData.owner) &&
845
+ lock.path === currentPath &&
846
+ lock.offset === offset &&
847
+ lock.length === length) {
848
+ const resok = new msg.Nfsv4LockResOk(lock.stateid);
849
+ return new msg.Nfsv4LockResponse(0, resok);
850
+ }
851
+ }
852
+ }
853
+ openOwnerState.seqid = openToLock.openSeqid;
854
+ const lockOwnerKey = this.makeLockOwnerKey(lockOwnerData.clientid, lockOwnerData.owner);
855
+ const lockRequestKey = this.makeLockRequestKey(lockOwnerKey, currentPath, locktype, offset, length, openToLock.lockSeqid);
856
+ if (this.hasConflictingLock(currentPath, locktype, offset, length, lockOwnerKey)) {
857
+ const conflictOwner = new struct.Nfsv4LockOwner(BigInt(0), new Uint8Array());
858
+ const denied = new msg.Nfsv4LockResDenied(offset, length, locktype, conflictOwner);
859
+ return new msg.Nfsv4LockResponse(10010, undefined, denied);
860
+ }
861
+ let lockOwnerState = this.lockOwners.get(lockOwnerKey);
862
+ if (!lockOwnerState) {
863
+ if (openToLock.lockSeqid !== 0) {
864
+ return new msg.Nfsv4LockResponse(10026);
865
+ }
866
+ lockOwnerState = new LockOwnerState_1.LockOwnerState(lockOwnerData.clientid, lockOwnerData.owner, 0);
867
+ this.lockOwners.set(lockOwnerKey, lockOwnerState);
868
+ }
869
+ else {
870
+ const lockSeqidValidation = this.validateSeqid(openToLock.lockSeqid, lockOwnerState.seqid);
871
+ if (lockSeqidValidation === 'invalid') {
872
+ return new msg.Nfsv4LockResponse(10026);
873
+ }
874
+ if (lockSeqidValidation === 'replay') {
875
+ if (lockOwnerState.lastRequestKey === lockRequestKey && lockOwnerState.lastResponse) {
876
+ return lockOwnerState.lastResponse;
877
+ }
878
+ return new msg.Nfsv4LockResponse(10026);
879
+ }
880
+ }
881
+ lockOwnerState.seqid = openToLock.lockSeqid;
882
+ const lockStateid = this.getOrCreateLockStateid(lockOwnerKey, currentPath);
883
+ const stateid = lockStateid.incrementAndGetStateid();
884
+ const lock = new ByteRangeLock_1.ByteRangeLock(stateid, currentPath, locktype, offset, length, lockOwnerKey);
885
+ const lockKey = this.makeLockKey(stateid, offset, length);
886
+ this.locks.set(lockKey, lock);
887
+ lockOwnerState.locks.add(lockKey);
888
+ const resok = new msg.Nfsv4LockResOk(stateid);
889
+ const response = new msg.Nfsv4LockResponse(0, resok);
890
+ lockOwnerState.lastResponse = response;
891
+ lockOwnerState.lastRequestKey = lockRequestKey;
892
+ return response;
893
+ }
894
+ async LOCKT(request, ctx) {
895
+ const currentPath = this.fh.currentPath(ctx);
896
+ const { locktype, offset, length, owner } = request;
897
+ const ownerKey = this.makeLockOwnerKey(owner.clientid, owner.owner);
898
+ if (this.hasConflictingLock(currentPath, locktype, offset, length, ownerKey)) {
899
+ const conflictOwner = new struct.Nfsv4LockOwner(BigInt(0), new Uint8Array());
900
+ const denied = new msg.Nfsv4LocktResDenied(offset, length, locktype, conflictOwner);
901
+ return new msg.Nfsv4LocktResponse(10010, denied);
902
+ }
903
+ return new msg.Nfsv4LocktResponse(0);
904
+ }
905
+ async LOCKU(request, ctx) {
906
+ const { lockStateid, offset, length, seqid } = request;
907
+ const lockStateidState = this.findLockStateidByOther(lockStateid.other);
908
+ if (!lockStateidState)
909
+ throw 10025;
910
+ const ownerKey = lockStateidState.lockOwnerKey;
911
+ const lockOwnerState = this.lockOwners.get(ownerKey);
912
+ if (!lockOwnerState)
913
+ throw 10025;
914
+ this.renewClientLease(lockOwnerState.clientid);
915
+ const currentPath = this.fh.currentPath(ctx);
916
+ if (lockStateidState.path !== currentPath)
917
+ throw 10025;
918
+ const requestKey = this.makeLockuRequestKey(ownerKey, lockStateid, offset, length, seqid);
919
+ const seqidValidation = this.validateSeqid(seqid, lockOwnerState.seqid);
920
+ if (seqidValidation === 'invalid') {
921
+ throw 10026;
922
+ }
923
+ if (seqidValidation === 'replay') {
924
+ if (lockOwnerState.lastRequestKey === requestKey && lockOwnerState.lastResponse) {
925
+ return lockOwnerState.lastResponse;
926
+ }
927
+ throw 10026;
928
+ }
929
+ lockOwnerState.seqid = seqid;
930
+ const lockKey = this.makeLockKey(lockStateid, offset, length);
931
+ const lock = this.locks.get(lockKey);
932
+ if (lock) {
933
+ this.locks.delete(lockKey);
934
+ lockOwnerState.locks.delete(lockKey);
935
+ }
936
+ const stateid = lockStateidState.incrementAndGetStateid();
937
+ const resok = new msg.Nfsv4LockuResOk(stateid);
938
+ const response = new msg.Nfsv4LockuResponse(0, resok);
939
+ lockOwnerState.lastResponse = response;
940
+ lockOwnerState.lastRequestKey = requestKey;
941
+ return response;
942
+ }
943
+ async RELEASE_LOCKOWNER(request, ctx) {
944
+ const { lockOwner } = request;
945
+ const ownerKey = this.makeLockOwnerKey(lockOwner.clientid, lockOwner.owner);
946
+ const lockOwnerState = this.lockOwners.get(ownerKey);
947
+ if (!lockOwnerState)
948
+ throw 10025;
949
+ for (const lockKey of lockOwnerState.locks)
950
+ this.locks.delete(lockKey);
951
+ this.lockOwners.delete(ownerKey);
952
+ return new msg.Nfsv4ReleaseLockOwnerResponse(0);
953
+ }
954
+ async RENEW(request, ctx) {
955
+ const clientid = request.clientid;
956
+ const client = this.clients.get(clientid);
957
+ if (!client)
958
+ throw 10022;
959
+ return new msg.Nfsv4RenewResponse(0);
960
+ }
961
+ async READ(request, ctx) {
962
+ const stateidKey = this.makeStateidKey(request.stateid);
963
+ const openFile = this.openFiles.get(stateidKey);
964
+ if (!openFile)
965
+ return new msg.Nfsv4ReadResponse(10025);
966
+ const fdHandle = openFile.fd;
967
+ let fd = undefined;
968
+ let openedHere = false;
969
+ try {
970
+ if (fdHandle && typeof fdHandle.read === 'function') {
971
+ fd = fdHandle;
972
+ }
973
+ else {
974
+ fd = await this.promises.open(openFile.path, this.fs.constants.O_RDONLY);
975
+ openedHere = true;
976
+ }
977
+ const buf = Buffer.alloc(request.count);
978
+ const { bytesRead } = await fd.read(buf, 0, request.count, Number(request.offset));
979
+ const eof = bytesRead < request.count;
980
+ const data = buf.slice(0, bytesRead);
981
+ const resok = new msg.Nfsv4ReadResOk(eof, data);
982
+ return new msg.Nfsv4ReadResponse(0, resok);
983
+ }
984
+ catch (err) {
985
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
986
+ return new msg.Nfsv4ReadResponse(status);
987
+ }
988
+ finally {
989
+ try {
990
+ if (openedHere && fd && typeof fd.close === 'function')
991
+ await fd.close();
992
+ }
993
+ catch (e) {
994
+ }
995
+ }
996
+ }
997
+ async READLINK(request, ctx) {
998
+ const currentPath = this.fh.currentPath(ctx);
999
+ const currentPathAbsolute = this.absolutePath(currentPath);
1000
+ try {
1001
+ const target = await this.promises.readlink(currentPathAbsolute);
1002
+ const resok = new msg.Nfsv4ReadlinkResOk(target);
1003
+ return new msg.Nfsv4ReadlinkResponse(0, resok);
1004
+ }
1005
+ catch (err) {
1006
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1007
+ return new msg.Nfsv4ReadlinkResponse(status);
1008
+ }
1009
+ }
1010
+ async REMOVE(request, ctx) {
1011
+ const currentPath = this.fh.currentPath(ctx);
1012
+ const targetPath = this.absolutePath(NodePath.join(currentPath, request.target));
1013
+ try {
1014
+ const stats = await this.promises.lstat(targetPath);
1015
+ if (stats.isDirectory()) {
1016
+ await this.promises.rmdir(targetPath);
1017
+ }
1018
+ else {
1019
+ await this.promises.unlink(targetPath);
1020
+ }
1021
+ this.fh.remove(targetPath);
1022
+ const before = this.changeCounter;
1023
+ const after = ++this.changeCounter;
1024
+ const cinfo = new struct.Nfsv4ChangeInfo(true, before, after);
1025
+ const resok = new msg.Nfsv4RemoveResOk(cinfo);
1026
+ return new msg.Nfsv4RemoveResponse(0, resok);
1027
+ }
1028
+ catch (err) {
1029
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1030
+ return new msg.Nfsv4RemoveResponse(status);
1031
+ }
1032
+ }
1033
+ async RENAME(request, ctx) {
1034
+ const savedPath = this.fh.savedPath(ctx);
1035
+ const currentPath = this.fh.currentPath(ctx);
1036
+ const savedPathAbsolute = this.absolutePath(savedPath);
1037
+ const currentPathAbsolute = this.absolutePath(currentPath);
1038
+ const oldFull = NodePath.join(savedPathAbsolute, request.oldname);
1039
+ const newFull = NodePath.join(currentPathAbsolute, request.newname);
1040
+ if (oldFull.length < this.dir.length || newFull.length < this.dir.length)
1041
+ throw 2;
1042
+ if (!oldFull.startsWith(this.dir))
1043
+ return new msg.Nfsv4RenameResponse(2);
1044
+ if (!newFull.startsWith(this.dir))
1045
+ return new msg.Nfsv4RenameResponse(2);
1046
+ let oldPath;
1047
+ let newPath;
1048
+ try {
1049
+ oldPath = this.absolutePath(oldFull);
1050
+ newPath = this.absolutePath(newFull);
1051
+ }
1052
+ catch (e) {
1053
+ const status = typeof e === 'number' ? e : 2;
1054
+ return new msg.Nfsv4RenameResponse(status);
1055
+ }
1056
+ try {
1057
+ await this.promises.rename(oldPath, newPath);
1058
+ this.fh.rename(oldPath, newPath);
1059
+ const before = this.changeCounter;
1060
+ const after = ++this.changeCounter;
1061
+ const sourceCinfo = new struct.Nfsv4ChangeInfo(true, before, after);
1062
+ const targetCinfo = new struct.Nfsv4ChangeInfo(true, before, after);
1063
+ const resok = new msg.Nfsv4RenameResOk(sourceCinfo, targetCinfo);
1064
+ return new msg.Nfsv4RenameResponse(0, resok);
1065
+ }
1066
+ catch (err) {
1067
+ if ((0, util_1.isErrCode)('EXDEV', err))
1068
+ return new msg.Nfsv4RenameResponse(18);
1069
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1070
+ return new msg.Nfsv4RenameResponse(status);
1071
+ }
1072
+ }
1073
+ async WRITE(request, ctx) {
1074
+ const stateidKey = this.makeStateidKey(request.stateid);
1075
+ const openFile = this.openFiles.get(stateidKey);
1076
+ if (!openFile)
1077
+ return new msg.Nfsv4WriteResponse(10025);
1078
+ const fdHandle = openFile.fd;
1079
+ let fd = undefined;
1080
+ let openedHere = false;
1081
+ try {
1082
+ if (fdHandle && typeof fdHandle.write === 'function') {
1083
+ fd = fdHandle;
1084
+ }
1085
+ else {
1086
+ fd = await this.promises.open(openFile.path, this.fs.constants.O_RDWR);
1087
+ openedHere = true;
1088
+ }
1089
+ const buffer = Buffer.from(request.data);
1090
+ const { bytesWritten } = await fd.write(buffer, 0, buffer.length, Number(request.offset));
1091
+ const committed = request.stable === 0 ? 0 : 2;
1092
+ if (request.stable === 2 || request.stable === 1) {
1093
+ if (typeof fd.datasync === 'function')
1094
+ await fd.datasync();
1095
+ else if (typeof fd.sync === 'function')
1096
+ await fd.sync();
1097
+ }
1098
+ const verifier = new struct.Nfsv4Verifier((0, node_crypto_1.randomBytes)(8));
1099
+ const resok = new msg.Nfsv4WriteResOk(bytesWritten, committed, verifier);
1100
+ return new msg.Nfsv4WriteResponse(0, resok);
1101
+ }
1102
+ catch (err) {
1103
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1104
+ return new msg.Nfsv4WriteResponse(status);
1105
+ }
1106
+ finally {
1107
+ try {
1108
+ if (openedHere && fd && typeof fd.close === 'function')
1109
+ await fd.close();
1110
+ }
1111
+ catch (e) {
1112
+ }
1113
+ }
1114
+ }
1115
+ async DELEGPURGE(request, ctx) {
1116
+ return new msg.Nfsv4DelegpurgeResponse(10004);
1117
+ }
1118
+ async DELEGRETURN(request, ctx) {
1119
+ return new msg.Nfsv4DelegreturnResponse(10004);
1120
+ }
1121
+ async COMMIT(request, ctx) {
1122
+ const currentPath = this.fh.currentPath(ctx);
1123
+ const currentPathAbsolute = this.absolutePath(currentPath);
1124
+ let fd = undefined;
1125
+ for (const openFile of this.openFiles.values()) {
1126
+ if (openFile.path === currentPathAbsolute) {
1127
+ fd = openFile.fd;
1128
+ break;
1129
+ }
1130
+ }
1131
+ try {
1132
+ if (fd && typeof fd.datasync === 'function') {
1133
+ await fd.datasync();
1134
+ }
1135
+ else if (fd && typeof fd.sync === 'function') {
1136
+ await fd.sync();
1137
+ }
1138
+ else {
1139
+ const handle = await this.promises.open(currentPathAbsolute, this.fs.constants.O_RDONLY);
1140
+ try {
1141
+ if (typeof handle.datasync === 'function')
1142
+ await handle.datasync();
1143
+ else if (typeof handle.sync === 'function')
1144
+ await handle.sync();
1145
+ }
1146
+ finally {
1147
+ try {
1148
+ await handle.close();
1149
+ }
1150
+ catch (e) {
1151
+ }
1152
+ }
1153
+ }
1154
+ return new msg.Nfsv4CommitResponse(0);
1155
+ }
1156
+ catch (err) {
1157
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1158
+ return new msg.Nfsv4CommitResponse(status);
1159
+ }
1160
+ }
1161
+ async CREATE(request, ctx) {
1162
+ const currentPath = this.fh.currentPath(ctx);
1163
+ const currentPathAbsolute = this.absolutePath(currentPath);
1164
+ const name = request.objname;
1165
+ const createPath = NodePath.join(currentPathAbsolute, name);
1166
+ if (createPath.length < this.dir.length)
1167
+ throw 2;
1168
+ try {
1169
+ const objType = request.objtype.type;
1170
+ if (objType === 2) {
1171
+ let mode = 0o777;
1172
+ try {
1173
+ if (request.createattrs && request.createattrs.attrmask) {
1174
+ const dec = new XdrDecoder_1.XdrDecoder();
1175
+ dec.reader.reset(request.createattrs.attrVals);
1176
+ const maskSet = (0, attributes_1.parseBitmask)(request.createattrs.attrmask.mask);
1177
+ if (maskSet.has(33)) {
1178
+ const m = dec.readUnsignedInt();
1179
+ mode = m & 0o7777;
1180
+ }
1181
+ }
1182
+ }
1183
+ catch (e) {
1184
+ }
1185
+ await this.promises.mkdir(createPath, mode);
1186
+ }
1187
+ else if (objType === 5) {
1188
+ const linkTarget = request.objtype.objtype.linkdata;
1189
+ await this.promises.symlink(linkTarget, createPath);
1190
+ }
1191
+ else {
1192
+ let mode = 0o666;
1193
+ try {
1194
+ if (request.createattrs && request.createattrs.attrmask) {
1195
+ const dec = new XdrDecoder_1.XdrDecoder();
1196
+ dec.reader.reset(request.createattrs.attrVals);
1197
+ const maskSet = (0, attributes_1.parseBitmask)(request.createattrs.attrmask.mask);
1198
+ if (maskSet.has(33)) {
1199
+ const m = dec.readUnsignedInt();
1200
+ mode = m & 0o7777;
1201
+ }
1202
+ }
1203
+ }
1204
+ catch (e) {
1205
+ }
1206
+ const fd = await this.promises.open(createPath, this.fs.constants.O_CREAT | this.fs.constants.O_EXCL | this.fs.constants.O_RDWR, mode);
1207
+ try {
1208
+ await fd.close();
1209
+ }
1210
+ catch { }
1211
+ }
1212
+ const stats = await this.promises.stat(createPath);
1213
+ const fh = this.fh.encode(createPath);
1214
+ ctx.cfh = fh;
1215
+ const before = this.changeCounter;
1216
+ const after = ++this.changeCounter;
1217
+ const cinfo = new struct.Nfsv4ChangeInfo(true, before, after);
1218
+ const attrset = new struct.Nfsv4Bitmap([]);
1219
+ const resok = new msg.Nfsv4CreateResOk(cinfo, attrset);
1220
+ return new msg.Nfsv4CreateResponse(0, resok);
1221
+ }
1222
+ catch (err) {
1223
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1224
+ return new msg.Nfsv4CreateResponse(status);
1225
+ }
1226
+ }
1227
+ async LINK(request, ctx) {
1228
+ const savedPath = this.fh.savedPath(ctx);
1229
+ const existingPath = this.absolutePath(savedPath);
1230
+ const currentPath = this.fh.currentPath(ctx);
1231
+ const newPath = this.absolutePath(NodePath.join(currentPath, request.newname));
1232
+ try {
1233
+ await this.promises.link(existingPath, newPath);
1234
+ const before = this.changeCounter;
1235
+ const after = ++this.changeCounter;
1236
+ const resok = new msg.Nfsv4LinkResOk(new struct.Nfsv4ChangeInfo(true, before, after));
1237
+ return new msg.Nfsv4LinkResponse(0, resok);
1238
+ }
1239
+ catch (err) {
1240
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1241
+ return new msg.Nfsv4LinkResponse(status);
1242
+ }
1243
+ }
1244
+ async NVERIFY(request, ctx) {
1245
+ const currentPath = this.fh.currentPath(ctx);
1246
+ const currentPathAbsolute = this.absolutePath(currentPath);
1247
+ try {
1248
+ const stats = await this.promises.lstat(currentPathAbsolute);
1249
+ const fsStats = await this.fsStats();
1250
+ const attrs = (0, attrs_1.encodeAttrs)(request.objAttributes.attrmask, stats, currentPathAbsolute, ctx.cfh, this.leaseTime, fsStats);
1251
+ if ((0, cmpUint8Array_1.cmpUint8Array)(attrs.attrVals, request.objAttributes.attrVals))
1252
+ return new msg.Nfsv4NverifyResponse(10027);
1253
+ return new msg.Nfsv4NverifyResponse(0);
1254
+ }
1255
+ catch (err) {
1256
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1257
+ return new msg.Nfsv4NverifyResponse(status);
1258
+ }
1259
+ }
1260
+ async SETATTR(request, ctx) {
1261
+ const currentPath = this.fh.currentPath(ctx);
1262
+ const currentPathAbsolute = this.absolutePath(currentPath);
1263
+ try {
1264
+ const inFattr = request.objAttributes;
1265
+ const dec = new XdrDecoder_1.XdrDecoder();
1266
+ dec.reader.reset(inFattr.attrVals);
1267
+ const mask = inFattr.attrmask.mask;
1268
+ let atime;
1269
+ let mtime;
1270
+ let uid;
1271
+ let gid;
1272
+ for (let i = 0; i < mask.length; i++) {
1273
+ const word = mask[i];
1274
+ for (let bit = 0; bit < 32; bit++) {
1275
+ const bitMask = 1 << bit;
1276
+ if (!(word & bitMask))
1277
+ continue;
1278
+ const attrNum = i * 32 + bit;
1279
+ switch (attrNum) {
1280
+ case 33: {
1281
+ const mode = dec.readUnsignedInt();
1282
+ await this.promises.chmod(currentPathAbsolute, mode & 0o7777);
1283
+ break;
1284
+ }
1285
+ case 36: {
1286
+ const owner = dec.readString();
1287
+ const parsedUid = parseInt(owner, 10);
1288
+ if (!isNaN(parsedUid)) {
1289
+ uid = parsedUid;
1290
+ }
1291
+ break;
1292
+ }
1293
+ case 37: {
1294
+ const group = dec.readString();
1295
+ const parsedGid = parseInt(group, 10);
1296
+ if (!isNaN(parsedGid)) {
1297
+ gid = parsedGid;
1298
+ }
1299
+ break;
1300
+ }
1301
+ case 4: {
1302
+ const size = dec.readUnsignedHyper();
1303
+ await this.promises.truncate(currentPathAbsolute, Number(size));
1304
+ break;
1305
+ }
1306
+ case 48: {
1307
+ const setIt = dec.readUnsignedInt();
1308
+ if (setIt === 1) {
1309
+ const seconds = Number(dec.readHyper());
1310
+ const nseconds = dec.readUnsignedInt();
1311
+ atime = new Date(seconds * 1000 + nseconds / 1000000);
1312
+ }
1313
+ break;
1314
+ }
1315
+ case 54: {
1316
+ const setIt = dec.readUnsignedInt();
1317
+ if (setIt === 1) {
1318
+ const seconds = Number(dec.readHyper());
1319
+ const nseconds = dec.readUnsignedInt();
1320
+ mtime = new Date(seconds * 1000 + nseconds / 1000000);
1321
+ }
1322
+ break;
1323
+ }
1324
+ case 19: {
1325
+ dec.readVarlenArray(() => dec.readUnsignedInt());
1326
+ break;
1327
+ }
1328
+ case 0: {
1329
+ const len = dec.readUnsignedInt();
1330
+ for (let j = 0; j < len; j++)
1331
+ dec.readUnsignedInt();
1332
+ break;
1333
+ }
1334
+ case 1: {
1335
+ dec.readUnsignedInt();
1336
+ break;
1337
+ }
1338
+ case 20:
1339
+ case 45:
1340
+ case 3: {
1341
+ dec.readUnsignedHyper();
1342
+ break;
1343
+ }
1344
+ case 47:
1345
+ case 53:
1346
+ case 52: {
1347
+ dec.readHyper();
1348
+ dec.readUnsignedInt();
1349
+ break;
1350
+ }
1351
+ default: {
1352
+ return new msg.Nfsv4SetattrResponse(10032);
1353
+ }
1354
+ }
1355
+ }
1356
+ }
1357
+ if (uid !== undefined || gid !== undefined) {
1358
+ const stats = await this.promises.lstat(currentPathAbsolute);
1359
+ const uidToSet = uid !== undefined ? uid : stats.uid;
1360
+ const gidToSet = gid !== undefined ? gid : stats.gid;
1361
+ await this.promises.chown(currentPathAbsolute, uidToSet, gidToSet);
1362
+ }
1363
+ if (atime || mtime) {
1364
+ const stats = await this.promises.lstat(currentPathAbsolute);
1365
+ const atimeToSet = atime || stats.atime;
1366
+ const mtimeToSet = mtime || stats.mtime;
1367
+ await this.promises.utimes(currentPathAbsolute, atimeToSet, mtimeToSet);
1368
+ }
1369
+ const stats = await this.promises.lstat(currentPathAbsolute);
1370
+ const fh = this.fh.encode(currentPath);
1371
+ const fsStats = await this.fsStats();
1372
+ const returnMask = new struct.Nfsv4Bitmap((0, attributes_1.attrNumsToBitmap)([33, 4]));
1373
+ const fattr = (0, attrs_1.encodeAttrs)(returnMask, stats, currentPath, fh, this.leaseTime, fsStats);
1374
+ const resok = new msg.Nfsv4SetattrResOk(returnMask);
1375
+ return new msg.Nfsv4SetattrResponse(0, resok);
1376
+ }
1377
+ catch (err) {
1378
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1379
+ return new msg.Nfsv4SetattrResponse(status);
1380
+ }
1381
+ }
1382
+ async VERIFY(request, ctx) {
1383
+ const currentPath = this.fh.currentPath(ctx);
1384
+ const currentPathAbsolute = this.absolutePath(currentPath);
1385
+ try {
1386
+ const stats = await this.promises.lstat(currentPathAbsolute);
1387
+ const fsStats = await this.fsStats();
1388
+ const attrs = (0, attrs_1.encodeAttrs)(request.objAttributes.attrmask, stats, currentPath, ctx.cfh, this.leaseTime, fsStats);
1389
+ if ((0, cmpUint8Array_1.cmpUint8Array)(attrs.attrVals, request.objAttributes.attrVals))
1390
+ return new msg.Nfsv4VerifyResponse(0);
1391
+ return new msg.Nfsv4VerifyResponse(10027);
1392
+ }
1393
+ catch (err) {
1394
+ const status = (0, util_1.normalizeNodeFsError)(err, ctx.connection.logger);
1395
+ return new msg.Nfsv4VerifyResponse(status);
1396
+ }
1397
+ }
1398
+ }
1399
+ exports.Nfsv4OperationsNode = Nfsv4OperationsNode;
1400
+ //# sourceMappingURL=Nfsv4OperationsNode.js.map