class Net::FTP::List::Unix

Parse Unix like FTP LIST entries.

MATCHES

drwxr-xr-x   4 steve    group       4096 Dec 10 20:23 etc
-rw-r--r--   1 root     other        531 Jan 29 03:26 README.txt

Constants

ONE_YEAR
REGEXP

Stolen straight from the ASF's commons Java FTP LIST parser library. svn.apache.org/repos/asf/commons/proper/net/trunk/src/java/org/apache/commons/net/ftp/

Public Class Methods

parse(raw, timezone: :utc) click to toggle source

Parse a Unix like FTP LIST entries.

# File lib/net/ftp/list/unix.rb, line 29
def self.parse(raw, timezone: :utc)
  match = REGEXP.match(raw.strip) or return false
  type  = case match[1]
          when /d/      then :dir
          when /l/      then :symlink
          when /[f-]/   then :file
          when /[psbc]/ then :device
          end
  return false if type.nil?

  # Don't match on rumpus (which looks very similar to unix)
  return false if match[17].nil? && ((match[15].nil? && (match[16].to_s == 'folder')) || (match[15].to_s == '0'))

  # TODO: Permissions, users, groups, date/time.
  filesize = match[18].to_i
  mtime_month_and_day = match[19]
  mtime_time_or_year = match[20]

  # Unix mtimes specify a 4 digit year unless the data is within the past 180
  # days or so. Future dates always specify a 4 digit year.
  # If the parsed date, with today's year, could be in the future, then
  # the date must be for the previous year
  mtime_string = case mtime_time_or_year
                 when /^[0-9]{1,2}:[0-9]{2}$/
                   if parse_time("#{mtime_month_and_day} #{Time.now.year}", timezone: timezone) > Time.now
                     "#{mtime_month_and_day} #{mtime_time_or_year} #{Time.now.year - 1}"
                   else
                     "#{mtime_month_and_day} #{mtime_time_or_year} #{Time.now.year}"
                   end
                 when /^[0-9]{4}$/
                   "#{mtime_month_and_day} #{mtime_time_or_year}"
                 end

  mtime = parse_time(mtime_string, timezone: timezone)
  basename = match[21].strip

  # filenames with spaces will end up in the last match
  basename += match[22] unless match[22].nil?

  # strip the symlink stuff we don't care about
  if type == :symlink
    basename.sub!(/\s+->(.+)$/, '')
    symlink_destination = Regexp.last_match(1).strip if Regexp.last_match(1)
  end

  emit_entry(
    raw,
    type: type,
    filesize: filesize,
    basename: basename,
    symlink_destination: symlink_destination,
    mtime: mtime,
  )
end