diff --git a/uppsrc/Core/SSH/Core.cpp b/uppsrc/Core/SSH/Core.cpp index 8d126ad22..ac36bf558 100644 --- a/uppsrc/Core/SSH/Core.cpp +++ b/uppsrc/Core/SSH/Core.cpp @@ -47,10 +47,10 @@ String GetName(int type, int64 id) void Ssh::Check() { auto sock = ssh->socket; - + if(IsTimeout()) SetError(-1, "Operation timed out."); - + if(ssh->status == ABORTED || (sock && ssh->socket->IsAbort())) SetError(-1, "Operation aborted."); @@ -63,10 +63,10 @@ bool Ssh::Run(Gate<>&& fn) try { if(InProgress()) SetError(-1, "An operation is already in progress."); - + ssh->status = WORKING; ssh->start_time = msecs(); - + while(InProgress()) { Mutex::Lock __m(StaticMutex); diff --git a/uppsrc/Core/SSH/Core.h b/uppsrc/Core/SSH/Core.h index 92b56675b..83fb4660b 100644 --- a/uppsrc/Core/SSH/Core.h +++ b/uppsrc/Core/SSH/Core.h @@ -2,7 +2,7 @@ class Ssh { public: void Abort() { if(ssh) ssh->status = ABORTED; } int GetTimeout() const { return ssh->timeout; } - int GetWaitStep() const { return ssh->waitstep; } + int GetWaitStep() const { return ssh->waitstep; } bool InProgress() const { return ssh->status == WORKING; } bool IsError() const { return ssh->status == FAILED || ssh->status == ABORTED; } int GetError() const { return ssh->error.Get(); } @@ -12,7 +12,7 @@ public: template T& To() { auto* t = dynamic_cast(this); ASSERT(t); return *t; } template bool Is() const { return dynamic_cast(this); } - operator bool() { return ssh; } + operator bool() const { return ssh; } static void Trace(bool b = true) { SSH::sTrace = b; } static void TraceVerbose(int level) { Trace((bool)level); SSH::sTraceVerbose = level; } @@ -45,7 +45,7 @@ protected: int waitstep; int chunk_size; int status; - bool noloop; + bool noloop; }; One ssh; @@ -60,7 +60,7 @@ protected: bool Run(Gate<>&& fn); bool WouldBlock(int rc) { return rc == LIBSSH2_ERROR_EAGAIN; } bool WouldBlock() { return ssh->session && WouldBlock(libssh2_session_last_errno(ssh->session)); } - bool IsTimeout() const { return ssh->timeout > 0 && msecs(ssh->start_time) >= ssh->timeout; } + bool IsTimeout() const { return !IsNull(ssh->timeout) && ssh->timeout > 0 && msecs(ssh->start_time) >= ssh->timeout; } void SetError(int rc, const String& reason = Null); void AddTo(SocketWaitEvent& e) { e.Add(*ssh->socket, GetWaitEvents()); } diff --git a/uppsrc/Core/SSH/ReadMe b/uppsrc/Core/SSH/ReadMe index ae7824c1e..77e7880ff 100644 --- a/uppsrc/Core/SSH/ReadMe +++ b/uppsrc/Core/SSH/ReadMe @@ -72,7 +72,7 @@ History: -------------------- 2018-08-10: SSH package: Third iteration. SSH package is now officially a part of Ultimate++. - Full non-blocking mode and MT convenience methods removed in favor of simple an robust interface. + Full non-blocking mode and MT convenience methods removed in favor of simple an robust blocking interface. Ssh, SFtp and SshSession classes are refactored accordingly. SFtpStream variants are added to the package (Thanks Mirek!). Memory footprint slightly reduced. diff --git a/uppsrc/Core/SSH/SFtp.cpp b/uppsrc/Core/SSH/SFtp.cpp index 6b62f1edb..bd045ed57 100644 --- a/uppsrc/Core/SSH/SFtp.cpp +++ b/uppsrc/Core/SSH/SFtp.cpp @@ -23,7 +23,7 @@ void SFtp::Exit() { if(!sftp_session) return; - + Run([=]() mutable { if(WouldBlock(libssh2_sftp_shutdown(*sftp_session))) return false; @@ -49,7 +49,7 @@ int SFtp::LStat(const String& path, SFtpAttrs& a, int type) SFtpHandle SFtp::Open(const String& path, dword flags, long mode) { SFtpHandle h = nullptr; - + Run([=, &h] () mutable { h = libssh2_sftp_open(*sftp_session, path, flags, mode); if(!h && !WouldBlock()) @@ -58,7 +58,7 @@ SFtpHandle SFtp::Open(const String& path, dword flags, long mode) LLOG(Format("File '%s' is successfully opened.", path)); return h; }); - + return h; } @@ -123,7 +123,7 @@ SFtp& SFtp::Seek(SFtpHandle handle, int64 position) int64 SFtp::GetPos(SFtpHandle handle) { int64 pos = 0; - + return Run([=, &pos] () mutable { pos = libssh2_sftp_tell64(handle); LLOG("File position: " << pos); @@ -131,9 +131,10 @@ int64 SFtp::GetPos(SFtpHandle handle) }); return pos; } + bool SFtp::Read(SFtpHandle handle, Event&& consumer, int size, int& done) { - int sz = min(size, ssh->chunk_size); + int sz = min(size - done, ssh->chunk_size); Buffer buffer(sz); int rc = libssh2_sftp_read(handle, buffer, sz); @@ -146,15 +147,18 @@ bool SFtp::Read(SFtpHandle handle, Event&& consumer, int size, SetError(-1, "Read aborted."); ssh->start_time = msecs(); } - if(!rc) + + auto b = !rc || done == size; + + if(b) LLOG("EOF received."); - return rc == 0 || done == size; + return b; } bool SFtp::Write(SFtpHandle handle, const void* buffer, int size, int& done) { int sz = min(size - done, ssh->chunk_size); - + int rc = libssh2_sftp_write(handle, (const char*) buffer + done, sz); if(!WouldBlock(rc) && rc < 0) SetError(rc); @@ -164,16 +168,18 @@ bool SFtp::Write(SFtpHandle handle, const void* buffer, int size, int& done) SetError(-1, "Write aborted."); ssh->start_time = msecs(); } - if(done == size) - LLOG("EOF"); - return rc == 0 || done == size; + auto b = !rc || done == size; + + if(b) + LLOG("EOF received."); + return b; } int SFtp::Get(SFtpHandle handle, void *ptr, int size) { int done = 0; - - Run([=, &done]{ + + Run([=, &done]() mutable { return Read( handle, [=, &done](const void* p, int sz) { @@ -191,7 +197,7 @@ bool SFtp::Put(SFtpHandle handle, const void *ptr, int size) { int done = 0; - Run([=, &done]{ + Run([=, &done]() mutable { return Write(handle, (char*) ptr, size, done); }); @@ -225,7 +231,7 @@ void SFtp::LoadFile(Stream& out, const char *path) SFtpHandle SFtp::OpenDir(const String& path) { SFtpHandle h = nullptr; - + Run([=, &h] () mutable { h = libssh2_sftp_opendir(*sftp_session, path); if(!h && !WouldBlock()) @@ -273,7 +279,7 @@ bool SFtp::ListDir(SFtpHandle handle, DirList& list) do { Zero(attrs); - + rc = libssh2_sftp_readdir_ex( handle, label, sizeof(label), @@ -297,7 +303,7 @@ bool SFtp::ListDir(SFtpHandle handle, DirList& list) while(rc > 0); LLOG(Format("Directory listing is successful. (%d entries)", list.GetCount())); return true; - + }); } @@ -310,7 +316,7 @@ bool SFtp::ListDir(const String& path, DirList& list) bool SFtp::SymLink(const String& path, String* target, int type) { Buffer buffer(512); - + if(type == LIBSSH2_SFTP_SYMLINK) return Run([=, &buffer] () mutable { int rc = libssh2_sftp_symlink_ex( @@ -349,6 +355,19 @@ bool SFtp::SymLink(const String& path, String* target, int type) }); } +SFtp::DirEntry SFtp::GetInfo(const String& path) +{ + DirEntry finfo; + + if(!GetAttrs(path, *finfo)) + return pick(Null); + + finfo.filename = path; + finfo.valid = true; + + return pick(finfo); +} + bool SFtp::GetAttrs(SFtpHandle handle, SFtpAttrs& attrs) { return Run([=, &attrs] () mutable { @@ -393,12 +412,10 @@ Value SFtp::QueryAttr(const String& path, int attr) { DirEntry finfo; Value v; - + if(!GetAttrs(path, *finfo)) return Null; - finfo.filename = path; - switch(attr) { case SFTP_ATTR_FILE: v = finfo.IsFile(); @@ -430,11 +447,6 @@ Value SFtp::QueryAttr(const String& path, int attr) case SFTP_ATTR_LAST_ACCESSED: v = finfo.GetLastAccessed(); break; - case SFTP_ATTR_INFO: - finfo.valid = true; - v = RawPickToValue(pick(finfo)); - finfo = Null; - break; default: break; } @@ -449,7 +461,7 @@ bool SFtp::ModifyAttr(const String& path, int attr, const Value& v) return false; SFtpAttrs& attrs = *finfo; - + switch(attr) { case SFTP_ATTR_SIZE: attrs.flags |= LIBSSH2_SFTP_ATTR_SIZE; @@ -466,7 +478,7 @@ bool SFtp::ModifyAttr(const String& path, int attr, const Value& v) default: break; } - + return SetAttrs(path, ~finfo);; } diff --git a/uppsrc/Core/SSH/SFtp.h b/uppsrc/Core/SSH/SFtp.h index 3db0c7980..8e3e9e048 100644 --- a/uppsrc/Core/SSH/SFtp.h +++ b/uppsrc/Core/SSH/SFtp.h @@ -62,8 +62,8 @@ public: DirEntry() { Zero(); } DirEntry(const Nuller&) { Zero(); } - DirEntry(DirEntry&& e) = default; - DirEntry& operator=(DirEntry&& e) = default; + DirEntry(DirEntry&&) = default; + DirEntry& operator=(DirEntry&&) = default; private: bool CanMode(dword u, dword g, dword o) const; @@ -78,7 +78,7 @@ public: public: SFtp& Timeout(int ms) { ssh->timeout = ms; return *this; } SFtp& WaitStep(int ms) { ssh->waitstep = clamp(ms, 0, INT_MAX); return *this; } - SFtp& ChunkSize(int sz) { ssh->chunk_size = clamp(sz, 128, INT_MAX); return *this; } + SFtp& ChunkSize(int sz) { ssh->chunk_size = clamp(sz, 1, INT_MAX); return *this; } // File SFtpHandle Open(const String& path, dword flags, long mode); @@ -92,12 +92,12 @@ public: int64 GetPos(SFtpHandle handle); // Read/Write - int Get(SFtpHandle handle, void *ptr, int size = INT_MAX); - bool Put(SFtpHandle handle, const void *ptr, int size); - bool SaveFile(const char *path, const String& data); - String LoadFile(const char *path); - bool SaveFile(const char *path, Stream& in); - void LoadFile(Stream& out, const char *path); + int Get(SFtpHandle handle, void *ptr, int size = INT_MAX); + bool Put(SFtpHandle handle, const void *ptr, int size); + bool SaveFile(const char *path, const String& data); + String LoadFile(const char *path); + bool SaveFile(const char *path, Stream& in); + void LoadFile(Stream& out, const char *path); // Directory SFtpHandle OpenDir(const String& path); @@ -115,7 +115,7 @@ public: bool GetAttrs(const String& path, SFtpAttrs& attrs); bool SetAttrs(SFtpHandle handle, const SFtpAttrs& attrs); bool SetAttrs(const String& path, const SFtpAttrs& attrs); -// DirEntry GetInfo(const String& path) { return QueryAttr(path, SFTP_ATTR_INFO); } + DirEntry GetInfo(const String& path); bool SetInfo(const DirEntry& entry) { return SetAttrs(entry.GetName(), ~entry); } int64 GetSize(const String& path) { return QueryAttr(path, SFTP_ATTR_SIZE); } bool SetSize(const String& path, int64 size) { return ModifyAttr(path, SFTP_ATTR_SIZE, size); } @@ -163,7 +163,6 @@ private: SFTP_ATTR_PIPE, SFTP_ATTR_BLOCK, SFTP_ATTR_SPECIAL, - SFTP_ATTR_INFO, SFTP_ATTR_UID, SFTP_ATTR_GID, SFTP_ATTR_PERMISSIONS, @@ -175,51 +174,51 @@ private: class SFtpStream : public BlockStream { protected: - virtual void SetStreamSize(int64 size); - virtual dword Read(int64 at, void *ptr, dword size); - virtual void Write(int64 at, const void *data, dword size); + virtual void SetStreamSize(int64 size); + virtual dword Read(int64 at, void *ptr, dword size); + virtual void Write(int64 at, const void *data, dword size); public: - virtual void Close(); - virtual bool IsOpen() const; + virtual void Close(); + virtual bool IsOpen() const; protected: - SFtp *sftp; - SFtpHandle handle; + SFtp *sftp; + SFtpHandle handle; - void SetPos(int64 pos); - void Init(int64 size); + void SetPos(int64 pos); + void Init(int64 size); public: - operator bool() const { return IsOpen(); } + operator bool() const { return IsOpen(); } - bool Open(SFtp& sftp, const char *filename, dword mode, int acm = 0644); - SFtpStream(SFtp& sftp, const char *filename, dword mode, int acm = 0644); - SFtpStream(); - ~SFtpStream(); - SFtpHandle GetHandle() const { return handle; } + bool Open(SFtp& sftp, const char *filename, dword mode, int acm = 0644); + SFtpStream(SFtp& sftp, const char *filename, dword mode, int acm = 0644); + SFtpStream(); + ~SFtpStream(); + SFtpHandle GetHandle() const { return handle; } }; class SFtpFileOut : public SFtpStream { public: - bool Open(SFtp& sftp, const char *fn, int acm = 0644) { return SFtpStream::Open(sftp, fn, CREATE|NOWRITESHARE, acm); } + bool Open(SFtp& sftp, const char *fn, int acm = 0644) { return SFtpStream::Open(sftp, fn, CREATE|NOWRITESHARE, acm); } - SFtpFileOut(SFtp& sftp, const char *fn) { Open(sftp, fn); } - SFtpFileOut() {} + SFtpFileOut(SFtp& sftp, const char *fn) { Open(sftp, fn); } + SFtpFileOut() {} }; class SFtpFileAppend : public SFtpStream { public: - bool Open(SFtp& sftp, const char *fn) { return SFtpStream::Open(sftp, fn, APPEND|NOWRITESHARE); } + bool Open(SFtp& sftp, const char *fn) { return SFtpStream::Open(sftp, fn, APPEND|NOWRITESHARE); } - SFtpFileAppend(SFtp& sftp, const char *fn) { Open(sftp, fn); } - SFtpFileAppend() {} + SFtpFileAppend(SFtp& sftp, const char *fn) { Open(sftp, fn); } + SFtpFileAppend() {} }; class SFtpFileIn : public SFtpStream { public: - bool Open(SFtp& sftp, const char *fn) { return SFtpStream::Open(sftp, fn, READ); } + bool Open(SFtp& sftp, const char *fn) { return SFtpStream::Open(sftp, fn, READ); } - SFtpFileIn(SFtp& sftp, const char *fn) { Open(sftp, fn); } - SFtpFileIn() {} + SFtpFileIn(SFtp& sftp, const char *fn) { Open(sftp, fn); } + SFtpFileIn() {} }; diff --git a/uppsrc/Core/SSH/Session.h b/uppsrc/Core/SSH/Session.h index 41621256f..7ba9c26a2 100644 --- a/uppsrc/Core/SSH/Session.h +++ b/uppsrc/Core/SSH/Session.h @@ -13,7 +13,6 @@ public: public: SshSession& Timeout(int ms) { ssh->timeout = ms; return *this; } - SshSession& NonBlocking(bool b = true) { return Timeout(b ? 0 : Null);} SshSession& WaitStep(int ms) { ssh->waitstep = clamp(ms, 0, INT_MAX); return *this; } SshSession& Keys(const String& prikey, const String& pubkey, const String& phrase = Null, bool fromfile = true);