Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
use the permissions bits to determine directoriness, as is proper
  • Loading branch information
jamis committed Mar 14, 2008
1 parent 4fc86a6 commit c9c7d64
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 35 deletions.
24 changes: 24 additions & 0 deletions lib/net/sftp/protocol/01/attributes.rb
Expand Up @@ -191,6 +191,30 @@ def group
attributes[:group]
end

# Returns true if these attributes appear to describe a directory. This
# is done by comparing the permissions, so if the permissions are not
# available, +nil+ is returned.
def directory?
return nil if permissions.nil?
return (permissions & 040000) == 040000
end

# Returns true if these attributes appear to describe a symlink. This
# is done by comparing the permissions, so if the permissions are not
# available, +nil+ is returned.
def symlink?
return nil if permissions.nil?
return (permissions & 020000) == 020000
end

# Returns true if these attributes appear to describe a regular file. This
# is done by comparing the permissions, so if the permissions are not
# available, +nil+ is returned.
def file?
return nil if permissions.nil?
return (permissions & 0100000) == 0100000
end

# Convert the object to a string suitable for passing in an SFTP
# packet. This is the raw representation of the attribute packet payload,
# and is not intended to be human readable.
Expand Down
34 changes: 9 additions & 25 deletions lib/net/sftp/protocol/01/name.rb
Expand Up @@ -3,16 +3,6 @@ module Net; module SFTP; module Protocol; module V01
# Represents a single named item on the remote server. This includes the
# name, attributes about the item, and the "longname", which is intended
# for use when displaying directory data, and has no specified format.
#
# This class also provides means to determine the type of the named item.
# However, these methods are admittedly fragile. It isn't until v4 of the
# SFTP protocol that a "type" field was included in the attributes, so there
# is no way to know, without parsing the longname field, what the type
# of a directory entry is. And the v3 spec explicitly says that clients
# should not attempt to parse the longname field, since the format is not
# defined in the spec. We're basing this off of the OpenSSH implementation,
# which returns output like ls -l. Other SFTP server implementations may
# not work as successfully.
class Name
# The name of the item on the remote server.
attr_reader :name
Expand All @@ -29,30 +19,24 @@ def initialize(name, longname, attributes)
end

# Returns +true+ if the item appears to be a directory. It does this by
# examining the first byte of the #longname field, a practice that the
# SFTP protocol specifically forbids, since the format of the #longname
# field is unspecified. However, there is no other way given to determine
# the type of a name entry.
# examining the attributes. If there is insufficient information in the
# attributes, this will return nil, rather than a boolean.
def directory?
longname[0] == ?d
attributes.directory?
end

# Returns +true+ if the item appears to be a symlink. It does this by
# examining the first byte of the #longname field, a practice that the
# SFTP protocol specifically forbids, since the format of the #longname
# field is unspecified. However, there is no other way given to determine
# the type of a name entry.
# examining the attributes. If there is insufficient information in the
# attributes, this will return nil, rather than a boolean.
def symlink?
longname[0] == ?l
attributes.symlink?
end

# Returns +true+ if the item appears to be a regular file. It does this by
# examining the first byte of the #longname field, a practice that the
# SFTP protocol specifically forbids, since the format of the #longname
# field is unspecified. However, there is no other way given to determine
# the type of a name entry.
# examining the attributes. If there is insufficient information in the
# attributes, this will return nil, rather than a boolean.
def file?
longname[0] == ?-
attributes.file?
end
end

Expand Down
6 changes: 3 additions & 3 deletions test/protocol/01/test_name.rb
Expand Up @@ -2,9 +2,9 @@

class Protocol::V01::TestName < Net::SFTP::TestCase
def setup
@directory = Net::SFTP::Protocol::V01::Name.new("test", "drwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new)
@link = Net::SFTP::Protocol::V01::Name.new("test", "lrwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new)
@file = Net::SFTP::Protocol::V01::Name.new("test", "-rwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new)
@directory = Net::SFTP::Protocol::V01::Name.new("test", "drwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new(:permissions => 040755))
@link = Net::SFTP::Protocol::V01::Name.new("test", "lrwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new(:permissions => 020755))
@file = Net::SFTP::Protocol::V01::Name.new("test", "-rwxr-x-r-x 89 test test 3026 Mar 10 17:45 test", Net::SFTP::Protocol::V01::Attributes.new(:permissions => 0100755))
end

def test_directory?
Expand Down
14 changes: 7 additions & 7 deletions test/test_download.rb
Expand Up @@ -188,10 +188,10 @@ def prepare_directory_tree_download(local, remote)

channel.sends_packet(FXP_READDIR, :long, 1, :string, "dir1")
channel.gets_packet(FXP_NAME, :long, 1, :long, 4,
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x01, :int64, 0,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x01, :int64, 0,
:string, "subdir1", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 subdir1", :long, 0x01, :int64, 0,
:string, "file1", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file1", :long, 0x01, :int64, 100)
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x04, :long, 040755,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x04, :long, 040755,
:string, "subdir1", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 subdir1", :long, 0x04, :long, 040755,
:string, "file1", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file1", :long, 0x04, :long, 0100644)

channel.sends_packet(FXP_OPENDIR, :long, 2, :string, File.join(remote, "subdir1"))
channel.sends_packet(FXP_OPEN, :long, 3, :string, File.join(remote, "file1"), :long, 0x01, :long, 0)
Expand All @@ -207,9 +207,9 @@ def prepare_directory_tree_download(local, remote)
channel.sends_packet(FXP_CLOSE, :long, 7, :string, "dir1")

channel.gets_packet(FXP_NAME, :long, 5, :long, 3,
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x01, :int64, 0,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x01, :int64, 0,
:string, "file2", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file2", :long, 0x01, :int64, 100)
:string, "..", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 ..", :long, 0x04, :long, 040755,
:string, ".", :string, "drwxr-xr-x 4 bob bob 136 Aug 1 .", :long, 0x04, :long, 040755,
:string, "file2", :string, "-rw-rw-r-- 1 bob bob 100 Aug 1 file2", :long, 0x04, :long, 0100644)

channel.sends_packet(FXP_OPEN, :long, 8, :string, File.join(remote, "subdir1", "file2"), :long, 0x01, :long, 0)
channel.sends_packet(FXP_READDIR, :long, 9, :string, "dir2")
Expand Down

0 comments on commit c9c7d64

Please sign in to comment.