fake_ftp 0.2.0 → 0.3.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.
- checksums.yaml +4 -4
- data/.codeclimate.yml +16 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.rubocop.yml +27 -0
- data/.rubocop_todo.yml +7 -0
- data/.simplecov +6 -0
- data/.travis.yml +27 -2
- data/CHANGELOG.md +136 -0
- data/Gemfile +9 -7
- data/Guardfile +5 -4
- data/LICENSE.md +20 -0
- data/README.md +30 -63
- data/Rakefile +12 -7
- data/fake_ftp.gemspec +16 -17
- data/lib/fake_ftp.rb +3 -2
- data/lib/fake_ftp/file.rb +11 -5
- data/lib/fake_ftp/server.rb +138 -261
- data/lib/fake_ftp/server_commands.rb +6 -0
- data/lib/fake_ftp/server_commands/acct.rb +11 -0
- data/lib/fake_ftp/server_commands/cdup.rb +11 -0
- data/lib/fake_ftp/server_commands/cwd.rb +13 -0
- data/lib/fake_ftp/server_commands/dele.rb +25 -0
- data/lib/fake_ftp/server_commands/list.rb +39 -0
- data/lib/fake_ftp/server_commands/mdtm.rb +17 -0
- data/lib/fake_ftp/server_commands/mkd.rb +11 -0
- data/lib/fake_ftp/server_commands/nlst.rb +32 -0
- data/lib/fake_ftp/server_commands/pass.rb +11 -0
- data/lib/fake_ftp/server_commands/pasv.rb +15 -0
- data/lib/fake_ftp/server_commands/port.rb +23 -0
- data/lib/fake_ftp/server_commands/pwd.rb +11 -0
- data/lib/fake_ftp/server_commands/quit.rb +13 -0
- data/lib/fake_ftp/server_commands/retr.rb +32 -0
- data/lib/fake_ftp/server_commands/rnfr.rb +18 -0
- data/lib/fake_ftp/server_commands/rnto.rb +22 -0
- data/lib/fake_ftp/server_commands/site.rb +11 -0
- data/lib/fake_ftp/server_commands/size.rb +11 -0
- data/lib/fake_ftp/server_commands/stor.rb +30 -0
- data/lib/fake_ftp/server_commands/type.rb +18 -0
- data/lib/fake_ftp/server_commands/user.rb +12 -0
- data/lib/fake_ftp/server_commands/wat.rb +33 -0
- data/lib/fake_ftp/version.rb +3 -1
- data/spec/functional/server_spec.rb +459 -358
- data/spec/integration/server_spec.rb +39 -29
- data/spec/models/fake_ftp/file_spec.rb +22 -21
- data/spec/models/fake_ftp/server_spec.rb +33 -32
- data/spec/spec_helper.rb +98 -14
- metadata +32 -3
data/Rakefile
CHANGED
@@ -1,10 +1,15 @@
|
|
1
|
-
|
2
|
-
Bundler::GemHelper.install_tasks
|
1
|
+
# frozen_string_literal: true
|
3
2
|
|
4
|
-
|
5
|
-
require '
|
3
|
+
begin
|
4
|
+
require 'bundler'
|
5
|
+
require 'rspec/core/rake_task'
|
6
|
+
require 'rubocop/rake_task'
|
7
|
+
rescue LoadError => e
|
8
|
+
warn e
|
9
|
+
end
|
6
10
|
|
7
|
-
|
11
|
+
Bundler::GemHelper.install_tasks if defined?(Bundler)
|
12
|
+
RSpec::Core::RakeTask.new if defined?(RSpec)
|
13
|
+
RuboCop::RakeTask.new if defined?(RuboCop)
|
8
14
|
|
9
|
-
|
10
|
-
task :default => :spec
|
15
|
+
task default: %i[rubocop spec]
|
data/fake_ftp.gemspec
CHANGED
@@ -1,22 +1,21 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
3
|
-
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.expand_path('../lib', __FILE__))
|
5
|
+
require 'fake_ftp/version'
|
4
6
|
|
5
7
|
Gem::Specification.new do |s|
|
6
|
-
s.name
|
7
|
-
s.version
|
8
|
-
s.platform
|
9
|
-
s.authors
|
10
|
-
s.email
|
11
|
-
s.homepage
|
12
|
-
s.summary
|
13
|
-
s.description =
|
14
|
-
s.license
|
8
|
+
s.name = 'fake_ftp'
|
9
|
+
s.version = FakeFtp::VERSION
|
10
|
+
s.platform = Gem::Platform::RUBY
|
11
|
+
s.authors = ['Colin Shield', 'Eric Saxby']
|
12
|
+
s.email = ['sax+github@livinginthepast.org']
|
13
|
+
s.homepage = 'http://rubygems.org/gems/fake_ftp'
|
14
|
+
s.summary = 'Creates a fake FTP server for use in testing'
|
15
|
+
s.description = 'Testing FTP? Use this!'
|
16
|
+
s.license = 'MIT'
|
15
17
|
|
16
|
-
s.
|
17
|
-
|
18
|
-
s.
|
19
|
-
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
-
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
-
s.require_paths = ["lib"]
|
18
|
+
s.files = `git ls-files -z`.split("\0")
|
19
|
+
s.test_files = `git ls-files -z -- spec/*`.split("\0")
|
20
|
+
s.require_paths = %w[lib]
|
22
21
|
end
|
data/lib/fake_ftp.rb
CHANGED
data/lib/fake_ftp/file.rb
CHANGED
@@ -1,23 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FakeFtp
|
2
4
|
class File
|
3
|
-
attr_accessor :bytes, :name, :last_modified_time
|
5
|
+
attr_accessor :bytes, :data, :name, :last_modified_time
|
4
6
|
attr_writer :type
|
5
|
-
attr_accessor :data
|
6
7
|
attr_reader :created
|
7
8
|
|
8
|
-
def initialize(name = nil, data = nil, type = nil,
|
9
|
+
def initialize(name = nil, data = nil, type = nil,
|
10
|
+
last_modified_time = Time.now)
|
9
11
|
@created = Time.now
|
10
12
|
@name = name
|
11
13
|
@data = data
|
12
|
-
# FIXME this is far too ambiguous. args should not mean different
|
14
|
+
# FIXME: this is far too ambiguous. args should not mean different
|
13
15
|
# things in different contexts.
|
14
|
-
data_is_bytes = (data.nil? || Integer
|
16
|
+
data_is_bytes = (data.nil? || data.is_a?(Integer))
|
15
17
|
@bytes = data_is_bytes ? data : data.to_s.length
|
16
18
|
@data = data_is_bytes ? nil : data
|
17
19
|
@type = type
|
18
20
|
@last_modified_time = last_modified_time.utc
|
19
21
|
end
|
20
22
|
|
23
|
+
def basename
|
24
|
+
::File.basename(@name)
|
25
|
+
end
|
26
|
+
|
21
27
|
def data=(data)
|
22
28
|
@data = data
|
23
29
|
@bytes = @data.nil? ? nil : data.length
|
data/lib/fake_ftp/server.rb
CHANGED
@@ -1,63 +1,67 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'socket'
|
2
4
|
require 'thread'
|
3
5
|
require 'timeout'
|
4
6
|
|
5
7
|
module FakeFtp
|
6
8
|
class Server
|
9
|
+
attr_accessor :client, :command_state, :data_server, :passive_port
|
10
|
+
attr_accessor :port, :store, :workdir
|
7
11
|
|
8
|
-
|
9
|
-
attr_reader :mode, :path
|
10
|
-
|
11
|
-
CMDS = %w(
|
12
|
-
acct
|
13
|
-
cwd
|
14
|
-
cdup
|
15
|
-
dele
|
16
|
-
list
|
17
|
-
mdtm
|
18
|
-
mkd
|
19
|
-
nlst
|
20
|
-
pass
|
21
|
-
pasv
|
22
|
-
port
|
23
|
-
pwd
|
24
|
-
quit
|
25
|
-
size
|
26
|
-
stor
|
27
|
-
retr
|
28
|
-
rnfr
|
29
|
-
rnto
|
30
|
-
type
|
31
|
-
user
|
32
|
-
)
|
33
|
-
LNBK = "\r\n"
|
12
|
+
alias path workdir
|
34
13
|
|
35
14
|
def initialize(control_port = 21, data_port = nil, options = {})
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
@connection = nil
|
15
|
+
@port = control_port
|
16
|
+
@passive_port = data_port
|
17
|
+
@store = {}
|
18
|
+
@workdir = '/pub'
|
41
19
|
@options = options
|
42
|
-
@
|
43
|
-
|
44
|
-
@
|
20
|
+
@command_state = {}
|
21
|
+
|
22
|
+
@connection = nil
|
23
|
+
@data_server = nil
|
24
|
+
@server = nil
|
25
|
+
@client = nil
|
26
|
+
|
27
|
+
raise Errno::EADDRINUSE, port.to_s if !control_port.zero? && running?
|
28
|
+
|
29
|
+
if passive_port && !passive_port.zero? && running?(passive_port)
|
30
|
+
raise Errno::EADDRINUSE, passive_port.to_s
|
31
|
+
end
|
32
|
+
|
33
|
+
self.mode = options.fetch(:mode, :active)
|
34
|
+
self.absolute = options.fetch(:absolute, false)
|
45
35
|
end
|
46
36
|
|
47
37
|
def files
|
48
|
-
@
|
38
|
+
@store.values.map do |f|
|
39
|
+
if absolute?
|
40
|
+
abspath(f.name)
|
41
|
+
else
|
42
|
+
f.name
|
43
|
+
end
|
44
|
+
end
|
49
45
|
end
|
50
46
|
|
51
47
|
def file(name)
|
52
|
-
@
|
48
|
+
@store.values.detect do |f|
|
49
|
+
if absolute?
|
50
|
+
abspath(f.name) == name
|
51
|
+
else
|
52
|
+
f.name == name
|
53
|
+
end
|
54
|
+
end
|
53
55
|
end
|
54
56
|
|
55
57
|
def reset
|
56
|
-
@
|
58
|
+
@store.clear
|
57
59
|
end
|
58
60
|
|
59
61
|
def add_file(filename, data, last_modified_time = Time.now)
|
60
|
-
@
|
62
|
+
@store[abspath(filename)] = FakeFtp::File.new(
|
63
|
+
filename.to_s, data, options[:mode], last_modified_time
|
64
|
+
)
|
61
65
|
end
|
62
66
|
|
63
67
|
def start
|
@@ -66,20 +70,36 @@ module FakeFtp
|
|
66
70
|
@port = @server.addr[1]
|
67
71
|
@thread = Thread.new do
|
68
72
|
while @started
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
73
|
+
debug('enter client loop')
|
74
|
+
@client = begin
|
75
|
+
@server.accept
|
76
|
+
rescue => e
|
77
|
+
debug("error on accept: #{e}")
|
78
|
+
nil
|
79
|
+
end
|
80
|
+
next unless @client
|
81
|
+
respond_with('220 Can has FTP?')
|
82
|
+
@connection = Thread.new(@client) do |socket|
|
83
|
+
debug('enter request thread')
|
84
|
+
while @started && !socket.nil? && !socket.closed?
|
85
|
+
input = begin
|
86
|
+
socket.gets
|
87
|
+
rescue
|
88
|
+
debug("error on socket.gets: #{e}")
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
if input
|
92
|
+
debug("server client raw: <- #{input.inspect}")
|
93
|
+
respond_with(handle_request(input))
|
80
94
|
end
|
81
95
|
end
|
96
|
+
unless @client.nil?
|
97
|
+
@client.close unless @client.closed?
|
98
|
+
@client = nil
|
99
|
+
end
|
100
|
+
debug('leave request thread')
|
82
101
|
end
|
102
|
+
debug('leave client loop')
|
83
103
|
end
|
84
104
|
unless @server.nil?
|
85
105
|
@server.close unless @server.closed?
|
@@ -87,258 +107,110 @@ module FakeFtp
|
|
87
107
|
end
|
88
108
|
end
|
89
109
|
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
110
|
+
return unless passive_port
|
111
|
+
@data_server = ::TCPServer.new('127.0.0.1', passive_port)
|
112
|
+
@passive_port = @data_server.addr[1]
|
94
113
|
end
|
95
114
|
|
96
115
|
def stop
|
97
116
|
@started = false
|
98
|
-
@client
|
99
|
-
@server
|
117
|
+
@client&.close
|
118
|
+
@server&.close
|
100
119
|
@server = nil
|
101
|
-
@data_server
|
120
|
+
@data_server&.close
|
102
121
|
@data_server = nil
|
103
122
|
end
|
104
123
|
|
105
|
-
def
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
private
|
110
|
-
|
111
|
-
def respond_with(stuff)
|
112
|
-
@client.print stuff << LNBK unless stuff.nil? or @client.nil? or @client.closed?
|
113
|
-
end
|
114
|
-
|
115
|
-
def parse(request)
|
116
|
-
return if request.nil?
|
117
|
-
puts request if @options[:debug]
|
118
|
-
command = request[0, 4].downcase.strip
|
119
|
-
contents = request.split
|
120
|
-
message = contents[1..contents.length]
|
121
|
-
case command
|
122
|
-
when *CMDS
|
123
|
-
__send__ "_#{command}", *message
|
124
|
-
else
|
125
|
-
'500 Unknown command'
|
126
|
-
end
|
127
|
-
end
|
128
|
-
|
129
|
-
|
130
|
-
## FTP commands
|
131
|
-
#
|
132
|
-
# Methods are prefixed with an underscore to avoid conflicts with internal server
|
133
|
-
# methods. Methods map 1:1 to FTP command words.
|
134
|
-
#
|
135
|
-
def _acct(*args)
|
136
|
-
'230 WHATEVER!'
|
137
|
-
end
|
138
|
-
|
139
|
-
def _cwd(*args)
|
140
|
-
@path = args[0]
|
141
|
-
@path = "/#{path}" if path[0].chr != "/"
|
142
|
-
'250 OK!'
|
143
|
-
end
|
144
|
-
|
145
|
-
def _cdup(*args)
|
146
|
-
'250 OK!'
|
147
|
-
end
|
148
|
-
|
149
|
-
def _list(*args)
|
150
|
-
respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
|
151
|
-
|
152
|
-
respond_with('150 Listing status ok, about to open data connection')
|
153
|
-
data_client = active? ? @active_connection : @data_server.accept
|
154
|
-
|
155
|
-
wildcards = build_wildcards(args)
|
156
|
-
files = matching_files(@files, wildcards)
|
157
|
-
|
158
|
-
files = files.map do |f|
|
159
|
-
"-rw-r--r--\t1\towner\tgroup\t#{f.bytes}\t#{f.created.strftime('%b %d %H:%M')}\t#{f.name}\n"
|
160
|
-
end
|
161
|
-
data_client.write(files.join)
|
162
|
-
data_client.close
|
163
|
-
@active_connection = nil
|
164
|
-
|
165
|
-
'226 List information transferred'
|
166
|
-
end
|
167
|
-
|
168
|
-
def _mdtm(filename = '', local = false)
|
169
|
-
respond_with('501 No filename given') && return if filename.empty?
|
170
|
-
server_file = file(filename)
|
171
|
-
respond_with('550 File not found') && return if server_file.nil?
|
172
|
-
|
173
|
-
respond_with("213 #{server_file.last_modified_time.strftime("%Y%m%d%H%M%S")}")
|
124
|
+
def running?(tcp_port = nil)
|
125
|
+
return port_is_open?(port) if tcp_port.nil?
|
126
|
+
port_is_open?(tcp_port)
|
174
127
|
end
|
175
128
|
|
176
|
-
|
177
|
-
respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
|
178
|
-
|
179
|
-
respond_with('150 Listing status ok, about to open data connection')
|
180
|
-
data_client = active? ? @active_connection : @data_server.accept
|
129
|
+
alias is_running? running?
|
181
130
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
files = files.map do |file|
|
186
|
-
"#{file.name}\n"
|
131
|
+
def mode=(value)
|
132
|
+
unless %i[active passive].include?(value)
|
133
|
+
raise ArgumentError, "invalid mode #{value.inspect}"
|
187
134
|
end
|
188
|
-
|
189
|
-
data_client.write(files.join)
|
190
|
-
data_client.close
|
191
|
-
@active_connection = nil
|
192
|
-
|
193
|
-
'226 List information transferred'
|
135
|
+
options[:mode] = value
|
194
136
|
end
|
195
137
|
|
196
|
-
def
|
197
|
-
|
138
|
+
def mode
|
139
|
+
options[:mode]
|
198
140
|
end
|
199
141
|
|
200
|
-
def
|
201
|
-
|
202
|
-
@mode = :passive
|
203
|
-
p1 = (passive_port / 256).to_i
|
204
|
-
p2 = passive_port % 256
|
205
|
-
"227 Entering Passive Mode (127,0,0,1,#{p1},#{p2})"
|
206
|
-
else
|
207
|
-
'502 Aww hell no, use Active'
|
208
|
-
end
|
142
|
+
def absolute?
|
143
|
+
options[:absolute]
|
209
144
|
end
|
210
145
|
|
211
|
-
def
|
212
|
-
|
213
|
-
|
214
|
-
unless @active_connection.nil?
|
215
|
-
@active_connection.close
|
216
|
-
@active_connection = nil
|
146
|
+
def absolute=(value)
|
147
|
+
unless [true, false].include?(value)
|
148
|
+
raise ArgumentError, "invalid absolute #{value}"
|
217
149
|
end
|
218
|
-
|
219
|
-
@active_connection = ::TCPSocket.open('127.0.0.1', remote_port)
|
220
|
-
'200 Okay'
|
150
|
+
options[:absolute] = value
|
221
151
|
end
|
222
152
|
|
223
|
-
|
224
|
-
|
225
|
-
end
|
153
|
+
attr_reader :options
|
154
|
+
private :options
|
226
155
|
|
227
|
-
def
|
228
|
-
|
229
|
-
@
|
230
|
-
@client = nil
|
156
|
+
def abspath(filename)
|
157
|
+
return filename if filename.start_with?('/')
|
158
|
+
[@workdir.to_s, filename].join('/').gsub('//', '/')
|
231
159
|
end
|
232
160
|
|
233
|
-
def
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
return respond_with('550 File not found') if file.nil?
|
238
|
-
|
239
|
-
respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
|
240
|
-
|
241
|
-
respond_with('150 File status ok, about to open data connection')
|
242
|
-
data_client = active? ? @active_connection : @data_server.accept
|
243
|
-
|
244
|
-
data_client.write(file.data)
|
245
|
-
|
246
|
-
data_client.close
|
247
|
-
@active_connection = nil
|
248
|
-
'226 File transferred'
|
249
|
-
end
|
250
|
-
|
251
|
-
def _rnfr(rename_from='')
|
252
|
-
return '501 Send path name.' if rename_from.nil? || rename_from.size < 1
|
253
|
-
|
254
|
-
@rename_from = rename_from
|
255
|
-
'350 Send RNTO to complete rename.'
|
256
|
-
end
|
257
|
-
|
258
|
-
def _rnto(rename_to='')
|
259
|
-
return '501 Send path name.' if rename_to.nil? || rename_to.size < 1
|
260
|
-
|
261
|
-
return '503 Send RNFR first.' unless @rename_from
|
262
|
-
|
263
|
-
if file = file(@rename_from)
|
264
|
-
file.name = rename_to
|
265
|
-
@rename_from = nil
|
266
|
-
'250 Path renamed.'
|
267
|
-
else
|
268
|
-
@rename_from = nil
|
269
|
-
'550 File not found.'
|
270
|
-
end
|
271
|
-
end
|
272
|
-
|
273
|
-
def _size(filename)
|
274
|
-
file_size = file(filename).bytes
|
275
|
-
respond_with("213 #{file_size}")
|
276
|
-
end
|
277
|
-
|
278
|
-
def _stor(filename = '')
|
279
|
-
respond_with('425 Ain\'t no data port!') && return if active? && @active_connection.nil?
|
280
|
-
|
281
|
-
respond_with('125 Do it!')
|
282
|
-
data_client = active? ? @active_connection : @data_server.accept
|
283
|
-
|
284
|
-
data = data_client.read(nil).chomp
|
285
|
-
file = FakeFtp::File.new(::File.basename(filename.to_s), data, @mode)
|
286
|
-
@files << file
|
287
|
-
|
288
|
-
data_client.close
|
289
|
-
@active_connection = nil
|
290
|
-
'226 Did it!'
|
161
|
+
def respond_with(stuff)
|
162
|
+
return if stuff.nil? || @client.nil? || @client.closed?
|
163
|
+
debug("server client raw: -> #{stuff.inspect}")
|
164
|
+
@client.print(stuff + "\r\n")
|
291
165
|
end
|
292
166
|
|
293
|
-
def
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
167
|
+
private def handle_request(request)
|
168
|
+
return if request.nil?
|
169
|
+
debug("raw request: #{request.inspect}")
|
170
|
+
command = request[0, 4].downcase.strip
|
171
|
+
contents = request.split
|
172
|
+
message = contents[1..contents.length]
|
298
173
|
|
299
|
-
|
174
|
+
inst = load_command_instance(command)
|
175
|
+
return "500 Unknown command #{command.inspect}" if inst.nil?
|
176
|
+
debug(
|
177
|
+
"running command #{command.inspect} " \
|
178
|
+
"#{inst.class.name}#run(*#{message.inspect})"
|
179
|
+
)
|
180
|
+
inst.run(*([self] + message))
|
300
181
|
end
|
301
182
|
|
302
|
-
def
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
'200 Type set to I.'
|
308
|
-
else
|
309
|
-
'504 We don\'t allow those'
|
183
|
+
private def load_command_instance(command)
|
184
|
+
require "fake_ftp/server_commands/#{command}"
|
185
|
+
FakeFtp::ServerCommands.constants.each do |const_name|
|
186
|
+
next unless const_name.to_s.downcase == command
|
187
|
+
return FakeFtp::ServerCommands.const_get(const_name).new
|
310
188
|
end
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
end
|
316
|
-
|
317
|
-
def _mkd(directory)
|
318
|
-
"257 OK!"
|
189
|
+
nil
|
190
|
+
rescue LoadError => e
|
191
|
+
debug("failed to require #{command.inspect} class: #{e}")
|
192
|
+
nil
|
319
193
|
end
|
320
194
|
|
321
195
|
def active?
|
322
|
-
|
196
|
+
options[:mode] == :active
|
323
197
|
end
|
324
198
|
|
325
|
-
private
|
326
|
-
|
327
|
-
def port_is_open?(port)
|
199
|
+
private def port_is_open?(port)
|
328
200
|
begin
|
329
|
-
Timeout
|
201
|
+
Timeout.timeout(1) do
|
330
202
|
begin
|
331
|
-
|
332
|
-
s.close
|
203
|
+
TCPSocket.new('127.0.0.1', port).close
|
333
204
|
return true
|
334
205
|
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
335
206
|
return false
|
336
207
|
end
|
337
208
|
end
|
338
|
-
rescue Timeout::Error
|
209
|
+
rescue Timeout::Error => e
|
210
|
+
debug("timeout while checking port #{port}: #{e}")
|
339
211
|
end
|
340
212
|
|
341
|
-
|
213
|
+
false
|
342
214
|
end
|
343
215
|
|
344
216
|
def build_wildcards(args)
|
@@ -350,14 +222,19 @@ module FakeFtp
|
|
350
222
|
wildcards
|
351
223
|
end
|
352
224
|
|
353
|
-
def matching_files(
|
354
|
-
if
|
355
|
-
|
225
|
+
def matching_files(wildcards)
|
226
|
+
if !wildcards.empty?
|
227
|
+
@store.values.select do |f|
|
356
228
|
wildcards.any? { |wildcard| f.name =~ /#{wildcard}/ }
|
357
229
|
end
|
358
230
|
else
|
359
|
-
|
231
|
+
@store.values
|
360
232
|
end
|
361
233
|
end
|
234
|
+
|
235
|
+
def debug(msg)
|
236
|
+
return unless options[:debug]
|
237
|
+
$stderr.puts("DEBUG:fake_ftp:#{msg}")
|
238
|
+
end
|
362
239
|
end
|
363
240
|
end
|