Blame src/SFtp.h

Packit 8f70b4
/*
Packit 8f70b4
 * lftp - file transfer program
Packit 8f70b4
 *
Packit 8f70b4
 * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
Packit 8f70b4
 *
Packit 8f70b4
 * This program is free software; you can redistribute it and/or modify
Packit 8f70b4
 * it under the terms of the GNU General Public License as published by
Packit 8f70b4
 * the Free Software Foundation; either version 3 of the License, or
Packit 8f70b4
 * (at your option) any later version.
Packit 8f70b4
 *
Packit 8f70b4
 * This program is distributed in the hope that it will be useful,
Packit 8f70b4
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 8f70b4
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 8f70b4
 * GNU General Public License for more details.
Packit 8f70b4
 *
Packit 8f70b4
 * You should have received a copy of the GNU General Public License
Packit 8f70b4
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 8f70b4
 */
Packit 8f70b4
Packit 8f70b4
#ifndef SFTP_H
Packit 8f70b4
#define SFTP_H
Packit 8f70b4
Packit 8f70b4
#include "SSH_Access.h"
Packit 8f70b4
#include "StatusLine.h"
Packit 8f70b4
#include <sys/types.h>
Packit 8f70b4
#include <sys/stat.h>
Packit 8f70b4
#include "FileSet.h"
Packit 8f70b4
Packit 8f70b4
class SFtp : public SSH_Access
Packit 8f70b4
{
Packit 8f70b4
   int	 protocol_version;
Packit 8f70b4
Packit 8f70b4
   const char *lc_to_utf8(const char *);
Packit 8f70b4
   const char *utf8_to_lc(const char *);
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
enum packet_type {
Packit 8f70b4
   SSH_FXP_INIT     =1,
Packit 8f70b4
   SSH_FXP_VERSION  =2,
Packit 8f70b4
   SSH_FXP_OPEN     =3,
Packit 8f70b4
   SSH_FXP_CLOSE    =4,
Packit 8f70b4
   SSH_FXP_READ     =5,
Packit 8f70b4
   SSH_FXP_WRITE    =6,
Packit 8f70b4
   SSH_FXP_LSTAT    =7,
Packit 8f70b4
   SSH_FXP_FSTAT    =8,
Packit 8f70b4
   SSH_FXP_SETSTAT  =9,
Packit 8f70b4
   SSH_FXP_FSETSTAT =10,
Packit 8f70b4
   SSH_FXP_OPENDIR  =11,
Packit 8f70b4
   SSH_FXP_READDIR  =12,
Packit 8f70b4
   SSH_FXP_REMOVE   =13,
Packit 8f70b4
   SSH_FXP_MKDIR    =14,
Packit 8f70b4
   SSH_FXP_RMDIR    =15,
Packit 8f70b4
   SSH_FXP_REALPATH =16,
Packit 8f70b4
   SSH_FXP_STAT     =17,
Packit 8f70b4
   SSH_FXP_RENAME   =18,   // v>=2
Packit 8f70b4
   SSH_FXP_READLINK =19,   // v>=3
Packit 8f70b4
   SSH_FXP_SYMLINK  =20,   // v<=5
Packit 8f70b4
   SSH_FXP_LINK     =21,   // v>=6
Packit 8f70b4
   SSH_FXP_BLOCK    =22,   // v>=6
Packit 8f70b4
   SSH_FXP_UNBLOCK  =23,   // v>=6
Packit 8f70b4
Packit 8f70b4
   SSH_FXP_STATUS   =101,
Packit 8f70b4
   SSH_FXP_HANDLE   =102,
Packit 8f70b4
   SSH_FXP_DATA     =103,
Packit 8f70b4
   SSH_FXP_NAME     =104,
Packit 8f70b4
   SSH_FXP_ATTRS    =105,
Packit 8f70b4
   SSH_FXP_EXTENDED =200,
Packit 8f70b4
   SSH_FXP_EXTENDED_REPLY=201
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
#define SSH_FILEXFER_ATTR_SIZE         0x00000001
Packit 8f70b4
#define SSH_FILEXFER_ATTR_UIDGID       0x00000002  // v<=3
Packit 8f70b4
#define SSH_FILEXFER_ATTR_PERMISSIONS  0x00000004
Packit 8f70b4
#define SSH_FILEXFER_ATTR_ACCESSTIME   0x00000008
Packit 8f70b4
#define SSH_FILEXFER_ATTR_ACMODTIME    0x00000008  // v<=3
Packit 8f70b4
#define SSH_FILEXFER_ATTR_CREATETIME   0x00000010
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MODIFYTIME   0x00000020
Packit 8f70b4
#define SSH_FILEXFER_ATTR_ACL          0x00000040
Packit 8f70b4
#define SSH_FILEXFER_ATTR_OWNERGROUP   0x00000080
Packit 8f70b4
#define SSH_FILEXFER_ATTR_SUBSECOND_TIMES 0x00000100
Packit 8f70b4
#define SSH_FILEXFER_ATTR_BITS              0x00000200 // v>=5
Packit 8f70b4
#define SSH_FILEXFER_ATTR_ALLOCATION_SIZE   0x00000400 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_TEXT_HINT         0x00000800 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MIME_TYPE         0x00001000 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_LINK_COUNT        0x00002000 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_UNTRANSLATED_NAME 0x00004000 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_CTIME             0x00008000 // v>=6
Packit 8f70b4
#define SSH_FILEXFER_ATTR_EXTENDED     0x80000000
Packit 8f70b4
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MASK_V3      0x8000000F
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MASK_V4      0x800001FD
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MASK_V5      0x800003FD
Packit 8f70b4
#define SSH_FILEXFER_ATTR_MASK_V6      0x8000FFFD
Packit 8f70b4
Packit 8f70b4
// BITS values (v>=5)
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_READONLY         0x00000001
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_SYSTEM           0x00000002
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_HIDDEN           0x00000004
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_CASE_INSENSITIVE 0x00000008
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_ARCHIVE          0x00000010
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_ENCRYPTED        0x00000020
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_COMPRESSED       0x00000040
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_SPARSE           0x00000080
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_APPEND_ONLY      0x00000100
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_IMMUTABLE        0x00000200
Packit 8f70b4
#define SSH_FILEXFER_ATTR_FLAGS_SYNC             0x00000400
Packit 8f70b4
Packit 8f70b4
enum sftp_file_type {
Packit 8f70b4
   SSH_FILEXFER_TYPE_REGULAR	 =1,
Packit 8f70b4
   SSH_FILEXFER_TYPE_DIRECTORY	 =2,
Packit 8f70b4
   SSH_FILEXFER_TYPE_SYMLINK	 =3,
Packit 8f70b4
   SSH_FILEXFER_TYPE_SPECIAL	 =4,
Packit 8f70b4
   SSH_FILEXFER_TYPE_UNKNOWN	 =5,
Packit 8f70b4
   SSH_FILEXFER_TYPE_SOCKET      =6, // v>=5
Packit 8f70b4
   SSH_FILEXFER_TYPE_CHAR_DEVICE =7, // v>=5
Packit 8f70b4
   SSH_FILEXFER_TYPE_BLOCK_DEVICE=8, // v>=5
Packit 8f70b4
   SSH_FILEXFER_TYPE_FIFO        =9  // v>=5
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
// open modes (v<=4)
Packit 8f70b4
#define SSH_FXF_READ		       0x00000001
Packit 8f70b4
#define SSH_FXF_WRITE		       0x00000002
Packit 8f70b4
#define SSH_FXF_APPEND		       0x00000004
Packit 8f70b4
#define SSH_FXF_CREAT		       0x00000008
Packit 8f70b4
#define SSH_FXF_TRUNC		       0x00000010
Packit 8f70b4
#define SSH_FXF_EXCL		       0x00000020
Packit 8f70b4
Packit 8f70b4
// open flags values (v>=5)
Packit 8f70b4
#define SSH_FXF_ACCESS_DISPOSITION        0x00000007
Packit 8f70b4
#define     SSH_FXF_CREATE_NEW            0x00000000
Packit 8f70b4
#define     SSH_FXF_CREATE_TRUNCATE       0x00000001
Packit 8f70b4
#define     SSH_FXF_OPEN_EXISTING         0x00000002
Packit 8f70b4
#define     SSH_FXF_OPEN_OR_CREATE        0x00000003
Packit 8f70b4
#define     SSH_FXF_TRUNCATE_EXISTING     0x00000004
Packit 8f70b4
#define SSH_FXF_ACCESS_APPEND_DATA        0x00000008
Packit 8f70b4
#define SSH_FXF_ACCESS_APPEND_DATA_ATOMIC 0x00000010
Packit 8f70b4
#define SSH_FXF_ACCESS_TEXT_MODE          0x00000020
Packit 8f70b4
#define SSH_FXF_ACCESS_READ_LOCK          0x00000040
Packit 8f70b4
#define SSH_FXF_ACCESS_WRITE_LOCK         0x00000080
Packit 8f70b4
#define SSH_FXF_ACCESS_DELETE_LOCK        0x00000100
Packit 8f70b4
#define SSH_FXF_ACCESS_BLOCK_ADVISORY     0x00000200  // v>=6
Packit 8f70b4
#define SSH_FXF_ACCESS_NOFOLLOW           0x00000400  // v>=6
Packit 8f70b4
#define SSH_FXF_ACCESS_DELETE_ON_CLOSE    0x00000800  // v>=6
Packit 8f70b4
Packit 8f70b4
// ACL masks
Packit 8f70b4
#define ACE4_READ_DATA         0x00000001
Packit 8f70b4
#define ACE4_LIST_DIRECTORY    0x00000001
Packit 8f70b4
#define ACE4_WRITE_DATA        0x00000002
Packit 8f70b4
#define ACE4_ADD_FILE          0x00000002
Packit 8f70b4
#define ACE4_APPEND_DATA       0x00000004
Packit 8f70b4
#define ACE4_ADD_SUBDIRECTORY  0x00000004
Packit 8f70b4
#define ACE4_READ_NAMED_ATTRS  0x00000008
Packit 8f70b4
#define ACE4_WRITE_NAMED_ATTRS 0x00000010
Packit 8f70b4
#define ACE4_EXECUTE           0x00000020
Packit 8f70b4
#define ACE4_DELETE_CHILD      0x00000040
Packit 8f70b4
#define ACE4_READ_ATTRIBUTES   0x00000080
Packit 8f70b4
#define ACE4_WRITE_ATTRIBUTES  0x00000100
Packit 8f70b4
#define ACE4_DELETE            0x00010000
Packit 8f70b4
#define ACE4_READ_ACL          0x00020000
Packit 8f70b4
#define ACE4_WRITE_ACL         0x00040000
Packit 8f70b4
#define ACE4_WRITE_OWNER       0x00080000
Packit 8f70b4
#define ACE4_SYNCHRONIZE       0x00100000
Packit 8f70b4
Packit 8f70b4
// RENAME flags (v>=5)
Packit 8f70b4
#define SSH_FXF_RENAME_OVERWRITE  0x00000001
Packit 8f70b4
#define SSH_FXF_RENAME_ATOMIC     0x00000002
Packit 8f70b4
#define SSH_FXF_RENAME_NATIVE     0x00000004
Packit 8f70b4
Packit 8f70b4
enum sftp_status_t {
Packit 8f70b4
   SSH_FX_OK		     =0,
Packit 8f70b4
   SSH_FX_EOF		     =1,
Packit 8f70b4
   SSH_FX_NO_SUCH_FILE	     =2,
Packit 8f70b4
   SSH_FX_PERMISSION_DENIED  =3,
Packit 8f70b4
   SSH_FX_FAILURE	     =4,
Packit 8f70b4
   SSH_FX_BAD_MESSAGE	     =5,
Packit 8f70b4
   SSH_FX_NO_CONNECTION      =6,
Packit 8f70b4
   SSH_FX_CONNECTION_LOST    =7,
Packit 8f70b4
   SSH_FX_OP_UNSUPPORTED     =8,
Packit 8f70b4
   SSH_FX_INVALID_HANDLE     =9,
Packit 8f70b4
   SSH_FX_NO_SUCH_PATH       =10,
Packit 8f70b4
   SSH_FX_FILE_ALREADY_EXISTS=11,
Packit 8f70b4
   SSH_FX_WRITE_PROTECT      =12,
Packit 8f70b4
   SSH_FX_NO_MEDIA           =13,
Packit 8f70b4
   SSH_FX_NO_SPACE_ON_FILESYSTEM    =14,
Packit 8f70b4
   SSH_FX_QUOTA_EXCEEDED	    =15,
Packit 8f70b4
   SSH_FX_UNKNOWN_PRINCIPAL	    =16,
Packit 8f70b4
   SSH_FX_LOCK_CONFLICT		    =17,
Packit 8f70b4
   SSH_FX_DIR_NOT_EMPTY		    =18,
Packit 8f70b4
   SSH_FX_NOT_A_DIRECTORY	    =19,
Packit 8f70b4
   SSH_FX_INVALID_FILENAME	    =20,
Packit 8f70b4
   SSH_FX_LINK_LOOP		    =21,
Packit 8f70b4
   SSH_FX_CANNOT_DELETE		    =22,
Packit 8f70b4
   SSH_FX_INVALID_PARAMETER	    =23,
Packit 8f70b4
   SSH_FX_FILE_IS_A_DIRECTORY	    =24,
Packit 8f70b4
   SSH_FX_BYTE_RANGE_LOCK_CONFLICT  =25,
Packit 8f70b4
   SSH_FX_BYTE_RANGE_LOCK_REFUSED   =26,
Packit 8f70b4
   SSH_FX_DELETE_PENDING            =27,
Packit 8f70b4
   SSH_FX_FILE_CORRUPT              =28,
Packit 8f70b4
   SSH_FX_OWNER_INVALID             =29,
Packit 8f70b4
   SSH_FX_GROUP_INVALID             =30
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
private:
Packit 8f70b4
   enum state_t
Packit 8f70b4
   {
Packit 8f70b4
      DISCONNECTED,
Packit 8f70b4
      CONNECTING,
Packit 8f70b4
      CONNECTING_1,
Packit 8f70b4
      CONNECTING_2,
Packit 8f70b4
      CONNECTED,
Packit 8f70b4
      FILE_RECV,
Packit 8f70b4
      FILE_SEND,
Packit 8f70b4
      WAITING,
Packit 8f70b4
      DONE
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   state_t state;
Packit 8f70b4
   unsigned ssh_id;
Packit 8f70b4
   xstring handle;
Packit 8f70b4
Packit 8f70b4
   void Init();
Packit 8f70b4
Packit 8f70b4
   void	 SendMethod();
Packit 8f70b4
   void	 SendArrayInfoRequests();
Packit 8f70b4
Packit 8f70b4
   Ref<DirectedBuffer> send_translate;
Packit 8f70b4
   Ref<DirectedBuffer> recv_translate;
Packit 8f70b4
Packit 8f70b4
   Ref<Buffer> file_buf;
Packit 8f70b4
   Ref<FileSet> file_set;
Packit 8f70b4
   Timer flush_timer;
Packit 8f70b4
Packit 8f70b4
   void DisconnectLL();
Packit 8f70b4
   int IsConnected() const
Packit 8f70b4
      {
Packit 8f70b4
	 if(state==DISCONNECTED)
Packit 8f70b4
	    return 0;
Packit 8f70b4
	 if(state==CONNECTING)
Packit 8f70b4
	    return 1;
Packit 8f70b4
	 return 2;
Packit 8f70b4
      }
Packit 8f70b4
Packit 8f70b4
   const char *SkipHome(const char *path);
Packit 8f70b4
   const char *WirePath(const char *path);
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   enum unpack_status_t
Packit 8f70b4
   {
Packit 8f70b4
      UNPACK_SUCCESS=0,
Packit 8f70b4
      UNPACK_WRONG_FORMAT=-1,
Packit 8f70b4
      UNPACK_PREMATURE_EOF=-2,
Packit 8f70b4
      UNPACK_NO_DATA_YET=1
Packit 8f70b4
   };
Packit 8f70b4
   class Packet
Packit 8f70b4
   {
Packit 8f70b4
      static bool is_valid_reply(int p)
Packit 8f70b4
      {
Packit 8f70b4
	 return p==SSH_FXP_VERSION
Packit 8f70b4
	    || (p>=101 && p<=105)
Packit 8f70b4
	    || p==SSH_FXP_EXTENDED_REPLY;
Packit 8f70b4
      }
Packit 8f70b4
   protected:
Packit 8f70b4
      int length;
Packit 8f70b4
      int unpacked;
Packit 8f70b4
      packet_type type;
Packit 8f70b4
      unsigned id;
Packit 8f70b4
      Packet(packet_type t)
Packit 8f70b4
	 {
Packit 8f70b4
	    type=t;
Packit 8f70b4
	    length=1;
Packit 8f70b4
	    if(HasID())
Packit 8f70b4
	       length+=4;
Packit 8f70b4
	 }
Packit 8f70b4
      bool HasID();
Packit 8f70b4
   public:
Packit 8f70b4
      Packet() { length=0; }
Packit 8f70b4
      virtual void ComputeLength() { length=1+4*HasID(); }
Packit 8f70b4
      virtual void Pack(Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    b->PackUINT32BE(length);
Packit 8f70b4
	    b->PackUINT8(type);
Packit 8f70b4
	    if(HasID())
Packit 8f70b4
	       b->PackUINT32BE(id);
Packit 8f70b4
	 }
Packit 8f70b4
      virtual unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      virtual ~Packet() {}
Packit 8f70b4
      int GetLength() { return length; }
Packit 8f70b4
      packet_type GetPacketType() { return type; }
Packit 8f70b4
      const char *GetPacketTypeText();
Packit 8f70b4
      unsigned GetID() const { return id; }
Packit 8f70b4
      const xstring& GetKey() { return xstring::get_tmp((const char*)&id,sizeof(id)); }
Packit 8f70b4
      void SetID(unsigned new_id) { id=new_id; }
Packit 8f70b4
      void DropData(Buffer *b) { b->Skip(4+(length>0?length:0)); }
Packit 8f70b4
      bool TypeIs(packet_type t) const { return type==t; }
Packit 8f70b4
      static unpack_status_t UnpackString(const Buffer *b,int *offset,int limit,xstring *str_out);
Packit 8f70b4
      static void PackString(Buffer *b,const char *str,int len=-1);
Packit 8f70b4
   };
Packit 8f70b4
private:
Packit 8f70b4
   unpack_status_t UnpackPacket(Buffer *,Packet **);
Packit 8f70b4
   class PacketUINT32 : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   protected:
Packit 8f70b4
      unsigned data;
Packit 8f70b4
      PacketUINT32(packet_type t,unsigned d=0) : Packet(t)
Packit 8f70b4
	 { data=d; length+=4; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=Packet::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    data=b->UnpackUINT32BE(unpacked);
Packit 8f70b4
	    unpacked+=4;
Packit 8f70b4
	    return UNPACK_SUCCESS;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length+=4; }
Packit 8f70b4
      void Pack(Buffer *b) { Packet::Pack(b); b->PackUINT32BE(data); }
Packit 8f70b4
   };
Packit 8f70b4
   class PacketSTRING : public Packet
Packit 8f70b4
   {
Packit 8f70b4
   protected:
Packit 8f70b4
      xstring string;
Packit 8f70b4
      PacketSTRING(packet_type t) : Packet(t)
Packit 8f70b4
	 {
Packit 8f70b4
	    length=4;
Packit 8f70b4
	 }
Packit 8f70b4
      PacketSTRING(packet_type t,const xstring &s) : Packet(t)
Packit 8f70b4
	 {
Packit 8f70b4
	    string.set(s);
Packit 8f70b4
	    length+=4+string.length();
Packit 8f70b4
	 }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      void ComputeLength() { Packet::ComputeLength(); length+=4+string.length(); }
Packit 8f70b4
      void Pack(Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    Packet::Pack(b);
Packit 8f70b4
	    Packet::PackString(b,string,string.length());
Packit 8f70b4
	 }
Packit 8f70b4
      const char *GetString() { return string; }
Packit 8f70b4
      int GetStringLength() { return string.length(); }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_INIT : public PacketUINT32
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_INIT(int v) : PacketUINT32(SSH_FXP_INIT,v) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Reply_VERSION : public PacketUINT32
Packit 8f70b4
   {
Packit 8f70b4
      char **extension_name;
Packit 8f70b4
      char **extension_data;
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_VERSION() : PacketUINT32(SSH_FXP_VERSION) {}
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    unpack_status_t res;
Packit 8f70b4
	    res=PacketUINT32::Unpack(b);
Packit 8f70b4
	    if(res!=UNPACK_SUCCESS)
Packit 8f70b4
	       return res;
Packit 8f70b4
	    // FIXME: unpack extensions.
Packit 8f70b4
	    return res;
Packit 8f70b4
	 }
Packit 8f70b4
      unsigned GetVersion() { return data; }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_REALPATH : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_REALPATH(const char *p) : PacketSTRING(SSH_FXP_REALPATH,p) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_FSTAT : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
      unsigned flags;
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
   public:
Packit 8f70b4
      Request_FSTAT(const xstring &h,unsigned f,int pv) : PacketSTRING(SSH_FXP_FSTAT,h)
Packit 8f70b4
	 {
Packit 8f70b4
	    flags=f;
Packit 8f70b4
	    protocol_version=pv;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength()
Packit 8f70b4
	 {
Packit 8f70b4
	    PacketSTRING::ComputeLength();
Packit 8f70b4
	    if(protocol_version>=4)
Packit 8f70b4
	       length+=4;
Packit 8f70b4
	 }
Packit 8f70b4
      void Pack(Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    PacketSTRING::Pack(b);
Packit 8f70b4
	    if(protocol_version>=4)
Packit 8f70b4
	       b->PackUINT32BE(flags);
Packit 8f70b4
	 }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_STAT : public Request_FSTAT
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_STAT(const char *p,unsigned f,int pv) : Request_FSTAT(p,f,pv)
Packit 8f70b4
	 {
Packit 8f70b4
	    type=SSH_FXP_STAT;
Packit 8f70b4
	 }
Packit 8f70b4
      const char *GetName() { return string; }
Packit 8f70b4
   };
Packit 8f70b4
public:
Packit 8f70b4
   struct FileAttrs
Packit 8f70b4
   {
Packit 8f70b4
      struct ExtFileAttr
Packit 8f70b4
      {
Packit 8f70b4
	 xstring extended_type;
Packit 8f70b4
	 xstring extended_data;
Packit 8f70b4
	 unpack_status_t Unpack(const Buffer *b,int *offset,int limit);
Packit 8f70b4
	 void Pack(Buffer *b);
Packit 8f70b4
      };
Packit 8f70b4
      struct FileACE
Packit 8f70b4
      {
Packit 8f70b4
	 unsigned ace_type;
Packit 8f70b4
	 unsigned ace_flag;
Packit 8f70b4
	 unsigned ace_mask;
Packit 8f70b4
	 xstring who;
Packit 8f70b4
	 FileACE() { ace_type=ace_flag=ace_mask=0; }
Packit 8f70b4
	 unpack_status_t Unpack(const Buffer *b,int *offset,int limit);
Packit 8f70b4
	 void Pack(Buffer *b);
Packit 8f70b4
      };
Packit 8f70b4
Packit 8f70b4
      unsigned flags;
Packit 8f70b4
      int      type;		    // v>=4
Packit 8f70b4
      off_t    size;		    // present only if flag SIZE
Packit 8f70b4
      xstring  owner;		    // present only if flag OWNERGROUP // v>=4
Packit 8f70b4
      xstring  group;		    // present only if flag OWNERGROUP // v>=4
Packit 8f70b4
      unsigned uid;		    // present only if flag UIDGID // v<=3
Packit 8f70b4
      unsigned gid;		    // present only if flag UIDGID // v<=3
Packit 8f70b4
      unsigned permissions;	    // present only if flag PERMISSIONS
Packit 8f70b4
      time_t   atime;		    // present only if flag ACCESSTIME (ACMODTIME)
Packit 8f70b4
      unsigned atime_nseconds;	    // present only if flag SUBSECOND_TIMES
Packit 8f70b4
      time_t   createtime;	    // present only if flag CREATETIME
Packit 8f70b4
      unsigned createtime_nseconds; // present only if flag SUBSECOND_TIMES
Packit 8f70b4
      time_t   mtime;		    // present only if flag MODIFYTIME (ACMODTIME)
Packit 8f70b4
      unsigned mtime_nseconds;	    // present only if flag SUBSECOND_TIMES
Packit 8f70b4
      time_t   ctime;		    // present only if flag CTIME // v>=6
Packit 8f70b4
      unsigned ctime_nseconds;	    // present only if flag SUBSECOND_TIMES // v>=6
Packit 8f70b4
      unsigned ace_count;	    // present only if flag ACL
Packit 8f70b4
      FileACE  *ace;
Packit 8f70b4
      unsigned attrib_bits;         // if flag BITS		  // v>=5
Packit 8f70b4
      unsigned attrib_bits_valid;   // if flag BITS		  // v>=6
Packit 8f70b4
      unsigned char text_hint;      // if flag TEXT_HINT	  // v>=6
Packit 8f70b4
      xstring  mime_type;	    // if flag MIME_TYPE	  // v>=6
Packit 8f70b4
      unsigned link_count;          // if flag LINK_COUNT	  // v>=6
Packit 8f70b4
      xstring  untranslated_name;   // if flag UNTRANSLATED_NAME  // v>=6
Packit 8f70b4
      unsigned extended_count;	    // present only if flag EXTENDED
Packit 8f70b4
      ExtFileAttr *extended_attrs;
Packit 8f70b4
Packit 8f70b4
      FileAttrs()
Packit 8f70b4
      {
Packit 8f70b4
	 flags=0; type=0; size=NO_SIZE; uid=gid=0;
Packit 8f70b4
	 permissions=0;
Packit 8f70b4
	 atime=createtime=mtime=ctime=NO_DATE;
Packit 8f70b4
	 atime_nseconds=createtime_nseconds=mtime_nseconds=ctime_nseconds=0;
Packit 8f70b4
	 extended_count=0; extended_attrs=0;
Packit 8f70b4
	 ace_count=0; ace=0;
Packit 8f70b4
	 attrib_bits=attrib_bits_valid=0; text_hint=0;
Packit 8f70b4
	 link_count=0;
Packit 8f70b4
      }
Packit 8f70b4
      ~FileAttrs();
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b,int *offset,int limit,int proto_version);
Packit 8f70b4
      void Pack(Buffer *b,int proto_version);
Packit 8f70b4
      int ComputeLength(int v);
Packit 8f70b4
   };
Packit 8f70b4
   struct NameAttrs
Packit 8f70b4
   {
Packit 8f70b4
      xstring name;
Packit 8f70b4
      xstring longname;
Packit 8f70b4
      FileAttrs attrs;
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b,int *offset,int limit,int proto_version);
Packit 8f70b4
   };
Packit 8f70b4
private:
Packit 8f70b4
   class Reply_NAME : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
      int count;
Packit 8f70b4
      NameAttrs *names;
Packit 8f70b4
      bool eof;
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_NAME(int pv) : Packet(SSH_FXP_NAME) { protocol_version=pv; eof=false; }
Packit 8f70b4
      ~Reply_NAME() { delete[] names; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      int GetCount() { return count; }
Packit 8f70b4
      const NameAttrs *GetNameAttrs(int index)
Packit 8f70b4
	 {
Packit 8f70b4
	    if(index>count)
Packit 8f70b4
	       return 0;
Packit 8f70b4
	    return &names[index];
Packit 8f70b4
	 }
Packit 8f70b4
      bool Eof() { return eof; }
Packit 8f70b4
   };
Packit 8f70b4
   class Reply_ATTRS : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
      FileAttrs attrs;
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_ATTRS(int pv) : Packet(SSH_FXP_ATTRS) { protocol_version=pv; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      const FileAttrs *GetAttrs() { return &attrs; }
Packit 8f70b4
   };
Packit 8f70b4
   class PacketSTRING_ATTRS : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   protected:
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
   public:
Packit 8f70b4
      FileAttrs attrs;
Packit 8f70b4
      PacketSTRING_ATTRS(packet_type type,const xstring &h,int pv)
Packit 8f70b4
       : PacketSTRING(type,h)
Packit 8f70b4
	 {
Packit 8f70b4
	    protocol_version=pv;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength()
Packit 8f70b4
	 {
Packit 8f70b4
	    PacketSTRING::ComputeLength();
Packit 8f70b4
	    length+=attrs.ComputeLength(protocol_version);
Packit 8f70b4
	 }
Packit 8f70b4
      void Pack(Buffer *b)
Packit 8f70b4
	 {
Packit 8f70b4
	    PacketSTRING::Pack(b);
Packit 8f70b4
	    attrs.Pack(b,protocol_version);
Packit 8f70b4
	 }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_FSETSTAT : public PacketSTRING_ATTRS
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_FSETSTAT(const xstring &h,int pv)
Packit 8f70b4
       : PacketSTRING_ATTRS(SSH_FXP_FSETSTAT,h,pv) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_OPEN : public PacketSTRING_ATTRS
Packit 8f70b4
   {
Packit 8f70b4
      unsigned pflags;		 // v<=4
Packit 8f70b4
      unsigned desired_access;	 // v>=5
Packit 8f70b4
      unsigned flags;		 // v>=5
Packit 8f70b4
   public:
Packit 8f70b4
      Request_OPEN(const char *fn,unsigned pf,unsigned da,unsigned f,int pv)
Packit 8f70b4
       : PacketSTRING_ATTRS(SSH_FXP_OPEN,fn,pv)
Packit 8f70b4
	 {
Packit 8f70b4
	    pflags=pf;
Packit 8f70b4
	    desired_access=da;
Packit 8f70b4
	    flags=f;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength()
Packit 8f70b4
	 {
Packit 8f70b4
	    PacketSTRING_ATTRS::ComputeLength();
Packit 8f70b4
	    length+=4+4*(protocol_version>=5);
Packit 8f70b4
	 }
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
   class Reply_HANDLE : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_HANDLE() : PacketSTRING(SSH_FXP_HANDLE) {}
Packit 8f70b4
      const xstring &GetHandle() { return string; }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_CLOSE : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_CLOSE(const xstring &h) : PacketSTRING(SSH_FXP_CLOSE,h) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_OPENDIR : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_OPENDIR(const char *name) : PacketSTRING(SSH_FXP_OPENDIR,name) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_READDIR : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_READDIR(const xstring &h) : PacketSTRING(SSH_FXP_READDIR,h) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Reply_STATUS : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
      unsigned code;
Packit 8f70b4
      xstring message;
Packit 8f70b4
      xstring language;
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_STATUS(int pv) { protocol_version=pv; code=0; }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      int GetCode() { return code; }
Packit 8f70b4
      const char *GetCodeText();
Packit 8f70b4
      const char *GetMessage() { return message; }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_READ : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      off_t pos;
Packit 8f70b4
      unsigned len;
Packit 8f70b4
      Request_READ(const xstring &h,off_t p,unsigned l)
Packit 8f70b4
       : PacketSTRING(SSH_FXP_READ,h) { pos=p; len=l; }
Packit 8f70b4
      void ComputeLength() { PacketSTRING::ComputeLength(); length+=8+4; }
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
   class Reply_DATA : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
      bool eof;
Packit 8f70b4
   public:
Packit 8f70b4
      Reply_DATA() : PacketSTRING(SSH_FXP_DATA) { eof=false; }
Packit 8f70b4
      void GetData(const char **b,int *s) { *b=string; *s=string.length(); }
Packit 8f70b4
      unpack_status_t Unpack(const Buffer *b);
Packit 8f70b4
      bool Eof() { return eof; }
Packit 8f70b4
   };
Packit 8f70b4
   class Request_WRITE : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      off_t pos;
Packit 8f70b4
      xstring data;
Packit 8f70b4
      Request_WRITE(const xstring &h,off_t p,const char *d,unsigned l)
Packit 8f70b4
       : PacketSTRING(SSH_FXP_WRITE,h) { pos=p; data.nset(d,l); }
Packit 8f70b4
      void ComputeLength() { PacketSTRING::ComputeLength(); length+=8+4+data.length(); }
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
   class Request_MKDIR : public PacketSTRING_ATTRS
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_MKDIR(const char *fn,int pv)
Packit 8f70b4
       : PacketSTRING_ATTRS(SSH_FXP_MKDIR,fn,pv) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_SETSTAT : public PacketSTRING_ATTRS
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_SETSTAT(const char *fn,int pv)
Packit 8f70b4
       : PacketSTRING_ATTRS(SSH_FXP_SETSTAT,fn,pv) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_RMDIR : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_RMDIR(const char *fn) : PacketSTRING(SSH_FXP_RMDIR,fn) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_REMOVE : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_REMOVE(const char *fn) : PacketSTRING(SSH_FXP_REMOVE,fn) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_RENAME : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      int protocol_version;
Packit 8f70b4
      xstring oldpath;
Packit 8f70b4
      xstring newpath;
Packit 8f70b4
      unsigned flags;
Packit 8f70b4
   public:
Packit 8f70b4
      Request_RENAME(const char *o,const char *n,unsigned f,int pv)
Packit 8f70b4
      : Packet(SSH_FXP_RENAME), oldpath(o), newpath(n)
Packit 8f70b4
	 {
Packit 8f70b4
	    protocol_version=pv;
Packit 8f70b4
	    flags=f;
Packit 8f70b4
	 }
Packit 8f70b4
      void ComputeLength();
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
   class Request_READLINK : public PacketSTRING
Packit 8f70b4
   {
Packit 8f70b4
   public:
Packit 8f70b4
      Request_READLINK(const char *name) : PacketSTRING(SSH_FXP_READLINK,name) {}
Packit 8f70b4
   };
Packit 8f70b4
   class Request_SYMLINK : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      xstring oldpath;
Packit 8f70b4
      xstring newpath;
Packit 8f70b4
   public:
Packit 8f70b4
      Request_SYMLINK(const char *o,const char *n)
Packit 8f70b4
      : Packet(SSH_FXP_SYMLINK), oldpath(o), newpath(n) {}
Packit 8f70b4
      void ComputeLength()
Packit 8f70b4
	 {
Packit 8f70b4
	    Packet::ComputeLength();
Packit 8f70b4
	    length+=4+strlen(oldpath)+4+strlen(newpath);
Packit 8f70b4
	 }
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
   class Request_LINK : public Packet
Packit 8f70b4
   {
Packit 8f70b4
      xstring oldpath;
Packit 8f70b4
      xstring newpath;
Packit 8f70b4
      bool symbolic;
Packit 8f70b4
   public:
Packit 8f70b4
      Request_LINK(const char *o,const char *n,bool s)
Packit 8f70b4
      : Packet(SSH_FXP_LINK), oldpath(o), newpath(n), symbolic(s) {}
Packit 8f70b4
      void ComputeLength()
Packit 8f70b4
	 {
Packit 8f70b4
	    Packet::ComputeLength();
Packit 8f70b4
	    length+=4+strlen(oldpath)+4+strlen(newpath)+1;
Packit 8f70b4
	 }
Packit 8f70b4
      void Pack(Buffer *b);
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   struct Expect;
Packit 8f70b4
   friend struct SFtp::Expect; // grant access to Packet.
Packit 8f70b4
   struct Expect
Packit 8f70b4
   {
Packit 8f70b4
      enum expect_t
Packit 8f70b4
      {
Packit 8f70b4
	 HOME_PATH,
Packit 8f70b4
	 FXP_VERSION,
Packit 8f70b4
	 CWD,
Packit 8f70b4
	 HANDLE,
Packit 8f70b4
	 HANDLE_STALE,
Packit 8f70b4
	 DATA,
Packit 8f70b4
	 INFO,
Packit 8f70b4
	 INFO_READLINK,
Packit 8f70b4
	 DEFAULT,
Packit 8f70b4
	 WRITE_STATUS,
Packit 8f70b4
	 IGNORE
Packit 8f70b4
      };
Packit 8f70b4
Packit 8f70b4
      Ref<Packet> request;
Packit 8f70b4
      Ref<Packet> reply;
Packit 8f70b4
      int i;
Packit 8f70b4
      expect_t tag;
Packit 8f70b4
      Expect(Packet *req,expect_t t,int j=0) : request(req), i(j), tag(t) {}
Packit 8f70b4
Packit 8f70b4
      bool has_data_at_pos(off_t pos) const {
Packit 8f70b4
	 if(!reply->TypeIs(SSH_FXP_DATA) || !request->TypeIs(SSH_FXP_READ))
Packit 8f70b4
	    return false;
Packit 8f70b4
	 return request.Cast<Request_READ>()->pos==pos;
Packit 8f70b4
      }
Packit 8f70b4
   };
Packit 8f70b4
Packit 8f70b4
   void PushExpect(Expect *);
Packit 8f70b4
   int HandleReplies();
Packit 8f70b4
   int HandlePty();
Packit 8f70b4
   void HandleExpect(Expect *);
Packit 8f70b4
   void CloseExpectQueue();
Packit 8f70b4
   int GetExpectCount(Expect::expect_t tag);
Packit 8f70b4
   void CloseHandle(Expect::expect_t e);
Packit 8f70b4
   int ReplyLogPriority(int);
Packit 8f70b4
Packit 8f70b4
   xmap_p<Expect> expect_queue;
Packit 8f70b4
   const xstring& expect_key(unsigned id);
Packit 8f70b4
Packit 8f70b4
   Expect *FindExpectExclusive(Packet *reply);
Packit 8f70b4
   xarray_p<Expect> ooo_chain; 	// out of order replies buffered
Packit 8f70b4
Packit 8f70b4
   int	 RespQueueSize() const { return expect_queue.count(); }
Packit 8f70b4
   int   RespQueueIsEmpty() const { return RespQueueSize()==0; }
Packit 8f70b4
   void  EmptyRespQueue() {
Packit 8f70b4
      expect_queue.empty();
Packit 8f70b4
      ooo_chain.truncate();
Packit 8f70b4
   }
Packit 8f70b4
Packit 8f70b4
   bool GetBetterConnection(int level,bool limit_reached);
Packit 8f70b4
   void MoveConnectionHere(SFtp *o);
Packit 8f70b4
Packit 8f70b4
   bool	 eof;
Packit 8f70b4
Packit 8f70b4
   void	 SendRequest();
Packit 8f70b4
   void	 SendRequest(Packet *req,Expect::expect_t exp,int i=0);
Packit 8f70b4
   void	 SendRequestGeneric(int type);
Packit 8f70b4
   void	 RequestMoreData();
Packit 8f70b4
   off_t request_pos;
Packit 8f70b4
Packit 8f70b4
   void MergeAttrs(FileInfo *fi,const FileAttrs *a);
Packit 8f70b4
   FileInfo *MakeFileInfo(const NameAttrs *a);
Packit 8f70b4
Packit 8f70b4
   int max_packets_in_flight;
Packit 8f70b4
   int max_packets_in_flight_slow_start;
Packit 8f70b4
   int size_read;
Packit 8f70b4
   int size_write;
Packit 8f70b4
   bool use_full_path;
Packit 8f70b4
Packit 8f70b4
protected:
Packit 8f70b4
   void SetError(int code,const Packet *reply);
Packit 8f70b4
   void SetError(int code,const char *mess=0) { FA::SetError(code,mess); }
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   static void ClassInit();
Packit 8f70b4
Packit 8f70b4
   SFtp();
Packit 8f70b4
   SFtp(const SFtp*);
Packit 8f70b4
   ~SFtp();
Packit 8f70b4
Packit 8f70b4
   const char *GetProto() const { return "sftp"; }
Packit 8f70b4
Packit 8f70b4
   FileAccess *Clone() const { return new SFtp(this); }
Packit 8f70b4
   static FileAccess *New();
Packit 8f70b4
Packit 8f70b4
   int Do();
Packit 8f70b4
   int Done();
Packit 8f70b4
   int Read(Buffer *,int);
Packit 8f70b4
   int Write(const void *,int);
Packit 8f70b4
   int StoreStatus();
Packit 8f70b4
   int Buffered();
Packit 8f70b4
Packit 8f70b4
   void Close();
Packit 8f70b4
   const char *CurrentStatus();
Packit 8f70b4
Packit 8f70b4
   void Reconfig(const char *name=0);
Packit 8f70b4
Packit 8f70b4
   bool SameSiteAs(const FileAccess *fa) const;
Packit 8f70b4
   bool SameLocationAs(const FileAccess *fa) const;
Packit 8f70b4
Packit 8f70b4
   DirList *MakeDirList(ArgV *args);
Packit 8f70b4
   Glob *MakeGlob(const char *pattern);
Packit 8f70b4
   ListInfo *MakeListInfo(const char *dir);
Packit 8f70b4
Packit 8f70b4
   bool NeedSizeDateBeforehand() { return false; }
Packit 8f70b4
Packit 8f70b4
   void SuspendInternal();
Packit 8f70b4
   void ResumeInternal();
Packit 8f70b4
Packit 8f70b4
   FileSet *GetFileSet();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class SFtpDirList : public DirList
Packit 8f70b4
{
Packit 8f70b4
   SMTaskRef<IOBuffer> ubuf;
Packit 8f70b4
   const char *dir;
Packit 8f70b4
   bool use_file_set;
Packit 8f70b4
   Ref<FileSet> fset;
Packit 8f70b4
   LsOptions ls_options;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   SFtpDirList(SFtp *s,ArgV *a);
Packit 8f70b4
   const char *Status();
Packit 8f70b4
   int Do();
Packit 8f70b4
Packit 8f70b4
   void SuspendInternal();
Packit 8f70b4
   void ResumeInternal();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
class SFtpListInfo : public ListInfo
Packit 8f70b4
{
Packit 8f70b4
   SMTaskRef<IOBuffer> ubuf;
Packit 8f70b4
Packit 8f70b4
public:
Packit 8f70b4
   SFtpListInfo(SFtp *session,const char *dir)
Packit 8f70b4
      : ListInfo(session,dir) {}
Packit 8f70b4
   int Do();
Packit 8f70b4
   const char *Status();
Packit 8f70b4
};
Packit 8f70b4
Packit 8f70b4
#endif