SFtp: GetInfo() method re-added. Pick semantics improved & cosmetics.

git-svn-id: svn://ultimatepp.org/upp/trunk@12158 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
oblivion 2018-08-10 20:55:31 +00:00
parent 1f72504a1a
commit f50acb57aa
6 changed files with 83 additions and 73 deletions

View file

@ -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);

View file

@ -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<int>(); }
@ -12,7 +12,7 @@ public:
template <class T> T& To() { auto* t = dynamic_cast<T*>(this); ASSERT(t); return *t; }
template <class T> bool Is() const { return dynamic_cast<const T*>(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<CoreData> 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()); }

View file

@ -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.

View file

@ -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<const void*, int>&& consumer, int size, int& done)
{
int sz = min(size, ssh->chunk_size);
int sz = min(size - done, ssh->chunk_size);
Buffer<char> buffer(sz);
int rc = libssh2_sftp_read(handle, buffer, sz);
@ -146,15 +147,18 @@ bool SFtp::Read(SFtpHandle handle, Event<const void*, int>&& 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<char> 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);;
}

View file

@ -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() {}
};

View file

@ -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);