1 #include "SSH.h"
2 
3 namespace Upp {
4 
5 #define LLOG(x)       do { if(SSH::sTrace) RLOG(SSH::GetName(ssh->otype, ssh->oid) << x); } while(false)
6 #define LDUMPHEX(x)	  do { if(SSH::sTraceVerbose) RDUMPHEX(x); } while(false)
7 
OpenRead(const String & path,ScpAttrs & attrs)8 bool Scp::OpenRead(const String& path, ScpAttrs& attrs)
9 {
10 	Zero(attrs);
11 	return Run([=, &attrs]() mutable {
12 		LIBSSH2_CHANNEL *ch = libssh2_scp_recv2(ssh->session, path, &attrs);
13 		if(!ch && !WouldBlock()) {
14 			LLOG("Unable to open file " << path);
15 			SetError(-1);
16 		}
17 		if(ch) {
18 			channel = MakeOne<LIBSSH2_CHANNEL*>(ch);
19 			LLOG("File " << path << " opened.");
20 		}
21 		return ch;
22 	});
23 }
24 
OpenWrite(const String & path,int64 size,long mode)25 bool Scp::OpenWrite(const String& path, int64 size, long mode)
26 {
27 	return Run([=]() mutable {
28 		LIBSSH2_CHANNEL *ch = libssh2_scp_send64(ssh->session, path, mode, size, 0, 0);
29 		if(!ch && !WouldBlock()) {
30 			LLOG("Unable to open file " << path);
31 			SetError(-1);
32 		}
33 		if(ch) {
34 			channel = MakeOne<LIBSSH2_CHANNEL*>(ch);
35 			LLOG("File " << path << " opened.");
36 		}
37 		return ch;
38 	});
39 }
40 
Load(Stream & s,ScpAttrs a,int64 maxsize)41 bool Scp::Load(Stream& s, ScpAttrs a, int64 maxsize)
42 {
43 	bool nowait = false;
44 	int64 done_ = 0;
45 	int64 size  = a.st_size;
46 	String msg;
47 
48 	if(size < 0 || size >= maxsize) {
49 		msg = "Invald stream size.";
50 	}
51 	else
52 	while(done_ < size && !IsEof() && !IsError()) {
53 		int csz = (int) min<int64>(size - done_, ssh->chunk_size);
54 		Buffer<char> chunk(csz, 0);
55 		int n = Get(chunk, csz);
56 		if(n > 0) {
57 			done_ += n;
58 			s.Put(chunk, n);
59 			if((nowait = WhenProgress(done_, size))) {
60 				msg = "File transfer aborted.";
61 				break;
62 			}
63 		}
64 	}
65 	return Shut(msg, nowait);
66 }
67 
Save(Stream & s)68 bool Scp::Save(Stream& s)
69 {
70 	bool nowait = false;
71 	int64 done_ = 0;
72 	int64 size  = s.GetSize();
73 	String msg;
74 
75 	Buffer<char> chunk(ssh->chunk_size, 0);
76 
77 	while(done_ < size && !IsEof() && !IsError()) {
78 		int l = s.Get(chunk, (int) min<int64>(size - done_, ssh->chunk_size));
79 		int n = Put(chunk, l);
80 		if(n > 0) {
81 			done_ += n;
82 			if(n < l)
83 				s.Seek(n);
84 			if((nowait = WhenProgress(done_, size))) {
85 				msg = "File transfer aborted.";;
86 				break;
87 			}
88 		}
89 	}
90 	return Shut(msg, nowait);
91 }
92 
SaveFile(const char * path,const String & data)93 bool Scp::SaveFile(const char *path, const String& data)
94 {
95 	StringStream s(data);
96 	return OpenWrite(path, s.GetSize()) && Save(s);
97 }
98 
LoadFile(const char * path)99 String Scp::LoadFile(const char *path)
100 {
101 	StringStream s;
102 	ScpAttrs attrs;
103 	if(OpenRead(path, attrs))
104 		Load(s, attrs, INT_MAX);
105 	return pick(s.GetResult());
106 }
107 
SaveFile(const char * path,Stream & in)108 bool Scp::SaveFile(const char *path, Stream& in)
109 {
110 	 return OpenWrite(path, in.GetSize()) && Save(in);
111 }
112 
LoadFile(Stream & out,const char * path)113 bool Scp::LoadFile(Stream& out, const char *path)
114 {
115 	ScpAttrs attrs;
116 	return OpenRead(path, attrs) && Load(out, attrs);
117 }
118 }