Class: Net::FTP
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Protocol
|
|
Instance Chain:
self,
SSL,
OpenSSL,
MonitorMixin,
Protocol
|
|
Inherits: |
Protocol
|
Defined in: | lib/net/ftp.rb |
Overview
This class implements the File Transfer Protocol. If you have used a command-line FTP
program, and are familiar with the commands, you will be able to use this class easily. Some extra features are included to take advantage of Ruby's style and strengths.
Example
require 'net/ftp'
Example 1
ftp = Net::FTP.new('example.com')
ftp.login
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
ftp.close
Example 2
Net::FTP.open('example.com') do |ftp|
ftp.login
files = ftp.chdir('pub/lang/ruby/contrib')
files = ftp.list('n*')
ftp.getbinaryfile('nif.rb-0.91.gz', 'nif.gz', 1024)
end
Major Methods
The following are the methods most likely to be useful to users:
Constant Summary
-
CASE_DEPENDENT_PARSER =
# File 'lib/net/ftp.rb', line 1036->(value) { value }
-
CASE_INDEPENDENT_PARSER =
# File 'lib/net/ftp.rb', line 1037->(value) { value.downcase }
-
CRLF =
Internal use only
# File 'lib/net/ftp.rb', line 89"\r\n"
-
DECIMAL_PARSER =
# File 'lib/net/ftp.rb', line 1038->(value) { value.to_i }
-
DEFAULT_BLOCKSIZE =
Internal use only
# File 'lib/net/ftp.rb', line 90BufferedIO::BUFSIZE
-
FACT_PARSERS =
# File 'lib/net/ftp.rb', line 1049Hash.new(CASE_DEPENDENT_PARSER)
-
FTP_PORT =
Internal use only
# File 'lib/net/ftp.rb', line 8821
-
OCTAL_PARSER =
# File 'lib/net/ftp.rb', line 1039->(value) { value.to_i(8) }
-
TIME_PARSER =
# File 'lib/net/ftp.rb', line 1040->(value, local = false) { unless /\A(?<year>\d{4})(?<month>\d{2})(?<day>\d{2}) (?<hour>\d{2})(?<min>\d{2})(?<sec>\d{2}) (\.(?<fractions>\d+))?/x =~ value raise FTPProtoError, "invalid time-val: #{value}" end usec = fractions.to_i * 10 ** (6 - fractions.to_s.size) Time.send(local ? :local : :utc, year, month, day, hour, min, sec, usec) }
Class Attribute Summary
-
.default_passive
rw
When
true
, connections are in passive mode per default. -
.default_passive=(value)
rw
When
true
, connections are in passive mode per default.
Class Method Summary
-
.new(host = nil, options = {}) ⇒ FTP
constructor
Creates and returns a new
FTP
object. -
.open(host, *args)
A synonym for .new, but with a mandatory host parameter.
Instance Attribute Summary
-
#binary
rw
When
true
, transfers are performed in binary mode. -
#binary=(newmode)
rw
A setter to toggle transfers in binary mode.
-
#closed? ⇒ Boolean
readonly
Returns
true
iff the connection is closed. -
#debug_mode
rw
When
true
, all traffic to and from the server is written to $stdout. -
#last_response
readonly
The server's last response.
-
#last_response_code
(also: #lastresp)
readonly
The server's last response code.
-
#lastresp
readonly
Alias for #last_response_code.
-
#open_timeout
rw
Number of seconds to wait for the connection to open.
-
#passive
rw
When
true
, the connection is in passive mode. -
#read_timeout
rw
Number of seconds to wait for one block to be read (via one read(2) call).
-
#read_timeout=(sec)
rw
Setter for the read_timeout attribute.
-
#resume
rw
Sets or retrieves the
resume
status, which decides whether incomplete transfers are resumed or restarted. -
#ssl_handshake_timeout
rw
Number of seconds to wait for the TLS handshake.
-
#welcome
readonly
The server's welcome message.
-
#return_code
rw
Internal use only
Obsolete.
-
#return_code=(s)
rw
Internal use only
Obsolete.
Instance Method Summary
-
#abort
Aborts the previous command (ABOR command).
-
#acct(account)
Sends the ACCT command.
-
#chdir(dirname)
Changes the (remote) directory.
-
#close
Closes the connection.
-
#connect(host, port = FTP_PORT)
Establishes an
FTP
connection to host, optionally overriding the default port. -
#delete(filename)
Deletes a file on the server.
-
#dir(*args, &block)
Alias for #list.
-
#get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)
Retrieves
remotefile
in whatever mode the session is set (text or binary). -
#getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)
Retrieves
remotefile
in binary mode, storing the result inlocalfile
. -
#getdir
Alias for #pwd.
-
#gettextfile(remotefile, localfile = File.basename(remotefile), &block)
Retrieves
remotefile
in ASCII (text) mode, storing the result inlocalfile
. -
#help(arg = nil)
Issues the HELP command.
-
#list(*args, &block)
(also: #ls, #dir)
Returns an array of file information in the directory (the output is like `ls -l`).
-
#login(user = "anonymous", passwd = nil, acct = nil)
Logs in to the remote host.
-
#ls(*args, &block)
Alias for #list.
-
#mdtm(filename)
Returns the raw last modification time of the (remote) file in the format “YYYYMMDDhhmmss” (MDTM command).
-
#mkdir(dirname)
Creates a remote directory.
-
#mlsd(pathname = nil, &block)
Returns an array of the entries of the directory specified by
pathname
. -
#mlst(pathname = nil)
Returns data (e.g., size, last modification time, entry type, etc.) about the file or directory specified by
pathname
. -
#mtime(filename, local = false)
Returns the last modification time of the (remote) file.
-
#nlst(dir = nil)
Returns an array of filenames in the remote directory.
-
#noop
Issues a NOOP command.
-
#put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)
Transfers
localfile
to the server in whatever mode the session is set (text or binary). -
#putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)
Transfers
localfile
to the server in binary mode, storing the result inremotefile
. -
#puttextfile(localfile, remotefile = File.basename(localfile), &block)
Transfers
localfile
to the server in ASCII (text) mode, storing the result inremotefile
. -
#pwd
(also: #getdir)
Returns the current remote directory.
-
#quit
Exits the
FTP
session. -
#rename(fromname, toname)
Renames a file on the server.
-
#retrbinary(cmd, blocksize, rest_offset = nil)
Puts the connection into binary (image) mode, issues the given command, and fetches the data returned, passing it to the associated block in chunks of
blocksize
characters. -
#retrlines(cmd)
Puts the connection into ASCII (text) mode, issues the given command, and passes the resulting data, one line at a time, to the associated block.
-
#rmdir(dirname)
Removes a remote directory.
-
#sendcmd(cmd)
Sends a command and returns the response.
-
#set_socket(sock, get_greeting = true)
Set the socket used to connect to the
FTP
server. -
#site(arg)
Issues a SITE command.
-
#size(filename)
Returns the size of the given (remote) filename.
-
#status(pathname = nil)
Returns the status (STAT command).
-
#storbinary(cmd, file, blocksize, rest_offset = nil)
Puts the connection into binary (image) mode, issues the given server-side command (such as “STOR myfile”), and sends the contents of the file named
file
to the server. -
#storlines(cmd, file)
Puts the connection into ASCII (text) mode, issues the given server-side command (such as “STOR myfile”), and sends the contents of the file named
file
to the server, one line at a time. -
#system
Returns system information.
-
#voidcmd(cmd)
Sends a command and expect a response beginning with '2'.
- #parse_mlsx_entry(entry) private
- #parse_pasv_ipv4_host(s) private
- #parse_pasv_ipv6_host(s) private
- #parse_pasv_port(s) private
- #start_tls_session(sock) private
- #get_body(resp) private Internal use only
-
#getline
private
Internal use only
Reads a line from the sock.
-
#getmultiline
private
Internal use only
Receive a section of lines until the response code's match.
-
#getresp
private
Internal use only
Receives a response from the destination host.
-
#makepasv
private
Internal use only
sends the appropriate command to enable a passive connection.
-
#makeport
private
Internal use only
Constructs a TCPServer socket.
-
#open_socket(host, port)
private
Internal use only
Constructs a socket with
host
andport
. -
#parse227(resp)
private
Internal use only
handler for response code 227 (Entering Passive Mode (h1,h2,h3,h4,p1,p2)).
-
#parse228(resp)
private
Internal use only
handler for response code 228 (Entering Long Passive Mode).
-
#parse229(resp)
private
Internal use only
handler for response code 229 (Extended Passive Mode Entered).
-
#parse257(resp)
private
Internal use only
handler for response code 257 (“PATHNAME” created).
-
#putline(line)
private
Internal use only
Ensures that
line
has a control return / line feed (CRLF) and writes it to the socket. -
#sanitize(s)
private
Internal use only
If string
s
includes the PASS command (password), then the contents of the password are cleaned from the string using “*”. -
#send_type_command
private
Internal use only
Sends a command to destination host, with the current binary sendmode type.
-
#sendport(host, port)
private
Internal use only
Constructs and send the appropriate PORT (or EPRT) command.
-
#transfercmd(cmd, rest_offset = nil)
private
Internal use only
Constructs a connection for transferring data.
-
#voidresp
private
Internal use only
Receives a response.
-
#with_binary(newmode)
private
Internal use only
Toggles transfers in binary mode and yields to a block.
Constructor Details
.new(host = nil, options = {}) ⇒ FTP
Creates and returns a new FTP
object. If a host
is given, a connection is made.
options
is an option hash, each key of which is a symbol.
The available options are:
- port
-
Port number (default value is 21)
- ssl
-
If options is true, then an attempt will be made to use SSL (now TLS) to connect to the server. For this to work OpenSSL [OSSL] and the Ruby OpenSSL [RSSL] extensions need to be installed. If options is a hash, it's passed to OpenSSL::SSL::SSLContext#set_params as parameters.
- private_data_connection
-
If true, TLS is used for data connections. Default:
true
when options is true. - username
-
Username for login. If options is the string “anonymous” and the options is
nil
, “anonymous@” is used as a password. - password
-
Password for login.
- account
-
Account information for ACCT.
- passive
-
When
true
, the connection is in passive mode. Default:true
. - open_timeout
-
Number of seconds to wait for the connection to open. See Net::FTP#open_timeout for details. Default:
nil
. - read_timeout
-
Number of seconds to wait for one block to be read. See Net::FTP#read_timeout for details. Default:
60
. - ssl_handshake_timeout
-
Number of seconds to wait for the TLS handshake. See Net::FTP#ssl_handshake_timeout for details. Default:
nil
. - debug_mode
-
When
true
, all traffic to and from the server is written to $stdout. Default:false
.
# File 'lib/net/ftp.rb', line 211
def initialize(host = nil, = {}, passwd = nil, acct = nil) super() begin = .to_hash rescue NoMethodError # for backward compatibility = {} [:username] = [:password] = passwd [:account] = acct end @host = nil if [:ssl] unless defined?(OpenSSL::SSL) raise "SSL extension not installed" end ssl_params = [:ssl] == true ? {} : [:ssl] @ssl_context = SSLContext.new @ssl_context.set_params(ssl_params) if defined?(VerifyCallbackProc) @ssl_context.verify_callback = VerifyCallbackProc end @ssl_context.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_CLIENT | OpenSSL::SSL::SSLContext::SESSION_CACHE_NO_INTERNAL_STORE @ssl_context.session_new_cb = proc {|sock, sess| @ssl_session = sess } @ssl_session = nil if [:private_data_connection].nil? @private_data_connection = true else @private_data_connection = [:private_data_connection] end else @ssl_context = nil if [:private_data_connection] raise ArgumentError, "private_data_connection can be set to true only when ssl is enabled" end @private_data_connection = false end @binary = true if [:passive].nil? @passive = @@default_passive else @passive = [:passive] end if [:debug_mode].nil? @debug_mode = false else @debug_mode = [:debug_mode] end @resume = false @bare_sock = @sock = NullSocket.new @logged_in = false @open_timeout = [:open_timeout] @ssl_handshake_timeout = [:ssl_handshake_timeout] @read_timeout = [:read_timeout] || 60 if host connect(host, [:port] || FTP_PORT) if [:username] login( [:username], [:password], [:account]) end end end
Class Attribute Details
.default_passive (rw)
When true
, connections are in passive mode per default. Default: true
.
# File 'lib/net/ftp.rb', line 151
def self.default_passive @@default_passive end
.default_passive=(value) (rw)
When true
, connections are in passive mode per default. Default: true
.
# File 'lib/net/ftp.rb', line 145
def self.default_passive=(value) @@default_passive = value end
Class Method Details
.open(host, *args)
A synonym for .new, but with a mandatory host parameter.
If a block is given, it is passed the FTP
object, which will be closed when the block finishes, or when an exception is raised.
Instance Attribute Details
#binary (rw)
When true
, transfers are performed in binary mode. Default: true
.
# File 'lib/net/ftp.rb', line 95
attr_reader :binary
#binary=(newmode) (rw)
A setter to toggle transfers in binary mode. newmode
is either true
or false
# File 'lib/net/ftp.rb', line 278
def binary=(newmode) if newmode != @binary @binary = newmode send_type_command if @logged_in end end
#closed? ⇒ Boolean
(readonly)
Returns true
iff the connection is closed.
# File 'lib/net/ftp.rb', line 1320
def closed? @sock == nil or @sock.closed? end
#debug_mode (rw)
When true
, all traffic to and from the server is written to $stdout. Default: false
.
# File 'lib/net/ftp.rb', line 102
attr_accessor :debug_mode
#last_response (readonly)
The server's last response.
# File 'lib/net/ftp.rb', line 141
attr_reader :last_response
#last_response_code (readonly) Also known as: #lastresp
The server's last response code.
# File 'lib/net/ftp.rb', line 137
attr_reader :last_response_code
#lastresp (readonly)
Alias for #last_response_code.
# File 'lib/net/ftp.rb', line 138
alias lastresp last_response_code
#open_timeout (rw)
Number of seconds to wait for the connection to open. Any number may be used, including Floats for fractional seconds. If the FTP
object cannot open a connection in this many seconds, it raises a Net::OpenTimeout
exception. The default value is nil
.
# File 'lib/net/ftp.rb', line 112
attr_accessor :open_timeout
#passive (rw)
When true
, the connection is in passive mode. Default: true
.
# File 'lib/net/ftp.rb', line 98
attr_accessor :passive
#read_timeout (rw)
Number of seconds to wait for one block to be read (via one read(2) call). Any number may be used, including Floats for fractional seconds. If the FTP
object cannot read data in this many seconds, it raises a Timeout::Error
exception. The default value is 60 seconds.
# File 'lib/net/ftp.rb', line 125
attr_reader :read_timeout
#read_timeout=(sec) (rw)
Setter for the read_timeout attribute.
# File 'lib/net/ftp.rb', line 128
def read_timeout=(sec) @sock.read_timeout = sec @read_timeout = sec end
#resume (rw)
Sets or retrieves the resume
status, which decides whether incomplete transfers are resumed or restarted. Default: false
.
# File 'lib/net/ftp.rb', line 106
attr_accessor :resume
#return_code (rw)
Obsolete
# File 'lib/net/ftp.rb', line 316
def return_code # :nodoc: warn("Net::FTP#return_code is obsolete and do nothing", uplevel: 1) return "\n" end
#return_code=(s) (rw)
Obsolete
# File 'lib/net/ftp.rb', line 322
def return_code=(s) # :nodoc: warn("Net::FTP#return_code= is obsolete and do nothing", uplevel: 1) end
#ssl_handshake_timeout (rw)
Number of seconds to wait for the TLS handshake. Any number may be used, including Floats for fractional seconds. If the FTP
object cannot complete the TLS handshake in this many seconds, it raises a Net::OpenTimeout
exception. The default value is nil
. If ssl_handshake_timeout
is nil
, #open_timeout is used instead.
# File 'lib/net/ftp.rb', line 119
attr_accessor :ssl_handshake_timeout
#welcome (readonly)
The server's welcome message.
# File 'lib/net/ftp.rb', line 134
attr_reader :welcome
Instance Method Details
#abort
Aborts the previous command (ABOR command).
# File 'lib/net/ftp.rb', line 1226
def abort line = "ABOR" + CRLF print "put: ABOR\n" if @debug_mode @sock.send(line, Socket::MSG_OOB) resp = getmultiline unless ["426", "226", "225"].include?(resp[0, 3]) raise FTPProtoError, resp end return resp end
#acct(account)
Sends the ACCT command.
This is a less common FTP
command, to send account information if the destination host requires it.
# File 'lib/net/ftp.rb', line 879
def acct(account) cmd = "ACCT " + account voidcmd(cmd) end
#chdir(dirname)
Changes the (remote) directory.
# File 'lib/net/ftp.rb', line 1147
def chdir(dirname) if dirname == ".." begin voidcmd("CDUP") return rescue FTPPermError => e if e. [0, 3] != "500" raise e end end end cmd = "CWD #{dirname}" voidcmd(cmd) end
#close
Closes the connection. Further operations are impossible until you open a new connection with #connect.
# File 'lib/net/ftp.rb', line 1304
def close if @sock and not @sock.closed? begin @sock.shutdown(Socket::SHUT_WR) rescue nil orig, self.read_timeout = self.read_timeout, 3 @sock.read rescue nil ensure @sock.close self.read_timeout = orig end end end
#connect(host, port = FTP_PORT)
Establishes an FTP
connection to host, optionally overriding the default port. If the environment variable SOCKS_SERVER
is set, sets up the connection through a SOCKS proxy. Raises an exception (typically Errno::ECONNREFUSED
) if the connection cannot be established.
# File 'lib/net/ftp.rb', line 366
def connect(host, port = FTP_PORT) if @debug_mode print "connect: ", host, ", ", port, "\n" end synchronize do @host = host @bare_sock = open_socket(host, port) @sock = BufferedSocket.new(@bare_sock, read_timeout: @read_timeout) voidresp if @ssl_context begin voidcmd("AUTH TLS") ssl_sock = start_tls_session(@bare_sock) @sock = BufferedSSLSocket.new(ssl_sock, read_timeout: @read_timeout) if @private_data_connection voidcmd("PBSZ 0") voidcmd("PROT P") end rescue OpenSSL::SSL::SSLError, OpenTimeout @sock.close raise end end end end
#delete(filename)
Deletes a file on the server.
# File 'lib/net/ftp.rb', line 1133
def delete(filename) resp = sendcmd("DELE #{filename}") if resp.start_with?("250") return elsif resp.start_with?("5") raise FTPPermError, resp else raise FTPReplyError, resp end end
#dir(*args, &block)
Alias for #list.
# File 'lib/net/ftp.rb', line 918
alias dir list
#get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)
Retrieves remotefile
in whatever mode the session is set (text or binary). See #gettextfile and #getbinaryfile.
# File 'lib/net/ftp.rb', line 808
def get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data if @binary getbinaryfile(remotefile, localfile, blocksize, &block) else gettextfile(remotefile, localfile, &block) end end
#get_body(resp) (private)
# File 'lib/net/ftp.rb', line 1162
def get_body(resp) # :nodoc: resp.slice(/\A[0-9a-zA-Z]{3} (.*)$/, 1) end
#getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)
Retrieves remotefile
in binary mode, storing the result in localfile
. If localfile
is nil, returns retrieved data. If a block is supplied, it is passed the retrieved data in blocksize
chunks.
# File 'lib/net/ftp.rb', line 747
def getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data f = nil result = nil if localfile if @resume rest_offset = File.size?(localfile) f = File.open(localfile, "a") else rest_offset = nil f = File.open(localfile, "w") end elsif !block_given? result = String.new end begin f&.binmode retrbinary("RETR #{remotefile}", blocksize, rest_offset) do |data| f&.write(data) block&.(data) result&.concat(data) end return result ensure f&.close end end
#getdir
Alias for #pwd.
# File 'lib/net/ftp.rb', line 1210
alias getdir pwd
#getline (private)
Reads a line from the sock. If EOF, then it will raise EOFError
# File 'lib/net/ftp.rb', line 431
def getline # :nodoc: line = @sock.readline # if get EOF, raise EOFError line.sub!(/(\r\n|\n|\r)\z/n, "") if @debug_mode print "get: ", sanitize(line), "\n" end return line end
#getmultiline (private)
Receive a section of lines until the response code's match.
#getresp (private)
Receives a response from the destination host.
Returns the response code or raises FTPTempError, FTPPermError, or FTPProtoError
# File 'lib/net/ftp.rb', line 460
def getresp # :nodoc: @last_response = getmultiline @last_response_code = @last_response[0, 3] case @last_response_code when /\A[123]/ return @last_response when /\A4/ raise FTPTempError, @last_response when /\A5/ raise FTPPermError, @last_response else raise FTPProtoError, @last_response end end
#gettextfile(remotefile, localfile = File.basename(remotefile), &block)
Retrieves remotefile
in ASCII (text) mode, storing the result in localfile
. If localfile
is nil, returns retrieved data. If a block is supplied, it is passed the retrieved data one line at a time.
# File 'lib/net/ftp.rb', line 782
def gettextfile(remotefile, localfile = File.basename(remotefile), &block) # :yield: line f = nil result = nil if localfile f = File.open(localfile, "w") elsif !block_given? result = String.new end begin retrlines("RETR #{remotefile}") do |line, newline| l = newline ? line + "\n" : line f&.print(l) block&.(line, newline) result&.concat(l) end return result ensure f&.close end end
#help(arg = nil)
Issues the HELP command.
# File 'lib/net/ftp.rb', line 1268
def help(arg = nil) cmd = "HELP" if arg cmd = cmd + " " + arg end sendcmd(cmd) end
#list(*args, &block) Also known as: #ls, #dir
Returns an array of file information in the directory (the output is like `ls -l`). If a block is given, it iterates through the listing.
# File 'lib/net/ftp.rb', line 903
def list(*args, &block) # :yield: line cmd = "LIST" args.each do |arg| cmd = "#{cmd} #{arg}" end lines = [] retrlines(cmd) do |line| lines << line end if block lines.each(&block) end return lines end
#login(user = "anonymous", passwd = nil, acct = nil)
Logs in to the remote host. The session must have been previously connected. If user
is the string “anonymous” and the password
is nil
, “anonymous@” is used as a password. If the #acct parameter is not nil
, an FTP
ACCT command is sent following the successful login. Raises an exception on error (typically FTPPermError).
# File 'lib/net/ftp.rb', line 598
def login(user = "anonymous", passwd = nil, acct = nil) if user == "anonymous" and passwd == nil passwd = "anonymous@" end resp = "" synchronize do resp = sendcmd('USER ' + user) if resp.start_with?("3") raise FTPReplyError, resp if passwd.nil? resp = sendcmd('PASS ' + passwd) end if resp.start_with?("3") raise FTPReplyError, resp if acct.nil? resp = sendcmd('ACCT ' + acct) end end if !resp.start_with?("2") raise FTPReplyError, resp end @welcome = resp send_type_command @logged_in = true end
#ls(*args, &block)
Alias for #list.
# File 'lib/net/ftp.rb', line 917
alias ls list
#makepasv (private)
sends the appropriate command to enable a passive connection
#makeport (private)
Constructs a TCPServer socket
# File 'lib/net/ftp.rb', line 523
def makeport # :nodoc: Addrinfo.tcp(@bare_sock.local_address.ip_address, 0).listen end
#mdtm(filename)
Returns the raw last modification time of the (remote) file in the format “YYYYMMDDhhmmss” (MDTM command).
Use #mtime if you want a parsed Time instance.
#mkdir(dirname)
Creates a remote directory.
#mlsd(pathname = nil, &block)
Returns an array of the entries of the directory specified by pathname
. Each entry has the facts (e.g., size, last modification time, etc.) and the pathname. If a block is given, it iterates through the listing. If pathname
is omitted, the current directory is assumed.
# File 'lib/net/ftp.rb', line 1107
def mlsd(pathname = nil, &block) # :yield: entry cmd = pathname ? "MLSD #{pathname}" : "MLSD" entries = [] retrlines(cmd) do |line| entries << parse_mlsx_entry(line) end if block entries.each(&block) end return entries end
#mlst(pathname = nil)
Returns data (e.g., size, last modification time, entry type, etc.) about the file or directory specified by pathname
. If pathname
is omitted, the current directory is assumed.
# File 'lib/net/ftp.rb', line 1085
def mlst(pathname = nil) cmd = pathname ? "MLST #{pathname}" : "MLST" resp = sendcmd(cmd) if !resp.start_with?("250") raise FTPReplyError, resp end line = resp.lines[1] unless line raise FTPProtoError, resp end entry = line.sub(/\A(250-| *)/, "") return parse_mlsx_entry(entry) end
#mtime(filename, local = false)
Returns the last modification time of the (remote) file. If local
is true
, it is returned as a local time, otherwise it's a UTC time.
# File 'lib/net/ftp.rb', line 1184
def mtime(filename, local = false) return TIME_PARSER.(mdtm(filename), local) end
#nlst(dir = nil)
Returns an array of filenames in the remote directory.
#noop
Issues a NOOP command.
Does nothing except return a response.
# File 'lib/net/ftp.rb', line 1288
def noop voidcmd("NOOP") end
#open_socket(host, port) (private)
Constructs a socket with host
and port
.
If SOCKSSocket is defined and the environment (ENV) defines SOCKS_SERVER, then a SOCKSSocket is returned, else a Socket is returned.
# File 'lib/net/ftp.rb', line 331
def open_socket(host, port) # :nodoc: return Timeout.timeout(@open_timeout, OpenTimeout) { if defined? SOCKSSocket and ENV["SOCKS_SERVER"] @passive = true SOCKSSocket.open(host, port) else Socket.tcp(host, port) end } end
#parse227(resp) (private)
handler for response code 227 (Entering Passive Mode (h1,h2,h3,h4,p1,p2))
Returns host and port.
# File 'lib/net/ftp.rb', line 1328
def parse227(resp) # :nodoc: if !resp.start_with?("227") raise FTPReplyError, resp end if m = /\((?<host>\d(,\d){3}),(?<port>\d,\d)\)/.match(resp) return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"]) else raise FTPProtoError, resp end end
#parse228(resp) (private)
handler for response code 228 (Entering Long Passive Mode)
Returns host and port.
# File 'lib/net/ftp.rb', line 1344
def parse228(resp) # :nodoc: if !resp.start_with?("228") raise FTPReplyError, resp end if m = /\(4,4,(?<host>\d(,\d){3}),2,(?<port>\d,\d)\)/.match(resp) return parse_pasv_ipv4_host(m["host"]), parse_pasv_port(m["port"]) elsif m = /\(6,16,(?<host>\d(,(\d)){15}),2,(?<port>\d,\d)\)/.match(resp) return parse_pasv_ipv6_host(m["host"]), parse_pasv_port(m["port"]) else raise FTPProtoError, resp end end
#parse229(resp) (private)
handler for response code 229 (Extended Passive Mode Entered)
Returns host and port.
# File 'lib/net/ftp.rb', line 1381
def parse229(resp) # :nodoc: if !resp.start_with?("229") raise FTPReplyError, resp end if m = /\((?<d>[!-~])\k<d>\k<d>(?<port>\d+)\k<d>\)/.match(resp) return @bare_sock.remote_address.ip_address, m["port"].to_i else raise FTPProtoError, resp end end
#parse257(resp) (private)
handler for response code 257 (“PATHNAME” created)
Returns host and port.
# File 'lib/net/ftp.rb', line 1397
def parse257(resp) # :nodoc: if !resp.start_with?("257") raise FTPReplyError, resp end return resp.slice(/"(([^"]|"")*)"/, 1).to_s.gsub(/""/, '"') end
#parse_mlsx_entry(entry) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 1065
def parse_mlsx_entry(entry) facts, pathname = entry.chomp.split(/ /, 2) unless pathname raise FTPProtoError, entry end return MLSxEntry.new( facts.scan(/(.*?)=(.*?);/).each_with_object({}) { |(factname, value), h| name = factname.downcase h[name] = FACT_PARSERS[name].(value) }, pathname) end
#parse_pasv_ipv4_host(s) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 1358
def parse_pasv_ipv4_host(s) return s.tr(",", ".") end
#parse_pasv_ipv6_host(s) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 1363
def parse_pasv_ipv6_host(s) return s.split(/,/).map { |i| "%02x" % i.to_i }.each_slice(2).map(&:join).join(":") end
#parse_pasv_port(s) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 1370
def parse_pasv_port(s) return s.split(/,/).map(&:to_i).inject { |x, y| (x << 8) + y } end
#put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)
Transfers localfile
to the server in whatever mode the session is set (text or binary). See #puttextfile and #putbinaryfile.
# File 'lib/net/ftp.rb', line 864
def put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) if @binary putbinaryfile(localfile, remotefile, blocksize, &block) else puttextfile(localfile, remotefile, &block) end end
#putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)
Transfers localfile
to the server in binary mode, storing the result in remotefile
. If a block is supplied, calls it, passing in the transmitted data in blocksize
chunks.
# File 'lib/net/ftp.rb', line 822
def putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block) # :yield: data if @resume begin rest_offset = size(remotefile) rescue Net::FTPPermError rest_offset = nil end else rest_offset = nil end f = File.open(localfile) begin f.binmode if rest_offset storbinary("APPE #{remotefile}", f, blocksize, rest_offset, &block) else storbinary("STOR #{remotefile}", f, blocksize, rest_offset, &block) end ensure f.close end end
#putline(line) (private)
Ensures that line
has a control return / line feed (CRLF) and writes it to the socket.
#puttextfile(localfile, remotefile = File.basename(localfile), &block)
Transfers localfile
to the server in ASCII (text) mode, storing the result in remotefile
. If callback or an associated block is supplied, calls it, passing in the transmitted data one line at a time.
#pwd Also known as: #getdir
Returns the current remote directory.
#quit
Exits the FTP
session.
# File 'lib/net/ftp.rb', line 1279
def quit voidcmd("QUIT") end
#rename(fromname, toname)
Renames a file on the server.
# File 'lib/net/ftp.rb', line 1122
def rename(fromname, toname) resp = sendcmd("RNFR #{fromname}") if !resp.start_with?("3") raise FTPReplyError, resp end voidcmd("RNTO #{toname}") end
#retrbinary(cmd, blocksize, rest_offset = nil)
Puts the connection into binary (image) mode, issues the given command, and fetches the data returned, passing it to the associated block in chunks of blocksize
characters. Note that cmd
is a server command (such as “RETR myfile”).
# File 'lib/net/ftp.rb', line 629
def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data synchronize do with_binary(true) do begin conn = transfercmd(cmd, rest_offset) loop do data = conn.read(blocksize) break if data == nil yield(data) end conn.shutdown(Socket::SHUT_WR) conn.read_timeout = 1 conn.read ensure conn.close if conn end voidresp end end end
#retrlines(cmd)
Puts the connection into ASCII (text) mode, issues the given command, and passes the resulting data, one line at a time, to the associated block. If no block is given, prints the lines. Note that cmd
is a server command (such as “RETR myfile”).
# File 'lib/net/ftp.rb', line 656
def retrlines(cmd) # :yield: line synchronize do with_binary(false) do begin conn = transfercmd(cmd) loop do line = conn.gets break if line == nil yield(line.sub(/\r?\n\z/, ""), !line.match(/\n\z/).nil?) end conn.shutdown(Socket::SHUT_WR) conn.read_timeout = 1 conn.read ensure conn.close if conn end voidresp end end end
#rmdir(dirname)
Removes a remote directory.
# File 'lib/net/ftp.rb', line 1199
def rmdir(dirname) voidcmd("RMD #{dirname}") end
#sanitize(s) (private)
If string s
includes the PASS command (password), then the contents of the password are cleaned from the string using “*”
# File 'lib/net/ftp.rb', line 407
def sanitize(s) # :nodoc: if s =~ /^PASS /i return s[0, 5] + "*" * (s.length - 5) else return s end end
#send_type_command (private)
Sends a command to destination host, with the current binary sendmode type.
If binary mode is true
, then “TYPE I” (image) is sent, otherwise “TYPE A” (ascii) is sent.
#sendcmd(cmd)
Sends a command and returns the response.
#sendport(host, port) (private)
Constructs and send the appropriate PORT (or EPRT) command
# File 'lib/net/ftp.rb', line 509
def sendport(host, port) # :nodoc: remote_address = @bare_sock.remote_address if remote_address.ipv4? cmd = "PORT " + (host.split(".") + port.divmod(256)).join(",") elsif remote_address.ipv6? cmd = sprintf("EPRT |2|%s|%d|", host, port) else raise FTPProtoError, host end voidcmd(cmd) end
#set_socket(sock, get_greeting = true)
Set the socket used to connect to the FTP
server.
May raise FTPReplyError if get_greeting
is false.
# File 'lib/net/ftp.rb', line 396
def set_socket(sock, get_greeting = true) synchronize do @sock = sock if get_greeting voidresp end end end
#site(arg)
Issues a SITE command.
# File 'lib/net/ftp.rb', line 1295
def site(arg) cmd = "SITE " + arg voidcmd(cmd) end
#size(filename)
Returns the size of the given (remote) filename.
# File 'lib/net/ftp.rb', line 1170
def size(filename) with_binary(true) do resp = sendcmd("SIZE #{filename}") if !resp.start_with?("213") raise FTPReplyError, resp end return get_body(resp).to_i end end
#start_tls_session(sock) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 343
def start_tls_session(sock) ssl_sock = SSLSocket.new(sock, @ssl_context) ssl_sock.sync_close = true ssl_sock.hostname = @host if ssl_sock.respond_to? :hostname= if @ssl_session && Process.clock_gettime(Process::CLOCK_REALTIME) < @ssl_session.time.to_f + @ssl_session.timeout # ProFTPD returns 425 for data connections if session is not reused. ssl_sock.session = @ssl_session end ssl_socket_connect(ssl_sock, @ssl_handshake_timeout || @open_timeout) if @ssl_context.verify_mode != VERIFY_NONE ssl_sock.post_connection_check(@host) end return ssl_sock end
#status(pathname = nil)
Returns the status (STAT command). pathname - when stat is invoked with pathname as a parameter it acts like
list but alot faster and over the same tcp session.
#storbinary(cmd, file, blocksize, rest_offset = nil)
Puts the connection into binary (image) mode, issues the given server-side command (such as “STOR myfile”), and sends the contents of the file named file
to the server. If the optional block is given, it also passes it the data, in chunks of blocksize
characters.
# File 'lib/net/ftp.rb', line 683
def storbinary(cmd, file, blocksize, rest_offset = nil) # :yield: data if rest_offset file.seek(rest_offset, IO::SEEK_SET) end synchronize do with_binary(true) do conn = transfercmd(cmd) loop do buf = file.read(blocksize) break if buf == nil conn.write(buf) yield(buf) if block_given? end conn.close voidresp end end rescue Errno::EPIPE # EPIPE, in this case, means that the data connection was unexpectedly # terminated. Rather than just raising EPIPE to the caller, check the # response on the control connection. If getresp doesn't raise a more # appropriate exception, re-raise the original exception. getresp raise end
#storlines(cmd, file)
Puts the connection into ASCII (text) mode, issues the given server-side command (such as “STOR myfile”), and sends the contents of the file named file
to the server, one line at a time. If the optional block is given, it also passes it the lines.
# File 'lib/net/ftp.rb', line 715
def storlines(cmd, file) # :yield: line synchronize do with_binary(false) do conn = transfercmd(cmd) loop do buf = file.gets break if buf == nil if buf[-2, 2] != CRLF buf = buf.chomp + CRLF end conn.write(buf) yield(buf) if block_given? end conn.close voidresp end end rescue Errno::EPIPE # EPIPE, in this case, means that the data connection was unexpectedly # terminated. Rather than just raising EPIPE to the caller, check the # response on the control connection. If getresp doesn't raise a more # appropriate exception, re-raise the original exception. getresp raise end
#system
Returns system information.
# File 'lib/net/ftp.rb', line 1215
def system resp = sendcmd("SYST") if !resp.start_with?("215") raise FTPReplyError, resp end return get_body(resp) end
#transfercmd(cmd, rest_offset = nil) (private)
Constructs a connection for transferring data
# File 'lib/net/ftp.rb', line 541
def transfercmd(cmd, rest_offset = nil) # :nodoc: if @passive host, port = makepasv conn = open_socket(host, port) if @resume and rest_offset resp = sendcmd("REST " + rest_offset.to_s) if !resp.start_with?("3") raise FTPReplyError, resp end end resp = sendcmd(cmd) # skip 2XX for some ftp servers resp = getresp if resp.start_with?("2") if !resp.start_with?("1") raise FTPReplyError, resp end else sock = makeport begin addr = sock.local_address sendport(addr.ip_address, addr.ip_port) if @resume and rest_offset resp = sendcmd("REST " + rest_offset.to_s) if !resp.start_with?("3") raise FTPReplyError, resp end end resp = sendcmd(cmd) # skip 2XX for some ftp servers resp = getresp if resp.start_with?("2") if !resp.start_with?("1") raise FTPReplyError, resp end conn, = sock.accept sock.shutdown(Socket::SHUT_WR) rescue nil sock.read rescue nil ensure sock.close end end if @private_data_connection return BufferedSSLSocket.new(start_tls_session(conn), read_timeout: @read_timeout) else return BufferedSocket.new(conn, read_timeout: @read_timeout) end end
#voidcmd(cmd)
Sends a command and expect a response beginning with '2'.
#voidresp (private)
Receives a response.
Raises FTPReplyError if the first position of the response code is not equal 2.
# File 'lib/net/ftp.rb', line 480
def voidresp # :nodoc: resp = getresp if !resp.start_with?("2") raise FTPReplyError, resp end end
#with_binary(newmode) (private)
Toggles transfers in binary mode and yields to a block. This preserves your current binary send mode, but allows a temporary transaction with binary sendmode of newmode
.
newmode
is either true
or false