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.closeExample 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)
endMajor Methods
The following are the methods most likely to be useful to users:
Mainframe User Support
Constant Summary
- 
    CASE_DEPENDENT_PARSER =
    
 # File 'lib/net/ftp.rb', line 1082->(value) { value } 
- 
    CASE_INDEPENDENT_PARSER =
    
 # File 'lib/net/ftp.rb', line 1083->(value) { value.downcase } 
- 
    CRLF =
    Internal use only
    
 # File 'lib/net/ftp.rb', line 94"\r\n"
- 
    DECIMAL_PARSER =
    
 # File 'lib/net/ftp.rb', line 1084->(value) { value.to_i } 
- 
    DEFAULT_BLOCKSIZE =
    Internal use only
    
 # File 'lib/net/ftp.rb', line 95BufferedIO::BUFSIZE 
- 
    FACT_PARSERS =
    
 # File 'lib/net/ftp.rb', line 1096Hash.new(CASE_DEPENDENT_PARSER) 
- 
    FTP_PORT =
    Internal use only
    
 # File 'lib/net/ftp.rb', line 9321
- 
    OCTAL_PARSER =
    
 # File 'lib/net/ftp.rb', line 1085->(value) { value.to_i(8) } 
- 
    TIME_PARSER =
    
 # File 'lib/net/ftp.rb', line 1086->(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{1,17}))?/x =~ value value = value[0, 97] + "..." if value.size > 100 raise FTPProtoError, "invalid time-val: #{value}" end usec = ".#{fractions}".to_r * 1_000_000 if fractions Time.public_send(local ? :local : :utc, year, month, day, hour, min, sec, usec) } 
- 
    VERSION =
    Internal use only
    
 # File 'lib/net/ftp.rb', line 92"0.3.8"
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 FTPobject.
- 
    
      .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 trueif and only if the connection is closed.
- 
    
      #debug_mode  
    
    rw
    When true, all traffic to and from the server is written to$stdout.
- 
    
      #debug_output  
    
    rw
    Sets or retrieves the output stream for debugging. 
- 
    
      #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. 
- 
    
      #use_pasv_ip  
    
    rw
    When true, use the IP address in PASV responses.
- 
    
      #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 FTPconnection to host, optionally overriding the default port.
- 
    
      #debug_print(msg)  
    
    Writes debug message to the debug output stream. 
- 
    
      #delete(filename)  
    
    Deletes a file on the server. 
- 
    
      #dir(*args, &block)  
    
    Alias for #list. 
- 
    
      #features  
    
    Issues a FEAT command. 
- 
    
      #get(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)  
    
    Retrieves remotefilein whatever mode the session is set (text or binary).
- 
    
      #getbinaryfile(remotefile, localfile = File.basename(remotefile), blocksize = DEFAULT_BLOCKSIZE, &block)  
    
    Retrieves remotefilein binary mode, storing the result inlocalfile.
- 
    
      #getdir  
    
    Alias for #pwd. 
- 
    
      #gettextfile(remotefile, localfile = File.basename(remotefile), &block)  
    
    Retrieves remotefilein 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`). 
- 
    
      #literal(arguments)  
    
    Alias for #quote. 
- 
    
      #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. 
- 
    
      #option(name, params = nil)  
    
    Issues an OPTS command - name Should be the name of the option to set - params is any optional parameters to supply with the option. 
- 
    
      #put(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)  
    
    Transfers localfileto the server in whatever mode the session is set (text or binary).
- 
    
      #putbinaryfile(localfile, remotefile = File.basename(localfile), blocksize = DEFAULT_BLOCKSIZE, &block)  
    
    Transfers localfileto the server in binary mode, storing the result inremotefile.
- 
    
      #puttextfile(localfile, remotefile = File.basename(localfile), &block)  
    
    Transfers localfileto the server in ASCII (text) mode, storing the result inremotefile.
- 
    
      #pwd  
      (also: #getdir)
    
    Returns the current remote directory. 
- 
    
      #quit  
    
    Exits the FTPsession.
- 
    
      #quote(arguments)  
      (also: #literal)
    
    The “quote” subcommand sends arguments verbatim to the remote ftp server. 
- 
    
      #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 blocksizecharacters.
- 
    
      #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 FTPserver.
- 
    
      #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 fileto 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 fileto 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 hostandport.
- 
    
      #parse227(resp)  
    
    private
    Internal use only
    handler for response code 227 (Entering Passive Mode (h1,h2,h3,h4,p1,p2)). 
- 
    
      #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 linehas a control return / line feed (CRLF) and writes it to the socket.
- 
    
      #sanitize(s)  
    
    private
    Internal use only
    If string sincludes 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[:ssl] 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: truewhenoptions[:ssl] is true.
- implicit_ftps
- 
If true, TLS is established on initial connection. Default: false
- username
- 
Username for login. If options is the string “anonymous” and the options[:password] isnil, “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.
- use_pasv_ip
- 
When true, use the IP address in PASV responses. Otherwise, it uses the same IP address for the control connection. Default:false.
- debug_mode
- 
When true, all traffic to and from the server is written to$stdout. Default:false.
# File 'lib/net/ftp.rb', line 230
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 # jruby-openssl does not support session caching unless RUBY_ENGINE == "jruby" @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 } end @ssl_session = nil if [:private_data_connection].nil? @private_data_connection = true else @private_data_connection = [:private_data_connection] end if [:implicit_ftps].nil? @implicit_ftps = false else @implicit_ftps = [:implicit_ftps] 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 if [:implicit_ftps] raise ArgumentError, "implicit_ftps can be set to true only when ssl is enabled" end @implicit_ftps = 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 @debug_output = $stdout @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 @use_pasv_ip = [:use_pasv_ip] || false 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 165
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 159
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 100
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 314
def binary=(newmode) if newmode != @binary @binary = newmode send_type_command if @logged_in end end
    #closed?  ⇒ Boolean  (readonly)
  
Returns true if and only if the connection is closed.
# File 'lib/net/ftp.rb', line 1413
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 111
attr_accessor :debug_mode
#debug_output (rw)
Sets or retrieves the output stream for debugging. Output stream will be used only when #debug_mode is set to true. The default value is $stdout.
# File 'lib/net/ftp.rb', line 116
attr_accessor :debug_output
#last_response (readonly)
The server’s last response.
# File 'lib/net/ftp.rb', line 155
attr_reader :last_response
#last_response_code (readonly) Also known as: #lastresp
The server’s last response code.
# File 'lib/net/ftp.rb', line 151
attr_reader :last_response_code
#lastresp (readonly)
Alias for #last_response_code.
# File 'lib/net/ftp.rb', line 152
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 126
attr_accessor :open_timeout
#passive (rw)
When true, the connection is in passive mode.  Default: true.
# File 'lib/net/ftp.rb', line 103
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 139
attr_reader :read_timeout
#read_timeout=(sec) (rw)
Setter for the read_timeout attribute.
# File 'lib/net/ftp.rb', line 142
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 120
attr_accessor :resume
#return_code (rw)
Obsolete
# File 'lib/net/ftp.rb', line 352
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 358
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 133
attr_accessor :ssl_handshake_timeout
#use_pasv_ip (rw)
When true, use the IP address in PASV responses.  Otherwise, it uses the same IP address for the control connection.  Default: false.
# File 'lib/net/ftp.rb', line 107
attr_accessor :use_pasv_ip
#welcome (readonly)
The server’s welcome message.
# File 'lib/net/ftp.rb', line 148
attr_reader :welcome
Instance Method Details
#abort
Aborts the previous command (ABOR command).
# File 'lib/net/ftp.rb', line 1283
def abort line = "ABOR" + CRLF debug_print "put: ABOR" @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 925
def acct(account) cmd = "ACCT " + account voidcmd(cmd) end
#chdir(dirname)
Changes the (remote) directory.
# File 'lib/net/ftp.rb', line 1194
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 1397
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 402
def connect(host, port = FTP_PORT) debug_print "connect: #{host}:#{port}" synchronize do @host = host @bare_sock = open_socket(host, port) if @ssl_context begin unless @implicit_ftps set_socket(BufferedSocket.new(@bare_sock, read_timeout: @read_timeout)) voidcmd("AUTH TLS") end set_socket(BufferedSSLSocket.new(start_tls_session(@bare_sock), read_timeout: @read_timeout), @implicit_ftps) if @private_data_connection voidcmd("PBSZ 0") voidcmd("PROT P") end rescue OpenSSL::SSL::SSLError, OpenTimeout @sock.close raise end else set_socket(BufferedSocket.new(@bare_sock, read_timeout: @read_timeout)) end end end
#debug_print(msg)
Writes debug message to the debug output stream
# File 'lib/net/ftp.rb', line 1488
def debug_print(msg) @debug_output << msg + "\n" if @debug_mode && @debug_output end
#delete(filename)
Deletes a file on the server.
# File 'lib/net/ftp.rb', line 1180
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 964
alias dir list
#features
Issues a FEAT command
Returns an array of supported optional features
# File 'lib/net/ftp.rb', line 1363
def features resp = sendcmd("FEAT") if !resp.start_with?("211") raise FTPReplyError, resp end feats = [] resp.each_line do |line| next if !line.start_with?(' ') # skip status lines feats << line.strip end return feats end
#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 849
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 1209
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 788
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 1267
alias getdir pwd
#getline (private)
Reads a line from the sock. If EOF, then it will raise EOFError
# File 'lib/net/ftp.rb', line 465
def getline # :nodoc: line = @sock.readline # if get EOF, raise EOFError line.sub!(/(\r\n|\n|\r)\z/n, "") debug_print "get: #{sanitize(line)}" 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 492
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 823
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 1326
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 949
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
#literal(arguments)
Alias for #quote.
# File 'lib/net/ftp.rb', line 1251
alias literal quote
#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 635
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 963
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 555
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 1154
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 1132
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 1231
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 1346
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 367
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
#option(name, params = nil)
Issues an OPTS command
- 
name Should be the name of the option to set 
- 
params is any optional parameters to supply with the option 
example: option(‘UTF8’, ‘ON’) => ‘OPTS UTF8 ON’
# File 'lib/net/ftp.rb', line 1386
def option(name, params = nil) cmd = "OPTS #{name}" cmd += " #{params}" if params voidcmd(cmd) 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 1421
def parse227(resp) # :nodoc: if !resp.start_with?("227") raise FTPReplyError, resp end if m = /(?<host>\d(?:,\d){3}),(?<port>\d,\d)/.match(resp) if @use_pasv_ip host = parse_pasv_ipv4_host(m["host"]) else host = @bare_sock.remote_address.ip_address end return 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 1461
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 1477
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 1112
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 1438
def parse_pasv_ipv4_host(s) return s.tr(",", ".") end
#parse_pasv_ipv6_host(s) (private)
[ GitHub ]# File 'lib/net/ftp.rb', line 1443
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 1450
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 910
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 863
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.
# File 'lib/net/ftp.rb', line 454
def putline(line) # :nodoc: debug_print "put: #{sanitize(line)}" if /[\r\n]/ =~ line raise ArgumentError, "A line must not contain CR or LF" end line = line + CRLF @sock.write(line) end
#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.
Returns the response which will contain a job number if the user was communicating with a mainframe in ASCII mode after issuing ‘quote site filetype=jes’
#pwd Also known as: #getdir
Returns the current remote directory.
#quit
Exits the FTP session.
# File 'lib/net/ftp.rb', line 1337
def quit voidcmd("QUIT") end
#quote(arguments) Also known as: #literal
The “quote” subcommand sends arguments verbatim to the remote ftp server. The “literal” subcommand is an alias for “quote”.
# File 'lib/net/ftp.rb', line 1248
def quote(arguments) sendcmd(arguments) end
#rename(fromname, toname)
Renames a file on the server.
# File 'lib/net/ftp.rb', line 1169
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 666
def retrbinary(cmd, blocksize, rest_offset = nil) # :yield: data synchronize do with_binary(true) do begin conn = transfercmd(cmd, rest_offset) while data = conn.read(blocksize) yield(data) end conn.shutdown(Socket::SHUT_WR) rescue nil conn.read_timeout = 1 conn.read rescue nil 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 691
def retrlines(cmd) # :yield: line synchronize do with_binary(false) do begin conn = transfercmd(cmd) while line = conn.gets yield(line.sub(/\r?\n\z/, ""), !line.match(/\n\z/).nil?) end conn.shutdown(Socket::SHUT_WR) rescue nil conn.read_timeout = 1 conn.read rescue nil ensure conn.close if conn end voidresp end end end
#rmdir(dirname)
Removes a remote directory.
# File 'lib/net/ftp.rb', line 1256
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 443
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 541
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 432
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 1353
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 1217
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 379
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 a lot faster and over the same tcp session. 
# File 'lib/net/ftp.rb', line 1300
def status(pathname = nil) line = pathname ? "STAT #{pathname}" : "STAT" if /[\r\n]/ =~ line raise ArgumentError, "A line must not contain CR or LF" end debug_print "put: #{line}" @sock.send(line + CRLF, Socket::MSG_OOB) return getresp end
#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 716
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 begin conn = transfercmd(cmd) while buf = file.read(blocksize) conn.write(buf) yield(buf) if block_given? end conn.shutdown(Socket::SHUT_WR) rescue nil conn.read_timeout = 1 conn.read rescue nil ensure conn.close if conn end 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 752
def storlines(cmd, file) # :yield: line synchronize do with_binary(false) do begin conn = transfercmd(cmd) while buf = file.gets if buf[-2, 2] != CRLF buf = buf.chomp + CRLF end conn.write(buf) yield(buf) if block_given? end conn.shutdown(Socket::SHUT_WR) rescue nil conn.read_timeout = 1 conn.read rescue nil ensure conn.close if conn end getresp # The response might be important when connected to a mainframe 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 1272
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 572
def transfercmd(cmd, rest_offset = nil) # :nodoc: if @passive host, port = makepasv succeeded = false begin 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 succeeded = true ensure conn&.close if !succeeded 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 512
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