ftpd 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ftpd might be problematic. Click here for more details.
- data/Changelog.md +24 -3
- data/Gemfile +2 -1
- data/Gemfile.lock +9 -2
- data/README.md +20 -9
- data/VERSION +1 -1
- data/doc/rfc.md +277 -0
- data/features/ftp_server/cdup.feature +36 -0
- data/features/ftp_server/command_errors.feature +0 -4
- data/features/ftp_server/delete.feature +1 -1
- data/features/ftp_server/directory_navigation.feature +18 -6
- data/features/ftp_server/get.feature +1 -1
- data/features/ftp_server/get_tls.feature +2 -2
- data/features/ftp_server/implicit_tls.feature +18 -0
- data/features/ftp_server/list_tls.feature +2 -2
- data/features/ftp_server/mkdir.feature +70 -0
- data/features/ftp_server/name_list_tls.feature +2 -2
- data/features/ftp_server/put.feature +1 -1
- data/features/ftp_server/put_tls.feature +2 -2
- data/features/ftp_server/rename.feature +90 -0
- data/features/ftp_server/rmdir.feature +71 -0
- data/features/ftp_server/step_definitions/debug.rb +6 -6
- data/features/ftp_server/step_definitions/test_server.rb +3 -2
- data/features/step_definitions/connect.rb +4 -3
- data/features/step_definitions/{directories.rb → directory_navigation.rb} +4 -0
- data/features/step_definitions/error_replies.rb +5 -5
- data/features/step_definitions/login.rb +2 -2
- data/features/step_definitions/mkdir.rb +9 -0
- data/features/step_definitions/rename.rb +11 -0
- data/features/step_definitions/rmdir.rb +9 -0
- data/features/step_definitions/server_files.rb +9 -0
- data/features/support/test_client.rb +19 -5
- data/features/support/test_server.rb +28 -3
- data/features/support/test_server_files.rb +5 -0
- data/ftpd.gemspec +17 -6
- data/lib/ftpd.rb +1 -0
- data/lib/ftpd/disk_file_system.rb +97 -16
- data/lib/ftpd/error.rb +16 -0
- data/lib/ftpd/exception_translator.rb +1 -1
- data/lib/ftpd/exceptions.rb +10 -4
- data/lib/ftpd/file_system_error_translator.rb +8 -4
- data/lib/ftpd/ftp_server.rb +1 -0
- data/lib/ftpd/session.rb +98 -87
- data/rake_tasks/yard.rake +1 -0
- data/spec/disk_file_system_spec.rb +55 -8
- data/spec/exception_translator_spec.rb +1 -1
- data/spec/file_system_error_translator_spec.rb +20 -4
- data/spec/translate_exceptions_spec.rb +1 -1
- metadata +32 -7
- data/sandbox/em-server.rb +0 -37
@@ -13,10 +13,6 @@ Then /^the server returns a "(.*?)" error$/ do |error_message|
|
|
13
13
|
(@error || '').should include error_message
|
14
14
|
end
|
15
15
|
|
16
|
-
Then /^the server returns a no such file error$/ do
|
17
|
-
step 'the server returns a "550 No such file or directory" error'
|
18
|
-
end
|
19
|
-
|
20
16
|
Then /^the server returns a not a directory error$/ do
|
21
17
|
step 'the server returns a "550 Not a directory" error'
|
22
18
|
end
|
@@ -90,5 +86,9 @@ Then /^the server returns an unimplemented command error$/ do
|
|
90
86
|
end
|
91
87
|
|
92
88
|
Then /^the server returns an action not taken error$/ do
|
93
|
-
step 'the server returns a "
|
89
|
+
step 'the server returns a "550 Unable to do it" error'
|
90
|
+
end
|
91
|
+
|
92
|
+
Then /^the server returns an already exists error$/ do
|
93
|
+
step 'the server returns a "550 Already exists" error'
|
94
94
|
end
|
@@ -9,11 +9,11 @@ def login(user, password, client_name = nil)
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
Given /^a successful connection( with TLS)?$/ do |with_tls|
|
12
|
+
Given /^a successful connection( with \w+ TLS)?$/ do |with_tls|
|
13
13
|
step "the client connects#{with_tls}"
|
14
14
|
end
|
15
15
|
|
16
|
-
Given /^a successful login( with TLS)?$/ do |with_tls|
|
16
|
+
Given /^a successful login( with \w+ TLS)?$/ do |with_tls|
|
17
17
|
step "a successful connection#{with_tls}"
|
18
18
|
step 'the client logs in'
|
19
19
|
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
When /^the client renames "(.*?)" to "(.*?)"$/ do
|
2
|
+
|from_path, to_path|
|
3
|
+
capture_error do
|
4
|
+
step %Q'the client successfully renames "#{from_path}" to "#{to_path}"'
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
When /^the client successfully renames "(.*?)" to "(.*?)"$/ do
|
9
|
+
|from_path, to_path|
|
10
|
+
@client.rename(from_path, to_path)
|
11
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
When /^the client removes directory "(.*?)"$/ do |path|
|
2
|
+
capture_error do
|
3
|
+
step %Q(the client successfully removes directory "#{path}")
|
4
|
+
end
|
5
|
+
end
|
6
|
+
|
7
|
+
When /^the client successfully removes directory "(.*?)"$/ do |path|
|
8
|
+
mkdir_response = @client.rmdir path
|
9
|
+
end
|
@@ -15,6 +15,15 @@ Then /^the server should( not)? have file "(.*?)"$/ do |neg, path|
|
|
15
15
|
@server.has_file?(path).should send(matcher)
|
16
16
|
end
|
17
17
|
|
18
|
+
Then /^the server should( not)? have directory "(.*?)"$/ do |neg, path|
|
19
|
+
matcher = if neg
|
20
|
+
:be_false
|
21
|
+
else
|
22
|
+
:be_true
|
23
|
+
end
|
24
|
+
@server.has_directory?(path).should send(matcher)
|
25
|
+
end
|
26
|
+
|
18
27
|
Then /^the remote file "(.*?)" should have (unix|windows) line endings$/ do
|
19
28
|
|remote_path, line_ending_type|
|
20
29
|
line_ending_type(@server.file_contents(remote_path)).should ==
|
@@ -24,10 +24,13 @@ class TestClient
|
|
24
24
|
:gettextfile,
|
25
25
|
:login,
|
26
26
|
:ls,
|
27
|
+
:mkdir,
|
27
28
|
:nlst,
|
28
29
|
:noop,
|
29
30
|
:passive=,
|
30
31
|
:pwd,
|
32
|
+
:rename,
|
33
|
+
:rmdir,
|
31
34
|
:quit,
|
32
35
|
:system
|
33
36
|
|
@@ -57,6 +60,11 @@ class TestClient
|
|
57
60
|
File.open(temp_path(path), 'rb', &:read)
|
58
61
|
end
|
59
62
|
|
63
|
+
def xpwd
|
64
|
+
response = raw('XPWD')
|
65
|
+
response[/"(.+)"/, 1]
|
66
|
+
end
|
67
|
+
|
60
68
|
private
|
61
69
|
|
62
70
|
RAW_METHOD_REGEX = /^send_(.*)$/
|
@@ -70,20 +78,26 @@ class TestClient
|
|
70
78
|
end
|
71
79
|
|
72
80
|
def make_ftp(opts)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
else
|
81
|
+
tls_mode = opts[:tls] || :off
|
82
|
+
case tls_mode
|
83
|
+
when :off
|
77
84
|
make_non_tls_ftp
|
85
|
+
when :implicit
|
86
|
+
make_tls_ftp(:implicit)
|
87
|
+
when :explicit
|
88
|
+
make_tls_ftp(:explicit)
|
89
|
+
else
|
90
|
+
raise "Unknown TLS mode: #{tls_mode}"
|
78
91
|
end
|
79
92
|
end
|
80
93
|
|
81
|
-
def make_tls_ftp
|
94
|
+
def make_tls_ftp(ftps_mode)
|
82
95
|
ftp = DoubleBagFTPS.new
|
83
96
|
context_opts = {
|
84
97
|
:verify_mode => OpenSSL::SSL::VERIFY_NONE
|
85
98
|
}
|
86
99
|
ftp.ssl_context = DoubleBagFTPS.create_ssl_context(context_opts)
|
100
|
+
ftp.ftps_mode = ftps_mode
|
87
101
|
ftp
|
88
102
|
end
|
89
103
|
|
@@ -15,16 +15,22 @@ class TestServer
|
|
15
15
|
|
16
16
|
attr_accessor :delete
|
17
17
|
attr_accessor :list
|
18
|
+
attr_accessor :mkdir
|
18
19
|
attr_accessor :name_list
|
19
20
|
attr_accessor :read
|
21
|
+
attr_accessor :rename
|
22
|
+
attr_accessor :rmdir
|
20
23
|
attr_accessor :write
|
21
24
|
|
22
25
|
def initialize(temp_dir)
|
23
26
|
@temp_dir = temp_dir
|
24
27
|
@delete = true
|
25
28
|
@list = true
|
29
|
+
@mkdir = true
|
26
30
|
@name_list = true
|
27
31
|
@read = true
|
32
|
+
@rename = true
|
33
|
+
@rmdir = true
|
28
34
|
@write = true
|
29
35
|
end
|
30
36
|
|
@@ -36,8 +42,11 @@ class TestServer
|
|
36
42
|
TestServerFileSystem.new(@temp_dir,
|
37
43
|
:delete => @delete,
|
38
44
|
:list => @list,
|
45
|
+
:mkdir => @mkdir,
|
39
46
|
:name_list => @name_list,
|
40
47
|
:read => @read,
|
48
|
+
:rename => @rename,
|
49
|
+
:rmdir => @rmdir,
|
41
50
|
:write => @write)
|
42
51
|
end
|
43
52
|
|
@@ -88,7 +97,7 @@ class TestServer
|
|
88
97
|
define_method method_name do |*args|
|
89
98
|
ftp_path = args.first
|
90
99
|
if force_file_system_error?(ftp_path)
|
91
|
-
raise Ftpd::
|
100
|
+
raise Ftpd::PermanentFileSystemError, 'Unable to do it'
|
92
101
|
end
|
93
102
|
original_method.bind(self).call *args
|
94
103
|
end
|
@@ -142,11 +151,24 @@ class TestServer
|
|
142
151
|
include Ftpd::DiskFileSystem::NameList
|
143
152
|
end
|
144
153
|
|
154
|
+
if opts[:mkdir]
|
155
|
+
include Ftpd::DiskFileSystem::Mkdir
|
156
|
+
end
|
157
|
+
|
145
158
|
if opts[:read]
|
146
159
|
include Ftpd::DiskFileSystem::Read
|
147
160
|
raise_on_file_system_error :read
|
148
161
|
end
|
149
162
|
|
163
|
+
if opts[:rename]
|
164
|
+
include Ftpd::DiskFileSystem::Rename
|
165
|
+
raise_on_file_system_error :rename
|
166
|
+
end
|
167
|
+
|
168
|
+
if opts[:rmdir]
|
169
|
+
include Ftpd::DiskFileSystem::Rmdir
|
170
|
+
end
|
171
|
+
|
150
172
|
if opts[:write]
|
151
173
|
include Ftpd::DiskFileSystem::Write
|
152
174
|
raise_on_file_system_error :write
|
@@ -195,8 +217,11 @@ class TestServer
|
|
195
217
|
|
196
218
|
def_delegator :@driver, :'delete='
|
197
219
|
def_delegator :@driver, :'list='
|
220
|
+
def_delegator :@driver, :'mkdir='
|
198
221
|
def_delegator :@driver, :'name_list='
|
222
|
+
def_delegator :@driver, :'rmdir='
|
199
223
|
def_delegator :@driver, :'read='
|
224
|
+
def_delegator :@driver, :'rename='
|
200
225
|
def_delegator :@driver, :'write='
|
201
226
|
|
202
227
|
def start
|
@@ -207,8 +232,8 @@ class TestServer
|
|
207
232
|
@server.stop
|
208
233
|
end
|
209
234
|
|
210
|
-
def
|
211
|
-
|
235
|
+
def debug_output
|
236
|
+
IO.read(@debug_file.path)
|
212
237
|
end
|
213
238
|
|
214
239
|
def host
|
@@ -18,6 +18,11 @@ module TestServerFiles
|
|
18
18
|
File.exists?(full_path)
|
19
19
|
end
|
20
20
|
|
21
|
+
def has_directory?(path)
|
22
|
+
full_path = temp_path(path)
|
23
|
+
File.directory?(full_path)
|
24
|
+
end
|
25
|
+
|
21
26
|
def file_contents(path)
|
22
27
|
full_path = temp_path(path)
|
23
28
|
File.open(full_path, 'rb', &:read)
|
data/ftpd.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = "ftpd"
|
8
|
-
s.version = "0.2.
|
8
|
+
s.version = "0.2.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Wayne Conrad"]
|
12
|
-
s.date = "2013-02-
|
13
|
-
s.description = "ftpd is a pure Ruby FTP server library. It supports implicit and explicit TLS, and
|
12
|
+
s.date = "2013-02-28"
|
13
|
+
s.description = "ftpd is a pure Ruby FTP server library. It supports implicit and explicit TLS, passive and active mode, and most of the commands specified in RFC 969. It an be used as part of a test fixture or embedded in a program."
|
14
14
|
s.email = "wconrad@yagni.com"
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE.md",
|
@@ -24,11 +24,13 @@ Gem::Specification.new do |s|
|
|
24
24
|
"README.md",
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
|
+
"doc/rfc.md",
|
27
28
|
"examples/example.rb",
|
28
29
|
"examples/hello_world.rb",
|
29
30
|
"features/example/example.feature",
|
30
31
|
"features/example/step_definitions/example_server.rb",
|
31
32
|
"features/ftp_server/allo.feature",
|
33
|
+
"features/ftp_server/cdup.feature",
|
32
34
|
"features/ftp_server/command_errors.feature",
|
33
35
|
"features/ftp_server/concurrent_sessions.feature",
|
34
36
|
"features/ftp_server/debug.feature",
|
@@ -37,9 +39,11 @@ Gem::Specification.new do |s|
|
|
37
39
|
"features/ftp_server/file_structure.feature",
|
38
40
|
"features/ftp_server/get.feature",
|
39
41
|
"features/ftp_server/get_tls.feature",
|
42
|
+
"features/ftp_server/implicit_tls.feature",
|
40
43
|
"features/ftp_server/list.feature",
|
41
44
|
"features/ftp_server/list_tls.feature",
|
42
45
|
"features/ftp_server/login.feature",
|
46
|
+
"features/ftp_server/mkdir.feature",
|
43
47
|
"features/ftp_server/mode.feature",
|
44
48
|
"features/ftp_server/name_list.feature",
|
45
49
|
"features/ftp_server/name_list_tls.feature",
|
@@ -48,6 +52,8 @@ Gem::Specification.new do |s|
|
|
48
52
|
"features/ftp_server/put.feature",
|
49
53
|
"features/ftp_server/put_tls.feature",
|
50
54
|
"features/ftp_server/quit.feature",
|
55
|
+
"features/ftp_server/rename.feature",
|
56
|
+
"features/ftp_server/rmdir.feature",
|
51
57
|
"features/ftp_server/step_definitions/debug.rb",
|
52
58
|
"features/ftp_server/step_definitions/test_server.rb",
|
53
59
|
"features/ftp_server/syntax_errors.feature",
|
@@ -59,7 +65,7 @@ Gem::Specification.new do |s|
|
|
59
65
|
"features/step_definitions/command.rb",
|
60
66
|
"features/step_definitions/connect.rb",
|
61
67
|
"features/step_definitions/delete.rb",
|
62
|
-
"features/step_definitions/
|
68
|
+
"features/step_definitions/directory_navigation.rb",
|
63
69
|
"features/step_definitions/error_replies.rb",
|
64
70
|
"features/step_definitions/file_structure.rb",
|
65
71
|
"features/step_definitions/generic_send.rb",
|
@@ -68,12 +74,15 @@ Gem::Specification.new do |s|
|
|
68
74
|
"features/step_definitions/line_endings.rb",
|
69
75
|
"features/step_definitions/list.rb",
|
70
76
|
"features/step_definitions/login.rb",
|
77
|
+
"features/step_definitions/mkdir.rb",
|
71
78
|
"features/step_definitions/mode.rb",
|
72
79
|
"features/step_definitions/noop.rb",
|
73
80
|
"features/step_definitions/passive.rb",
|
74
81
|
"features/step_definitions/port.rb",
|
75
82
|
"features/step_definitions/put.rb",
|
76
83
|
"features/step_definitions/quit.rb",
|
84
|
+
"features/step_definitions/rename.rb",
|
85
|
+
"features/step_definitions/rmdir.rb",
|
77
86
|
"features/step_definitions/server_files.rb",
|
78
87
|
"features/step_definitions/stop_server.rb",
|
79
88
|
"features/step_definitions/success_replies.rb",
|
@@ -109,7 +118,6 @@ Gem::Specification.new do |s|
|
|
109
118
|
"rake_tasks/spec.rake",
|
110
119
|
"rake_tasks/test.rake",
|
111
120
|
"rake_tasks/yard.rake",
|
112
|
-
"sandbox/em-server.rb",
|
113
121
|
"spec/disk_file_system_spec.rb",
|
114
122
|
"spec/exception_translator_spec.rb",
|
115
123
|
"spec/file_system_error_translator_spec.rb",
|
@@ -119,7 +127,7 @@ Gem::Specification.new do |s|
|
|
119
127
|
s.homepage = "http://github.com/wconrad/ftpd"
|
120
128
|
s.licenses = ["MIT"]
|
121
129
|
s.require_paths = ["lib"]
|
122
|
-
s.rubygems_version = "1.8.
|
130
|
+
s.rubygems_version = "1.8.24"
|
123
131
|
s.summary = "Pure Ruby FTP server library"
|
124
132
|
|
125
133
|
if s.respond_to? :specification_version then
|
@@ -131,6 +139,7 @@ Gem::Specification.new do |s|
|
|
131
139
|
s.add_development_dependency(%q<double-bag-ftps>, [">= 0"])
|
132
140
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
133
141
|
s.add_development_dependency(%q<rake>, [">= 0"])
|
142
|
+
s.add_development_dependency(%q<redcarpet>, [">= 0"])
|
134
143
|
s.add_development_dependency(%q<rspec>, [">= 0"])
|
135
144
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
136
145
|
else
|
@@ -139,6 +148,7 @@ Gem::Specification.new do |s|
|
|
139
148
|
s.add_dependency(%q<double-bag-ftps>, [">= 0"])
|
140
149
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
141
150
|
s.add_dependency(%q<rake>, [">= 0"])
|
151
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
142
152
|
s.add_dependency(%q<rspec>, [">= 0"])
|
143
153
|
s.add_dependency(%q<yard>, [">= 0"])
|
144
154
|
end
|
@@ -148,6 +158,7 @@ Gem::Specification.new do |s|
|
|
148
158
|
s.add_dependency(%q<double-bag-ftps>, [">= 0"])
|
149
159
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
150
160
|
s.add_dependency(%q<rake>, [">= 0"])
|
161
|
+
s.add_dependency(%q<redcarpet>, [">= 0"])
|
151
162
|
s.add_dependency(%q<rspec>, [">= 0"])
|
152
163
|
s.add_dependency(%q<yard>, [">= 0"])
|
153
164
|
end
|
data/lib/ftpd.rb
CHANGED
@@ -10,6 +10,7 @@ module Ftpd
|
|
10
10
|
autoload :Error, 'ftpd/error'
|
11
11
|
autoload :ExceptionTranslator, 'ftpd/exception_translator'
|
12
12
|
autoload :FileSystemErrorTranslator, 'ftpd/file_system_error_translator'
|
13
|
+
autoload :FileSystemMethodMissing, 'ftpd/file_system_method_missing'
|
13
14
|
autoload :FtpServer, 'ftpd/ftp_server'
|
14
15
|
autoload :InsecureCertificate, 'ftpd/insecure_certificate'
|
15
16
|
autoload :Server, 'ftpd/server'
|
@@ -17,8 +17,8 @@ module Ftpd
|
|
17
17
|
# Expand an ftp_path to an absolute file system path.
|
18
18
|
#
|
19
19
|
# ftp_path is an absolute path relative to the FTP file system.
|
20
|
-
#
|
21
|
-
#
|
20
|
+
# The return value is an absolute path relative to the disk file
|
21
|
+
# system.
|
22
22
|
|
23
23
|
def expand_ftp_path(ftp_path)
|
24
24
|
File.expand_path(File.join(@data_dir, ftp_path))
|
@@ -44,6 +44,8 @@ module Ftpd
|
|
44
44
|
# * RETR
|
45
45
|
# * DELE
|
46
46
|
# * CWD
|
47
|
+
# * MKD
|
48
|
+
# * RMD
|
47
49
|
|
48
50
|
def accessible?(ftp_path)
|
49
51
|
# The server should never try to access a path outside of the
|
@@ -59,6 +61,7 @@ module Ftpd
|
|
59
61
|
# * RETR
|
60
62
|
# * DELE
|
61
63
|
# * CWD
|
64
|
+
# * MKD
|
62
65
|
|
63
66
|
def exists?(ftp_path)
|
64
67
|
File.exists?(expand_ftp_path(ftp_path))
|
@@ -68,6 +71,7 @@ module Ftpd
|
|
68
71
|
#
|
69
72
|
# Called for:
|
70
73
|
# * CWD
|
74
|
+
# * MKD
|
71
75
|
|
72
76
|
def directory?(ftp_path)
|
73
77
|
File.directory?(expand_ftp_path(ftp_path))
|
@@ -84,7 +88,7 @@ module Ftpd
|
|
84
88
|
|
85
89
|
include TranslateExceptions
|
86
90
|
|
87
|
-
# Remove a file.
|
91
|
+
# Remove a file.
|
88
92
|
#
|
89
93
|
# Called for:
|
90
94
|
# * DELE
|
@@ -107,7 +111,7 @@ module Ftpd
|
|
107
111
|
|
108
112
|
include TranslateExceptions
|
109
113
|
|
110
|
-
# Read a file into memory.
|
114
|
+
# Read a file into memory.
|
111
115
|
#
|
112
116
|
# Called for:
|
113
117
|
# * RETR
|
@@ -130,7 +134,7 @@ module Ftpd
|
|
130
134
|
|
131
135
|
include TranslateExceptions
|
132
136
|
|
133
|
-
# Write a file to disk.
|
137
|
+
# Write a file to disk.
|
134
138
|
#
|
135
139
|
# Called for:
|
136
140
|
# * STOR
|
@@ -147,6 +151,54 @@ module Ftpd
|
|
147
151
|
end
|
148
152
|
end
|
149
153
|
|
154
|
+
class DiskFileSystem
|
155
|
+
|
156
|
+
# DiskFileSystem mixing providing mkdir
|
157
|
+
|
158
|
+
module Mkdir
|
159
|
+
|
160
|
+
include TranslateExceptions
|
161
|
+
|
162
|
+
# Create a directory.
|
163
|
+
#
|
164
|
+
# Called for:
|
165
|
+
# * MKD
|
166
|
+
#
|
167
|
+
# If missing, then these commands are not supported.
|
168
|
+
|
169
|
+
def mkdir(ftp_path)
|
170
|
+
Dir.mkdir expand_ftp_path(ftp_path)
|
171
|
+
end
|
172
|
+
translate_exceptions :mkdir
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
class DiskFileSystem
|
179
|
+
|
180
|
+
# DiskFileSystem mixing providing mkdir
|
181
|
+
|
182
|
+
module Rmdir
|
183
|
+
|
184
|
+
include TranslateExceptions
|
185
|
+
|
186
|
+
# Remove a directory.
|
187
|
+
#
|
188
|
+
# Called for:
|
189
|
+
# * RMD
|
190
|
+
#
|
191
|
+
# If missing, then these commands are not supported.
|
192
|
+
|
193
|
+
def rmdir(ftp_path)
|
194
|
+
Dir.rmdir expand_ftp_path(ftp_path)
|
195
|
+
end
|
196
|
+
translate_exceptions :rmdir
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
|
150
202
|
class DiskFileSystem
|
151
203
|
|
152
204
|
# Ls interface used by List and NameList
|
@@ -186,10 +238,10 @@ module Ftpd
|
|
186
238
|
|
187
239
|
include TranslateExceptions
|
188
240
|
|
189
|
-
# Get a file list, long form.
|
190
|
-
#
|
191
|
-
#
|
192
|
-
#
|
241
|
+
# Get a file list, long form. This returns a long-form
|
242
|
+
# directory listing. The FTP standard does not specify the
|
243
|
+
# format of the listing, but many systems emit a *nix style
|
244
|
+
# directory listing:
|
193
245
|
#
|
194
246
|
# -rw-r--r-- 1 wayne wayne 4 Feb 18 18:36 a
|
195
247
|
# -rw-r--r-- 1 wayne wayne 8 Feb 18 18:36 b
|
@@ -234,7 +286,7 @@ module Ftpd
|
|
234
286
|
|
235
287
|
include Ls
|
236
288
|
|
237
|
-
# Get a file list, short form.
|
289
|
+
# Get a file list, short form.
|
238
290
|
#
|
239
291
|
# This returns one filename per line, and nothing else
|
240
292
|
#
|
@@ -250,6 +302,30 @@ module Ftpd
|
|
250
302
|
end
|
251
303
|
end
|
252
304
|
|
305
|
+
class DiskFileSystem
|
306
|
+
|
307
|
+
# DiskFileSystem mixin providing file/directory rename/move
|
308
|
+
|
309
|
+
module Rename
|
310
|
+
|
311
|
+
include TranslateExceptions
|
312
|
+
|
313
|
+
# Rename or move a file or directory
|
314
|
+
#
|
315
|
+
# Called for:
|
316
|
+
# * RNTO
|
317
|
+
#
|
318
|
+
# If missing, then these commands are not supported.
|
319
|
+
|
320
|
+
def rename(from_ftp_path, to_ftp_path)
|
321
|
+
FileUtils.mv(expand_ftp_path(from_ftp_path),
|
322
|
+
expand_ftp_path(to_ftp_path))
|
323
|
+
end
|
324
|
+
translate_exceptions :rename
|
325
|
+
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
253
329
|
class DiskFileSystem
|
254
330
|
|
255
331
|
# DiskFileSystem "omnibus" mixin, which pulls in mixins which are
|
@@ -266,15 +342,17 @@ module Ftpd
|
|
266
342
|
# An FTP file system mapped to a disk directory. This can serve as
|
267
343
|
# a template for creating your own specialized driver.
|
268
344
|
#
|
269
|
-
#
|
270
|
-
#
|
271
|
-
#
|
272
|
-
#
|
345
|
+
# Any method may raise a PermanentFileSystemError (e.g. "file not
|
346
|
+
# found") or TransientFileSystemError (e.g. "file busy"). A
|
347
|
+
# PermanentFileSystemError will cause a "550" error response to be
|
348
|
+
# sent; a TransientFileSystemError will cause a "450" error response
|
349
|
+
# to be sent.
|
273
350
|
#
|
274
351
|
# The class is divided into modules that may be included piecemeal.
|
275
352
|
# By including some mixins and not others, you can compose a disk
|
276
|
-
# file system driver "a la
|
277
|
-
# server that, for example, allows reading but not writing
|
353
|
+
# file system driver "a la carte." This is useful if you want an
|
354
|
+
# FTP server that, for example, allows reading but not writing
|
355
|
+
# files.
|
278
356
|
|
279
357
|
class DiskFileSystem
|
280
358
|
|
@@ -286,8 +364,11 @@ module Ftpd
|
|
286
364
|
|
287
365
|
include DiskFileSystem::Delete
|
288
366
|
include DiskFileSystem::List
|
367
|
+
include DiskFileSystem::Mkdir
|
289
368
|
include DiskFileSystem::NameList
|
290
369
|
include DiskFileSystem::Read
|
370
|
+
include DiskFileSystem::Rename
|
371
|
+
include DiskFileSystem::Rmdir
|
291
372
|
include DiskFileSystem::Write
|
292
373
|
|
293
374
|
# Make a new instance to serve a directory. data_dir should be an
|