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