nfs-rb 1.0.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.
@@ -0,0 +1,94 @@
1
+ # The XDR representation of the NFS mount protocol. Based on RFC 1094.
2
+
3
+ module NFS
4
+ module Mount
5
+ include SUNRPC
6
+
7
+ MNTPATHLEN = 1024 # maximum bytes in a pathname argument
8
+ MNTNAMLEN = 255 # maximum bytes in a name argument
9
+
10
+ # The fhandle is the file handle that the server passes to the client.
11
+ # All file operations are done using the file handles to refer to a file
12
+ # or a directory. The file handle can contain whatever information the
13
+ # server needs to distinguish an individual file.
14
+ # -just use nfs_fh from the nfs protocol.
15
+
16
+ # If a status of zero is returned, the call completed successfully, and
17
+ # a file handle for the directory follows. A non-zero status indicates
18
+ # some sort of error. The status corresponds with UNIX error numbers.
19
+ FhStatus = Union.new(NFS::NFSStat) do
20
+ arm :NFS_OK do
21
+ component :fhs_fhandle, NFS::NFSFh
22
+ end
23
+
24
+ default do
25
+ end
26
+ end
27
+
28
+ # The type dirpath is the pathname of a directory
29
+ DirPath = DynamicString.new(MNTPATHLEN)
30
+
31
+ # The type name is used for arbitrary names (hostnames, groupnames)
32
+ Name = DynamicString.new(MNTNAMLEN)
33
+
34
+ # A list of who has what mounted
35
+ MountBody = Structure.new do
36
+ component :ml_hostname, Name
37
+ component :ml_directory, DirPath
38
+ component :ml_next, Optional.new(self)
39
+ end
40
+
41
+ MountList = Optional.new(MountBody)
42
+
43
+ # A list of netgroups
44
+ GroupNode = Structure.new do
45
+ component :gr_name, Name
46
+ component :gr_next, Optional.new(self)
47
+ end
48
+
49
+ Groups = Optional.new(GroupNode)
50
+
51
+ # A list of what is exported and to whom
52
+ ExportNode = Structure.new do
53
+ component :ex_dir, DirPath
54
+ component :ex_groups, Groups
55
+ component :ex_next, Optional.new(self)
56
+ end
57
+
58
+ Exports = Optional.new(ExportNode)
59
+
60
+ MOUNTVERS = 1
61
+
62
+ MOUNTPROG = Program.new(100005) do
63
+ version(MOUNTVERS) do
64
+ # If fhs_status is 0, then fhs_fhandle contains the
65
+ # file handle for the directory. This file handle may
66
+ # be used in the NFS protocol. This procedure also adds
67
+ # a new entry to the mount list for this client mounting
68
+ # the directory.
69
+ # Unix authentication required.
70
+ procedure FhStatus, :MNT, 1, DirPath
71
+
72
+ # Returns the list of remotely mounted filesystems. The
73
+ # mountlist contains one entry for each hostname and
74
+ # directory pair.
75
+ procedure MountList, :DUMP, 2, Void.new
76
+
77
+ # Removes the mount list entry for the directory
78
+ # Unix authentication required.
79
+ procedure Void.new, :UMNT, 3, DirPath
80
+
81
+ # Removes all of the mount list entries for this client
82
+ # Unix authentication required.
83
+ procedure Void.new, :UMNTALL, 4, Void.new
84
+
85
+ # Returns a list of all the exported filesystems, and which
86
+ # machines are allowed to import it.
87
+ procedure Exports, :EXPORT, 5, Void.new
88
+
89
+ # Identical to MOUNTPROC_EXPORT above
90
+ procedure Exports, :EXPORTALL, 6, Void.new
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,259 @@
1
+ # A port of the NFSv2 XDR specification to Ruby XDR/SUNRPC. Based on RFC 1094.
2
+
3
+ module NFS
4
+ module NFS
5
+ include SUNRPC
6
+
7
+ PORT = 2049
8
+ MAXDATA = 8192
9
+ MAXPATHLEN = 1024
10
+ MAXNAMELEN = 255
11
+ FHSIZE = 32
12
+ FIFO_DEV = -1 # size kludge for named pipes
13
+
14
+ MODE_FMT = 0170000 # type of file
15
+ MODE_DIR = 0040000 # directory
16
+ MODE_CHR = 0020000 # character special
17
+ MODE_BLK = 0060000 # block special
18
+ MODE_REG = 0100000 # regular
19
+ MODE_LNK = 0120000 # symbolic link
20
+ MODE_SOCK = 0140000 # socket
21
+ MODE_FIFO = 0010000 # fifo
22
+
23
+ NFSStat = Enumeration.new do
24
+ name :NFS_OK, 0 # no error
25
+ name :NFSERR_PERM, 1 # Not owner
26
+ name :NFSERR_NOENT, 2 # No such file or directory
27
+ name :NFSERR_IO, 5 # I/O error
28
+ name :NFSERR_NXIO, 6 # No such device or address
29
+ name :NFSERR_ACCES, 13 # Permission denied
30
+ name :NFSERR_EXIST, 17 # File exists
31
+ name :NFSERR_NODEV, 19 # No such device
32
+ name :NFSERR_NOTDIR, 20 # Not a directory
33
+ name :NFSERR_ISDIR, 21 # Is a directory
34
+ name :NFSERR_INVAL, 22 # Invalid argument
35
+ name :NFSERR_FBIG, 27 # File too large
36
+ name :NFSERR_NOSPC, 28 # No space left on device
37
+ name :NFSERR_ROFS, 30 # Read-only file system
38
+ name :NFSERR_NAMETOOLONG, 63 # File name too long
39
+ name :NFSERR_NOTEMPTY, 66 # Directory not empty
40
+ name :NFSERR_DQUOT, 69 # Disc quota exceeded
41
+ name :NFSERR_STALE, 70 # Stale NFS file handle
42
+ name :NFSERR_WFLUSH, 99 # Write cache flushed
43
+ end
44
+
45
+ FType = Enumeration.new do
46
+ name :NFNON, 0 # non-file
47
+ name :NFREG, 1 # regular file
48
+ name :NFDIR, 2 # directory
49
+ name :NFBLK, 3 # block special
50
+ name :NFCHR, 4 # character special
51
+ name :NFLNK, 5 # symbolic link
52
+ name :NFSOCK, 6 # unix domain sockets
53
+ name :NFBAD, 7 # unused
54
+ name :NFFIFO, 8 # named pipe
55
+ end
56
+
57
+ NFSFh = Structure.new do
58
+ component :data, FixedOpaque.new(FHSIZE)
59
+ end
60
+
61
+ NFSTime = Structure.new do
62
+ component :seconds, UnsignedInteger.new
63
+ component :useconds, UnsignedInteger.new
64
+ end
65
+
66
+ FAttr = Structure.new do
67
+ component :type, FType # file type
68
+ component :mode, UnsignedInteger.new # protection mode bits
69
+ component :nlink, UnsignedInteger.new # number of hard links
70
+ component :uid, UnsignedInteger.new # owner user id
71
+ component :gid, UnsignedInteger.new # owner group id
72
+ component :size, UnsignedInteger.new # file size in bytes
73
+ component :blocksize, UnsignedInteger.new # prefered block size
74
+ component :rdev, UnsignedInteger.new # special device number
75
+ component :blocks, UnsignedInteger.new # Kb of disk used by file
76
+ component :fsid, UnsignedInteger.new # device number
77
+ component :fileid, UnsignedInteger.new # inode number
78
+ component :atime, NFSTime # time of last access
79
+ component :mtime, NFSTime # time of last modification
80
+ component :ctime, NFSTime # time of last change
81
+ end
82
+
83
+ SAttr = Structure.new do
84
+ component :mode, UnsignedInteger.new # protection mode bits
85
+ component :uid, UnsignedInteger.new # owner user id
86
+ component :gid, UnsignedInteger.new # owner group id
87
+ component :size, UnsignedInteger.new # file size in bytes
88
+ component :atime, NFSTime # time of last access
89
+ component :mtime, NFSTime # time of last modification
90
+ end
91
+
92
+ Filename = DynamicString.new(MAXNAMELEN)
93
+ NFSPath = DynamicString.new(MAXPATHLEN)
94
+
95
+ AttrStat = Union.new(NFSStat) do
96
+ arm :NFS_OK do
97
+ component :attributes, FAttr
98
+ end
99
+
100
+ default do
101
+ end
102
+ end
103
+
104
+ SAttrArgs = Structure.new do
105
+ component :file, NFSFh
106
+ component :attributes, SAttr
107
+ end
108
+
109
+ DirOpArgs = Structure.new do
110
+ component :dir, NFSFh
111
+ component :name, Filename
112
+ end
113
+
114
+ DirOpOkRes = Structure.new do
115
+ component :file, NFSFh
116
+ component :attributes, FAttr
117
+ end
118
+
119
+ DirOpRes = Union.new(NFSStat) do
120
+ arm :NFS_OK do
121
+ component :diropres, DirOpOkRes
122
+ end
123
+
124
+ default do
125
+ end
126
+ end
127
+
128
+ ReadLinkRes = Union.new(NFSStat) do
129
+ arm :NFS_OK do
130
+ component :data, NFSPath
131
+ end
132
+
133
+ default do
134
+ end
135
+ end
136
+
137
+ # Arguments to remote read
138
+ ReadArgs = Structure.new do
139
+ component :file, NFSFh # handle for file
140
+ component :offset, UnsignedInteger.new # byte offset in file
141
+ component :count, UnsignedInteger.new # immediate read count
142
+ component :totalcount, UnsignedInteger.new # read count from offset
143
+ end
144
+
145
+ # Status OK portion of remote read reply
146
+ ReadOkRes = Structure.new do
147
+ component :attributes, FAttr # Attributes needed for pagin ??
148
+ component :data, Opaque.new(MAXDATA)
149
+ end
150
+
151
+ ReadRes = Union.new(NFSStat) do
152
+ arm :NFS_OK do
153
+ component :reply, ReadOkRes
154
+ end
155
+
156
+ default do
157
+ end
158
+ end
159
+
160
+ # Arguments to remote write
161
+ WriteArgs = Structure.new do
162
+ component :file, NFSFh # handle for file
163
+ component :beginoffset, UnsignedInteger.new # begin. byte offset in file
164
+ component :offset, UnsignedInteger.new # curr. byte offset in file
165
+ component :totalcount, UnsignedInteger.new # write count to this offset
166
+ component :data, Opaque.new(MAXDATA) # data
167
+ end
168
+
169
+ CreateArgs = Structure.new do
170
+ component :where, DirOpArgs
171
+ component :attributes, SAttr
172
+ end
173
+
174
+ RenameArgs = Structure.new do
175
+ component :from, DirOpArgs
176
+ component :to, DirOpArgs
177
+ end
178
+
179
+ LinkArgs = Structure.new do
180
+ component :from, NFSFh
181
+ component :to, DirOpArgs
182
+ end
183
+
184
+ SymlinkArgs = Structure.new do
185
+ component :from, DirOpArgs
186
+ component :to, NFSPath
187
+ component :attributes, SAttr
188
+ end
189
+
190
+ NFSCookie = UnsignedInteger.new
191
+
192
+ # Arguments to readdir
193
+ ReadDirArgs = Structure.new do
194
+ component :dir, NFSFh # directory handle
195
+ component :cookie, NFSCookie # cookie
196
+ component :count, UnsignedInteger.new # directory bytes to read
197
+ end
198
+
199
+ Entry = Structure.new do
200
+ component :fileid, UnsignedInteger.new
201
+ component :name, Filename
202
+ component :cookie, NFSCookie
203
+ component :nextentry, Optional.new(self)
204
+ end
205
+
206
+ DirList = Structure.new do
207
+ component :entries, Optional.new(Entry)
208
+ component :eof, Boolean.new
209
+ end
210
+
211
+ ReadDirRes = Union.new(NFSStat) do
212
+ arm :NFS_OK do
213
+ component :reply, DirList
214
+ end
215
+ end
216
+
217
+ StatFsOkRes = Structure.new do
218
+ component :tsize, UnsignedInteger.new # preferred xfer size in bytes
219
+ component :bsize, UnsignedInteger.new # file system block size
220
+ component :blocks, UnsignedInteger.new # total blocks in file system
221
+ component :bfree, UnsignedInteger.new # free blocks in fs
222
+ component :bavail, UnsignedInteger.new # free blocks avail to non-root
223
+ end
224
+
225
+ StatFsRes = Union.new(NFSStat) do
226
+ arm :NFS_OK do
227
+ component :reply, StatFsOkRes
228
+ end
229
+
230
+ default do
231
+ end
232
+ end
233
+
234
+ # Remote file service routines
235
+ NFS_VERSION = 2
236
+
237
+ NFS_PROGRAM = Program.new(100003) do
238
+ version(NFS_VERSION) do
239
+ procedure AttrStat, :GETATTR, 1, NFSFh
240
+ procedure AttrStat, :SETATTR, 2, SAttrArgs
241
+ procedure Void.new, :ROOT, 3, Void.new
242
+ procedure DirOpRes, :LOOKUP, 4, DirOpArgs
243
+ procedure ReadLinkRes, :READLINK, 5, NFSFh
244
+ procedure ReadRes, :READ, 6, ReadArgs
245
+ procedure Void.new, :WRITECACHE, 7, Void.new
246
+ procedure AttrStat, :WRITE, 8, WriteArgs
247
+ procedure DirOpRes, :CREATE, 9, CreateArgs
248
+ procedure NFSStat, :REMOVE, 10, DirOpArgs
249
+ procedure NFSStat, :RENAME, 11, RenameArgs
250
+ procedure NFSStat, :LINK, 12, LinkArgs
251
+ procedure NFSStat, :SYMLINK, 13, SymlinkArgs
252
+ procedure DirOpRes, :MKDIR, 14, CreateArgs
253
+ procedure NFSStat, :RMDIR, 15, DirOpArgs
254
+ procedure ReadDirRes, :READDIR, 16, ReadDirArgs
255
+ procedure StatFsRes, :STATFS, 17, NFSFh
256
+ end
257
+ end
258
+ end
259
+ end
@@ -0,0 +1,39 @@
1
+ module NFS
2
+ class Server
3
+ attr_reader :dir, :host, :port, :protocol
4
+
5
+ def initialize(dir:, host:, port:, protocol:)
6
+ @dir = dir
7
+ @host = host
8
+ @port = port
9
+ @protocol = protocol
10
+
11
+ @handler = Handler.new(FileProxy.open(dir))
12
+ @server = server_class.new(@handler.programs, port, host)
13
+ end
14
+
15
+ def join
16
+ @server.join
17
+ end
18
+
19
+ def start
20
+ @server.start
21
+ end
22
+
23
+ def shutdown
24
+ @server.shutdown
25
+ end
26
+
27
+ private
28
+
29
+ def server_class
30
+ if protocol == :tcp
31
+ SUNRPC::TCPServer
32
+ elsif protocol == :udp
33
+ SUNRPC::UDPServer
34
+ else
35
+ raise "Unsupported protocol #{protocol}, expected :tcp or :udp"
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,365 @@
1
+ # Ruby XDR based implementation of SUNRPC. Based on RFC 1057.
2
+
3
+ module NFS
4
+ module SUNRPC
5
+ autoload :Client, 'nfs/sunrpc/client'
6
+ autoload :Procedure, 'nfs/sunrpc/procedure'
7
+ autoload :Program, 'nfs/sunrpc/program'
8
+ autoload :Server, 'nfs/sunrpc/server'
9
+ autoload :TCPServer, 'nfs/sunrpc/tcp_server'
10
+ autoload :UDPClient, 'nfs/sunrpc/udp_client'
11
+ autoload :UDPServer, 'nfs/sunrpc/udp_server'
12
+ autoload :Version, 'nfs/sunrpc/version'
13
+
14
+ include XDR
15
+
16
+ MAXAUTHLEN = 400
17
+ AUTH_UNIX_MAXMACHINENAMELEN = 255
18
+ AUTH_UNIX_MAXGIDS = 16
19
+
20
+ AuthFlavor = Enumeration.new do
21
+ name :AUTH_NULL, 0
22
+ name :AUTH_UNIX, 1
23
+ name :AUTH_SHORT, 2
24
+ name :AUTH_DES, 3
25
+ # and more to be defined?
26
+ end
27
+
28
+ OpaqueAuth = Structure.new do
29
+ component :flavor, AuthFlavor
30
+ component :body, Opaque.new(MAXAUTHLEN)
31
+ end
32
+
33
+ AuthUnix = Structure.new do
34
+ component :stamp, UnsignedInteger.new
35
+ component :machinename, DynamicString.new(AUTH_UNIX_MAXMACHINENAMELEN)
36
+ component :uid, UnsignedInteger.new
37
+ component :gid, UnsignedInteger.new
38
+ component :gids, DynamicArray.new(UnsignedInteger.new, AUTH_UNIX_MAXGIDS)
39
+ end
40
+
41
+ AuthDESNamekind = Enumeration.new do
42
+ name :ADN_FULLNAME, 0
43
+ name :ADN_NICKNAME, 1
44
+ end
45
+
46
+ DESBlock = FixedOpaque.new(8)
47
+
48
+ MAXNETNAMELEN = 255
49
+
50
+ AuthDESFullname = Structure.new do
51
+ component :name, DynamicString.new(MAXNETNAMELEN) # name of client
52
+ component :key, DESBlock # PK encrypted conversation key
53
+ component :window, FixedOpaque.new(4) # encrypted window
54
+ end
55
+
56
+ AuthDESCred = Union.new(AuthDESNamekind) do
57
+ arm :ADN_FULLNAME do
58
+ component :adc_fullname, AuthDESFullname
59
+ end
60
+
61
+ arm :ADN_NICKNAME do
62
+ component :adc_nickname, SignedInteger.new
63
+ end
64
+ end
65
+
66
+ Timestamp = Structure.new do
67
+ component :seconds, UnsignedInteger.new # seconds
68
+ component :useconds, UnsignedInteger.new # microseconds
69
+ end
70
+
71
+ AuthDESVerfClnt = Structure.new do
72
+ component :adv_timestamp, DESBlock # encrypted timestamp
73
+ component :adv_winverf, FixedOpaque.new(4) # encrypted window verifier
74
+ end
75
+
76
+ AuthDESVerfSvr = Structure.new do
77
+ component :adv_timeverf, DESBlock # encrypted verifier
78
+ component :adv_nickname, SignedInteger.new # nickname for client (unencrypted)
79
+ end
80
+
81
+ MsgType = Enumeration.new do
82
+ name :CALL, 0
83
+ name :REPLY, 1
84
+ end
85
+
86
+ ReplyStat = Enumeration.new do
87
+ name :MSG_ACCEPTED, 0
88
+ name :MSG_DENIED, 1
89
+ end
90
+
91
+ AcceptStat = Enumeration.new do
92
+ name :SUCCESS, 0 # RPC executed successfully
93
+ name :PROG_UNAVAIL, 1 # remote hasn't exported program
94
+ name :PROG_MISMATCH, 2 # remote can't support version number
95
+ name :PROC_UNAVAIL, 3 # program can't support procedure
96
+ name :GARBAGE_ARGS, 4 # procedure can't decode params
97
+ end
98
+
99
+ RejectStat = Enumeration.new do
100
+ name :RPC_MISMATCH, 0 # RPC version number != 2
101
+ name :AUTH_ERROR, 1 # remote can't authenticate caller
102
+ end
103
+
104
+ AuthStat = Enumeration.new do
105
+ name :AUTH_BADCRED, 1 # bad credentials (seal broken)
106
+ name :AUTH_REJECTEDCRED, 2 # client must begin new session
107
+ name :AUTH_BADVERF, 3 # bad verifier (seal broken)
108
+ name :AUTH_REJECTEDVERF, 4 # verifier expired or replayed
109
+ name :AUTH_TOOWEAK, 5 # rejected for security reasons
110
+ end
111
+
112
+ CallBody = Structure.new do
113
+ component :rpcvers, UnsignedInteger.new # must be equal to two (2)
114
+ component :prog, UnsignedInteger.new
115
+ component :vers, UnsignedInteger.new
116
+ component :proc, UnsignedInteger.new
117
+ component :cred, OpaqueAuth
118
+ component :verf, OpaqueAuth
119
+ # procedure specific parameters start here
120
+ end
121
+
122
+ AcceptedReply = Structure.new do
123
+ component :verf, OpaqueAuth
124
+ component :reply_data, Union.new(AcceptStat) do
125
+ arm :SUCCESS do
126
+ component :results, FixedOpaque.new(0)
127
+ # Procedure specific results start here
128
+ end
129
+
130
+ arm :PROG_MISMATCH do
131
+ component :mismatch_info, Structure.new do
132
+ component :low, UnsignedInteger.new
133
+ component :high, UnsignedInteger.new
134
+ end
135
+ end
136
+
137
+ default do
138
+ # Void. Cases include PROG_UNAVAIL, PROC_UNAVAIL, and GARBAGE_ARGS.
139
+ end
140
+ end
141
+ end
142
+
143
+ RejectedReply = Union.new(RejectStat) do
144
+ arm :RPC_MISMATCH do
145
+ component :mismatch_info, Structure.new do
146
+ component :low, UnsignedInteger.new
147
+ component :high, UnsignedInteger.new
148
+ end
149
+ end
150
+
151
+ arm :AUTH_ERROR do
152
+ component :stat, AuthStat
153
+ end
154
+ end
155
+
156
+ ReplyBody = Union.new(ReplyStat) do
157
+ arm :MSG_ACCEPTED do
158
+ component :areply, AcceptedReply
159
+ end
160
+
161
+ arm :MSG_DENIED do
162
+ component :rreply, RejectedReply
163
+ end
164
+ end
165
+
166
+ RpcMsg = Structure.new do
167
+ component :xid, UnsignedInteger.new
168
+ component :body, (Union.new(MsgType) do
169
+ arm :CALL do
170
+ component :cbody, CallBody
171
+ end
172
+
173
+ arm :REPLY do
174
+ component :rbody, ReplyBody
175
+ end
176
+ end)
177
+ end
178
+
179
+ # Server Exceptions
180
+
181
+ class IgnoreRequest < Exception
182
+ def encode(xid)
183
+ nil
184
+ end
185
+ end
186
+
187
+ # Abstract base of "rejected" errors
188
+ class RequestDenied < Exception
189
+ def encode(xid)
190
+ RpcMsg.encode({
191
+ xid: xid,
192
+ body: {
193
+ _discriminant: :REPLY,
194
+ rbody: {
195
+ _discriminant: :MSG_DENIED,
196
+ rreply: rreply
197
+ }
198
+ }
199
+ })
200
+ end
201
+ end
202
+
203
+ class RpcMismatch < RequestDenied
204
+ # RPC mismatch takes the xid since, it won't actually have one
205
+ # passed to its encode method.
206
+ def initialize(low, high, xid)
207
+ @low, @high, @xid = low, high, xid
208
+ end
209
+
210
+ def encode(xid)
211
+ RpcMsg.encode({
212
+ xid: @xid,
213
+ body: {
214
+ _discriminant: :REPLY,
215
+ rbody: {
216
+ _discriminant: :MSG_DENIED,
217
+ rreply: rreply
218
+ }
219
+ }
220
+ })
221
+ end
222
+
223
+ private
224
+
225
+ def rreply
226
+ {
227
+ _discriminant: :RPC_MISMATCH,
228
+ mismatch_info: {
229
+ low: @low,
230
+ high: @high
231
+ }
232
+ }
233
+ end
234
+ end
235
+
236
+ # Abstract base of authentication errors
237
+ class AuthenticationError < RequestDenied
238
+ private
239
+
240
+ def rreply
241
+ {
242
+ _discriminant: :AUTH_ERROR,
243
+ stat: AuthStat
244
+ }
245
+ end
246
+ end
247
+
248
+ class BadCredentials < AuthenticationError
249
+ private
250
+
251
+ def auth_stat
252
+ :AUTH_BADCRED
253
+ end
254
+ end
255
+
256
+ class RejectedCredentials < AuthenticationError
257
+ private
258
+
259
+ def auth_stat
260
+ :AUTH_REJECTEDCRED
261
+ end
262
+ end
263
+
264
+ class BadVerifier < AuthenticationError
265
+ private
266
+
267
+ def auth_stat
268
+ :AUTH_BADVERF
269
+ end
270
+ end
271
+
272
+ class RejectedVerifier < AuthenticationError
273
+ private
274
+
275
+ def auth_stat
276
+ :AUTH_REJECTEDVERF
277
+ end
278
+ end
279
+
280
+ class TooWeak < AuthenticationError
281
+ private
282
+
283
+ def auth_stat
284
+ :AUTH_TOOWEAK
285
+ end
286
+ end
287
+
288
+ # Abstract base of errors where the message was "accepted"
289
+ class AcceptedError < Exception
290
+ def encode(xid)
291
+ RpcMsg.encode({
292
+ xid: xid,
293
+ body: {
294
+ _discriminant: :REPLY,
295
+ rbody: {
296
+ _discriminant: :MSG_ACCEPTED,
297
+ areply: areply
298
+ }
299
+ }
300
+ })
301
+ end
302
+ end
303
+
304
+ # Program not supported
305
+ class ProgramUnavailable < AcceptedError
306
+ private
307
+
308
+ def areply
309
+ {
310
+ verf: { flavor: :AUTH_NULL, body: '' },
311
+ reply_data: {
312
+ _discriminant: :PROG_UNAVAIL
313
+ }
314
+ }
315
+ end
316
+ end
317
+
318
+ # Version not supported
319
+ class ProgramMismatch < AcceptedError
320
+ def initialize(low, high)
321
+ @low, @high = low, high
322
+ end
323
+
324
+ private
325
+
326
+ def areply
327
+ {
328
+ verf: { flavor: :AUTH_NULL, body: '' },
329
+ reply_data: {
330
+ _discriminant: :PROG_MISMATCH,
331
+ low: @low,
332
+ high: @high
333
+ }
334
+ }
335
+ end
336
+ end
337
+
338
+ # Procedure not supported
339
+ class ProcedureUnavailable < AcceptedError
340
+ private
341
+
342
+ def areply
343
+ {
344
+ verf: { flavor: :AUTH_NULL, body: '' },
345
+ reply_data: {
346
+ _discriminant: :PROC_UNAVAIL
347
+ }
348
+ }
349
+ end
350
+ end
351
+
352
+ class GarbageArguments < AcceptedError
353
+ private
354
+
355
+ def areply
356
+ {
357
+ verf: { flavor: :AUTH_NULL, body: '' },
358
+ reply_data: {
359
+ _discriminant: :GARBAGE_ARGS
360
+ }
361
+ }
362
+ end
363
+ end
364
+ end
365
+ end