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