nfs-rb 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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