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,3 @@
1
+ module NFS
2
+ VERSION = '1.0.0'
3
+ end
@@ -0,0 +1,300 @@
1
+ # Ruby XDR. XDR codec for Ruby. Based on RFC 4506.
2
+
3
+ module NFS
4
+ module XDR
5
+ class Void
6
+ def encode(value)
7
+ ''
8
+ end
9
+
10
+ def decode(string)
11
+ nil
12
+ end
13
+ end
14
+
15
+ class SignedInteger
16
+ def encode(value)
17
+ [value].pack('N')
18
+ end
19
+
20
+ def decode(string)
21
+ string.slice!(0..3).unpack('N').pack('I').unpack('i')[0]
22
+ end
23
+ end
24
+
25
+ class UnsignedInteger
26
+ def encode(value)
27
+ [value].pack('N')
28
+ end
29
+
30
+ def decode(string)
31
+ string.slice!(0..3).unpack('N')[0]
32
+ end
33
+ end
34
+
35
+ class Enumeration < SignedInteger
36
+ def initialize(&block)
37
+ @values = {}
38
+ @names = {}
39
+
40
+ if block_given?
41
+ instance_eval(&block)
42
+ end
43
+ end
44
+
45
+ def name(v_name, value)
46
+ @values[v_name] = value
47
+ @names[value] = v_name
48
+ end
49
+
50
+ def encode(name)
51
+ super(@values[name])
52
+ end
53
+
54
+ def decode(string)
55
+ @names[super(string)]
56
+ end
57
+ end
58
+
59
+ class Boolean < Enumeration
60
+ def initialize
61
+ super
62
+
63
+ name :TRUE, 1
64
+ name :FALSE, 0
65
+ end
66
+ end
67
+
68
+ class FloatNum
69
+ def encode(value)
70
+ [value].pack('g')
71
+ end
72
+
73
+ def decode(string)
74
+ string.slice!(0..3).unpack('g')[0]
75
+ end
76
+ end
77
+
78
+ class DoubleNum
79
+ def encode(value)
80
+ [value].pack('G')
81
+ end
82
+
83
+ def decode(string)
84
+ string.slice!(0..7).unpack('G')[0]
85
+ end
86
+ end
87
+
88
+ def self.pad(n, align)
89
+ r = n % align
90
+ r = align if r == 0
91
+ n + align - r
92
+ end
93
+
94
+ class FixedString
95
+ def initialize(n)
96
+ @n = n
97
+ end
98
+
99
+ def encode(value)
100
+ [value.to_s].pack('a' + XDR.pad(@n, 4).to_s)
101
+ end
102
+
103
+ def decode(string)
104
+ superstring = string.slice!(0, XDR.pad(@n, 4))
105
+ superstring.nil? ? '' : superstring[0, @n]
106
+ end
107
+ end
108
+
109
+ class DynamicString
110
+ def initialize(n = nil)
111
+ @n = n
112
+ @length = UnsignedInteger.new
113
+ end
114
+
115
+ def encode(value)
116
+ value = value.to_s
117
+ n = value.size
118
+ n = @n if !@n.nil? && @n < n
119
+ @length.encode(n) + [value].pack('a' + XDR::pad(n, 4).to_s)
120
+ end
121
+
122
+ def decode(string)
123
+ length = @length.decode(string)
124
+ superstring = string.slice!(0, XDR.pad(length, 4))
125
+ superstring.nil? ? '' : superstring[0, length]
126
+ end
127
+ end
128
+
129
+ class FixedOpaque < FixedString
130
+ end
131
+
132
+ class Opaque < DynamicString
133
+ end
134
+
135
+ class FixedArray
136
+ def initialize(type, n)
137
+ @type, @n = type, n
138
+ end
139
+
140
+ def encode(value)
141
+ n.times do |i|
142
+ @type.encode(value[i])
143
+ end
144
+ end
145
+
146
+ def decode(string)
147
+ Array.new(n) do
148
+ @type.decode(string)
149
+ end
150
+ end
151
+ end
152
+
153
+ class DynamicArray
154
+ def initialize(type, n)
155
+ @type, @n = type, n
156
+ @length = UnsignedInteger.new
157
+ end
158
+
159
+ def encode(value)
160
+ n = value.size
161
+
162
+ if !@n.nil? && @n < n
163
+ n = @n
164
+ end
165
+
166
+ result = @length.encode(n)
167
+
168
+ n.times do |i|
169
+ result << @type.encode(value[i])
170
+ end
171
+
172
+ result
173
+ end
174
+
175
+ def decode(string)
176
+ length = @length.decode(string)
177
+
178
+ Array.new(length) do
179
+ @type.decode(string)
180
+ end
181
+ end
182
+ end
183
+
184
+ class Optional < DynamicArray
185
+ def initialize(type)
186
+ super(type, 1)
187
+ end
188
+
189
+ def encode(value)
190
+ if value.nil?
191
+ super([])
192
+ else
193
+ super([value])
194
+ end
195
+ end
196
+
197
+ def decode(string)
198
+ result = super(string)
199
+
200
+ if result.empty?
201
+ nil
202
+ else
203
+ result[0]
204
+ end
205
+ end
206
+ end
207
+
208
+ class Structure
209
+ def initialize(&block)
210
+ @components = []
211
+ @names = []
212
+ instance_eval(&block) if block_given?
213
+ end
214
+
215
+ def component(name, type)
216
+ @components << [name, type]
217
+ @names << name
218
+ end
219
+
220
+ def encode(value)
221
+ ''.tap do |result|
222
+ @components.each do |component|
223
+ unless value.include?(component[0])
224
+ raise 'missing structure component ' + component[0].to_s
225
+ end
226
+
227
+ result << component[1].encode(value[component[0]])
228
+ end
229
+ end
230
+ end
231
+
232
+ def decode(string)
233
+ @components.each_with_object({}) do |component, result|
234
+ result[component[0]] = component[1].decode(string)
235
+ end
236
+ end
237
+ end
238
+
239
+ # Each arm of the union is represented as a struct
240
+ class Union
241
+ def initialize(disc_type, &block)
242
+ @disc_type = disc_type
243
+ @arms = {}
244
+ @default_arm = nil
245
+ instance_eval(&block) if block_given?
246
+ end
247
+
248
+ # Add an arm
249
+ def arm(disc_value, struct = nil, &block)
250
+ if block_given?
251
+ struct = Structure.new(&block)
252
+ end
253
+
254
+ @arms[disc_value] = struct
255
+ end
256
+
257
+ # Set the default arm
258
+ def default(struct = nil, &block)
259
+ if block_given?
260
+ struct = Structure.new(&block)
261
+ end
262
+
263
+ @default_arm = struct
264
+ end
265
+
266
+ def encode(struct)
267
+ disc = struct[:_discriminant]
268
+ arm = @default_arm
269
+ arm = @arms[disc] if @arms.include?(disc)
270
+ result = @disc_type.encode(disc)
271
+
272
+ unless arm.nil?
273
+ result << arm.encode(struct)
274
+ end
275
+
276
+ result
277
+ end
278
+
279
+ def decode(string)
280
+ disc = @disc_type.decode(string)
281
+ arm = @default_arm
282
+
283
+ if @arms.include?(disc)
284
+ arm = @arms[disc]
285
+ end
286
+
287
+ result = nil
288
+
289
+ if arm.nil?
290
+ result = {}
291
+ else
292
+ result = arm.decode(string)
293
+ end
294
+
295
+ result[:_discriminant] = disc
296
+ result
297
+ end
298
+ end
299
+ end
300
+ end
@@ -0,0 +1,17 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), 'lib')
2
+ require 'nfs/version'
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = 'nfs-rb'
6
+ s.version = ::NFS::VERSION
7
+ s.authors = ['Cameron Dutro', 'Brian Ollenberger']
8
+ s.email = ['camertron@gmail.com']
9
+ s.homepage = 'http://github.com/camertron/nfs'
10
+ s.description = s.summary = 'An NFS v2 server implemented in pure Ruby.'
11
+ s.platform = Gem::Platform::RUBY
12
+ s.require_path = 'lib'
13
+
14
+ s.executables << 'nfs-rb'
15
+
16
+ s.files = Dir['{lib,spec}/**/*', 'Gemfile', 'LICENSE', 'CHANGELOG.md', 'README.md', 'Rakefile', 'nfs-rb.gemspec']
17
+ end
@@ -0,0 +1,29 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'NFS' do
4
+ it 'supports directory listing' do
5
+ files = Dir.chdir($dest_dir) do
6
+ Dir.glob("*.*")
7
+ end
8
+
9
+ expect(files.sort).to eq(['file1.txt', 'file2.txt'].sort)
10
+ end
11
+
12
+ it 'supports reading files' do
13
+ %w(file1.txt file2.txt).each do |file|
14
+ orig_contents = File.read(File.join($orig_dir, file))
15
+ dest_contents = File.read(File.join($dest_dir, file))
16
+ expect(dest_contents).to eq(orig_contents)
17
+ end
18
+ end
19
+
20
+ it 'supports file stats' do
21
+ %w(file1.txt file2.txt).each do |file|
22
+ orig_stat = File.lstat(File.join($orig_dir, 'file1.txt'))
23
+ dest_stat = File.lstat(File.join($dest_dir, 'file1.txt'))
24
+ expect(orig_stat.size).to eq(dest_stat.size)
25
+ expect(orig_stat.mtime.to_i).to eq(dest_stat.mtime.to_i)
26
+ expect(orig_stat.ctime.to_i).to eq(dest_stat.ctime.to_i)
27
+ end
28
+ end
29
+ end
@@ -0,0 +1 @@
1
+ Hello world!
@@ -0,0 +1,3 @@
1
+ Oy! This is a other file.
2
+
3
+ With multiple lines.
@@ -0,0 +1,10 @@
1
+ require 'nfs'
2
+
3
+ nfs_server = NFS::Server.new(
4
+ dir: File.expand_path(File.join('.', 'orig_dir'), __dir__),
5
+ host: '127.0.0.1',
6
+ port: 1234,
7
+ protocol: :tcp
8
+ )
9
+
10
+ nfs_server.join
@@ -0,0 +1,44 @@
1
+ # encoding: UTF-8
2
+
3
+ $:.push(File.dirname(__FILE__))
4
+
5
+ require 'rspec'
6
+ require 'fileutils'
7
+ require 'nfs'
8
+
9
+ RSpec.configure do |config|
10
+ config.before(:suite) do
11
+ $orig_dir = File.expand_path(File.join('.', 'orig_dir'), __dir__)
12
+ $dest_dir = File.expand_path(File.join('.', 'dest_dir'), __dir__)
13
+
14
+ FileUtils.mkdir_p($dest_dir)
15
+
16
+ $server_pid = Process.spawn(
17
+ "bundle exec ruby #{File.join('spec', 'run_server.rb')}"
18
+ )
19
+
20
+ system(
21
+ "mount -t nfs -o "\
22
+ 'rsize=8192,wsize=8192,timeo=1,nfsvers=2,proto=tcp,'\
23
+ "port=1234,mountport=1234,"\
24
+ "hard,intr,nolock 127.0.0.1:/ "\
25
+ "#{$dest_dir}"
26
+ )
27
+
28
+ if $?.exitstatus != 0
29
+ fail "Unable to mount NFS volume at #{$dest_dir}"
30
+ exit 1
31
+ end
32
+ end
33
+
34
+ config.after(:suite) do
35
+ system("umount #{$dest_dir}")
36
+
37
+ if $?.exitstatus != 0
38
+ fail "Unable to unmount NFS volume at #{$dest_dir}"
39
+ exit 2
40
+ end
41
+
42
+ Process.kill('HUP', $server_pid)
43
+ end
44
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nfs-rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Cameron Dutro
8
+ - Brian Ollenberger
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2020-08-16 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: An NFS v2 server implemented in pure Ruby.
15
+ email:
16
+ - camertron@gmail.com
17
+ executables:
18
+ - nfs-rb
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - CHANGELOG.md
23
+ - Gemfile
24
+ - LICENSE
25
+ - README.md
26
+ - Rakefile
27
+ - bin/nfs-rb
28
+ - lib/nfs.rb
29
+ - lib/nfs/default_logger.rb
30
+ - lib/nfs/file_proxy.rb
31
+ - lib/nfs/filehandle.rb
32
+ - lib/nfs/handler.rb
33
+ - lib/nfs/mount.rb
34
+ - lib/nfs/nfs.rb
35
+ - lib/nfs/server.rb
36
+ - lib/nfs/sunrpc.rb
37
+ - lib/nfs/sunrpc/client.rb
38
+ - lib/nfs/sunrpc/procedure.rb
39
+ - lib/nfs/sunrpc/program.rb
40
+ - lib/nfs/sunrpc/server.rb
41
+ - lib/nfs/sunrpc/tcp_server.rb
42
+ - lib/nfs/sunrpc/udp_server.rb
43
+ - lib/nfs/sunrpc/version.rb
44
+ - lib/nfs/version.rb
45
+ - lib/nfs/xdr.rb
46
+ - nfs-rb.gemspec
47
+ - spec/nfs_spec.rb
48
+ - spec/orig_dir/file1.txt
49
+ - spec/orig_dir/file2.txt
50
+ - spec/run_server.rb
51
+ - spec/spec_helper.rb
52
+ homepage: http://github.com/camertron/nfs
53
+ licenses: []
54
+ metadata: {}
55
+ post_install_message:
56
+ rdoc_options: []
57
+ require_paths:
58
+ - lib
59
+ required_ruby_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ requirements: []
70
+ rubygems_version: 3.1.4
71
+ signing_key:
72
+ specification_version: 4
73
+ summary: An NFS v2 server implemented in pure Ruby.
74
+ test_files: []