1 /*
2  * Part of WCM Commander
3  * https://github.com/corporateshark/WCMCommander
4  * wcm@linderdaum.com
5  */
6 
7 #ifdef _WIN32
8 #  include <winsock2.h>
9 #endif
10 
11 
12 #include "vfs-sftp.h"
13 
14 #ifdef LIBSSH2_EXIST
15 
16 #include "string-util.h"
17 
18 #define SSH_PASSWORD_ATTEMPTS 3
19 
InitSSH()20 void InitSSH()
21 {
22 	libssh2_init( 0 );
23 }
24 
GetDefaultSshKeys(FSString & pub_key,FSString & private_key)25 bool GetDefaultSshKeys( FSString& pub_key, FSString& private_key )
26 {
27 	// TODO: Get by-host keyfiles, configure keyfiles, etc etc
28 	// http://askubuntu.com/questions/30788/does-ssh-key-need-to-be-named-id-rsa
29 
30 #if _MSC_VER > 1700
31 	char* home;
32 	size_t size;
33 	_dupenv_s(&home, &size, "HOME" );
34 #else
35 	const char* home = getenv( "HOME" );
36 #endif
37 
38 	if ( !home )
39 	{
40 		return false;
41 	}
42 
43 	pub_key = carray_cat<char>( home, "/.ssh/id_rsa.pub" ).data();
44 	private_key = carray_cat<char>( home, "/.ssh/id_rsa" ).data();
45 
46 #if _MSC_VER > 1700
47 	// deallocate after _dupenv_s()
48 	free(home);
49 #endif
50 
51 	struct stat sb;
52 	if ( ( stat( pub_key.GetUtf8(), &sb ) != 0 ) || ( stat( private_key.GetUtf8(), &sb ) != 0 ) )
53 	{
54 		pub_key = "";
55 		private_key = "";
56 		return false;
57 	}
58 
59 	return true;
60 }
61 
62 
63 enum INT_SSH_ERRORS
64 {
65 	SSH_INTERROR_NOTSUPPORT = -20,
66 	SSH_INTERROR_X3 = -21,
67 	SSH_INTERROR_CONNECT = -22,
68 	SSH_INTERROR_AUTH = -23,
69 	SSH_INTERROR_FATAL = -24,
70 	SSH_INTERROR_OUTOF = -25,
71 	SSH_INTERROR_UNSUPPORTED_AUTH = -26,
72 	SSH_INTERROR_STOPPED = -50
73 };
74 
75 
FSSftp(FSSftpParam * param)76 FSSftp::FSSftp( FSSftpParam* param )
77 	:  FS( SFTP ), sshSession( 0 ), sftpSession( 0 )
78 {
79 	if ( param )
80 	{
81 		_operParam = *param;
82 		_infoParam = *param;
83 	}
84 
85 	for ( int i = 0; i < MAX_FILES; i++ )
86 	{
87 		fileTable[i] = 0;
88 	}
89 }
90 
91 
WaitSocket(FSCInfo * info)92 void FSSftp::WaitSocket( FSCInfo* info ) //throw int(errno) or int(-2) on stop
93 {
94 	while ( true )
95 	{
96 		if ( info && info->IsStopped() ) { throw int( -2 ); } //stopped
97 
98 		int dir = libssh2_session_block_directions( sshSession );
99 
100 		if ( ( dir & ( LIBSSH2_SESSION_BLOCK_INBOUND | LIBSSH2_SESSION_BLOCK_OUTBOUND ) ) == 0 )
101 		{
102 			return ;
103 		}
104 
105 		int n = _sock.Select2(
106 					( dir & LIBSSH2_SESSION_BLOCK_INBOUND ) != 0,
107 					( dir & LIBSSH2_SESSION_BLOCK_OUTBOUND ) != 0,
108 					3 );
109 
110 		if ( n > 0 ) { return; }
111 	}
112 }
113 
114 
115 #define WHILE_EAGAIN_(retvar, a) \
116 while (true) {\
117    retvar = a;\
118    if (retvar != LIBSSH2_ERROR_EAGAIN) break;\
119    WaitSocket(info);\
120 }
121 
CheckSessionEagain()122 void FSSftp::CheckSessionEagain()
123 {
124 	int e = libssh2_session_last_errno( this->sshSession );
125 
126 	if ( e != LIBSSH2_ERROR_EAGAIN ) { throw int( e - 1000 ); }
127 }
128 
TransSftpError(int e,LIBSSH2_SFTP * sftp)129 inline int TransSftpError( int e, LIBSSH2_SFTP* sftp )
130 {
131 	if ( e == LIBSSH2_ERROR_SFTP_PROTOCOL ) { e = libssh2_sftp_last_error( sftp ); }
132 
133 	return e < 0 ? e - 1000 : e;
134 }
135 
CheckSFTPEagain()136 void FSSftp::CheckSFTPEagain()
137 {
138 	int e = libssh2_session_last_errno( sshSession );
139 
140 	if ( e == LIBSSH2_ERROR_EAGAIN ) { return; }
141 
142 	throw TransSftpError( e, sftpSession );
143 }
144 
CheckSFTP(int err)145 inline void FSSftp::CheckSFTP( int err )
146 {
147 	if ( !err ) { return; }
148 
149 	throw TransSftpError( err, sftpSession );
150 }
151 
152 
CopyToStrZ(const char * s,int size)153 static std::vector<char> CopyToStrZ( const char* s, int size )
154 {
155 	if ( size <= 0 ) { size = 0; }
156 
157 	std::vector<char> p( size + 1 );
158 
159 	if ( size > 0 ) { memcpy( p.data(), s, size ); }
160 
161 	p[size] = 0;
162 	return p;
163 }
164 
165 static Mutex kbdIntMutex; //NO lock in callback
166 static FSCInfo* volatile kbdIntInfo = 0;
167 static FSSftpParam* volatile kbdIntParam = 0;
168 
KbIntCallback(const char * name,int name_len,const char * instruction,int instruction_len,int num_prompts,const LIBSSH2_USERAUTH_KBDINT_PROMPT * prompts,LIBSSH2_USERAUTH_KBDINT_RESPONSE * responses,void ** anstract)169 void KbIntCallback(
170    const char* name, int name_len,
171    const char* instruction, int instruction_len,
172    int num_prompts,
173    const LIBSSH2_USERAUTH_KBDINT_PROMPT* prompts,
174    LIBSSH2_USERAUTH_KBDINT_RESPONSE* responses,
175    void** anstract )
176 {
177 	if ( num_prompts <= 0 ) { return; }
178 
179 	if ( !kbdIntInfo ) { return; }
180 
181 	try
182 	{
183 
184 		std::vector<FSPromptData> pData( num_prompts );
185 		int i;
186 
187 		for ( i = 0; i < num_prompts; i++ )
188 		{
189 			pData[i].visible = prompts[i].echo != 0;
190 			pData[i].prompt = std::string( prompts[i].text, prompts[i].length );
191 		}
192 
193 		if ( !kbdIntInfo->Prompt(
194 				utf8_to_unicode( "SFTP" ).data(),
195 				utf8str_to_unicode( kbdIntParam->user + "@" + kbdIntParam->server ).data(),
196 				pData.data(), num_prompts ) )
197 		{
198 			return;
199 		}
200 
201 		for ( i = 0; i < num_prompts; i++ )
202 		{
203 			std::string str = ( char* )FSString( pData[i].prompt.c_str() ).Get( kbdIntParam->charset );
204 
205 			if ( str.data() )
206 			{
207 				int l = strlen( str.data() );
208 				responses[i].length = l;
209 				responses[i].text = ( char* ) malloc( l + 1 );
210 
211 				if ( responses[i].text )
212 				{
213 #if _MSC_VER > 1700
214 					Lstrncpy( responses[i].text, l + 1, str.data(), _TRUNCATE );
215 #else
216 					Lstrncpy( responses[i].text, str.data(), l + 1 );
217 #endif
218 				}
219 			}
220 		}
221 
222 	}
223 	catch ( cexception* ex )
224 	{
225 		fprintf( stderr, "exception in kbdint callback used with libssh2: %s\n", ex->message() );
226 		ex->destroy();
227 	}
228 	catch ( ... )
229 	{
230 		fprintf( stderr, "excention (...) in kbdint callback used with libssh2\n" );
231 	}
232 }
233 
CheckSession(int * err,FSCInfo * info)234 int FSSftp::CheckSession( int* err, FSCInfo* info )
235 {
236 
237 	if ( sshSession ) { return 0; }
238 
239 	try
240 	{
241 
242 		unsigned ip;
243 		int e;
244 
245 		if ( !GetHostIp( _operParam.server.c_str(), &ip, &e ) )
246 		{
247 			throw int( e );
248 		}
249 
250 		_sock.Create();
251 		_sock.Connect( ntohl( ip ), _operParam.port );
252 
253 		sshSession = libssh2_session_init();
254 
255 		if ( !sshSession ) { throw int( SSH_INTERROR_X3 ); }
256 
257 		libssh2_session_set_blocking( sshSession, 0 );
258 
259 		WHILE_EAGAIN_( e, libssh2_session_handshake( sshSession, _sock.Id() ) );
260 
261 		if ( e ) { throw int( e - 1000 ); }
262 
263 		FSString userName = "";
264 
265 		if ( !_operParam.user.empty() )
266 		{
267 			userName = _operParam.user.c_str();
268 		}
269 		else
270 		{
271 #ifndef _WIN32
272 			char* ret = getenv( "LOGNAME" );
273 
274 			if ( ret )
275 			{
276 				userName = FSString( sys_charset_id, ret );
277 				_operParam.user = userName.GetUtf8();
278 
279 				MutexLock infoLock( &infoMutex );
280 				_infoParam.user = userName.GetUtf8();
281 			}
282 
283 #endif
284 		};
285 
286 		char* authList = 0;
287 
288 		char* charUserName = ( char* )userName.Get( _operParam.charset );
289 
290 		while ( true )
291 		{
292 			authList = libssh2_userauth_list( sshSession, charUserName, strlen( charUserName ) );
293 
294 			if ( authList ) { break; }
295 
296 			CheckSessionEagain();
297 			WaitSocket( info );
298 		}
299 
300 		//publickey,password,keyboard-interactive
301 		static const char passId[] = "password";
302 		static const char publickey[] = "publickey";
303 		static const char kInterId[] = "keyboard-interactive";
304 
305 		static unicode_t userSymbol[] = { '@', 0 };
306 
307 		int ret = 0;
308 #if _MSC_VER > 1700
309 		char* next_tok = nullptr;
310 		for ( char* authorizationMethod = strtok_s( authList, ",", &next_tok );
311 			  authorizationMethod != nullptr;
312 			  authorizationMethod = strtok_s( nullptr, ",", &next_tok )
313 			)
314 #else
315 		for ( char* authorizationMethod = strtok( authList, "," );
316 			  authorizationMethod != nullptr;
317 			  authorizationMethod = strtok( nullptr, "," ) )
318 #endif
319 		{
320 			if ( !strcmp( authorizationMethod, publickey ) )
321 			{
322 				FSString public_key;
323 				FSString private_key;
324 				if( !GetDefaultSshKeys(public_key, private_key) )
325 				{
326 					continue;
327 				}
328 
329 				WHILE_EAGAIN_( ret, libssh2_userauth_publickey_fromfile ( sshSession, charUserName, public_key.GetUtf8(), private_key.GetUtf8(), "" ) );
330 
331 				if ( !ret )
332 				{
333 					fprintf(stderr, "You shouldn't use keys with an empty passphrase!\n");
334 					break;
335 				}
336 
337 				// TODO: prompt for key password. Copied from SO, didn't work:
338 				// http://stackoverflow.com/questions/14952702/
339 //				else if (ret == LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED)
340 //				{
341 //					// if we get here it means the public key was initially accepted
342 //					// but the private key has a non-empty passphrase
343 //					for (int i = 0; i < SSH_PASSWORD_ATTEMPTS; ++i)
344 //					{
345 //
346 //						FSPromptData data;
347 //						data.visible = false;
348 //						data.prompt = utf8_to_unicode( "Private key password:" ).data();
349 //
350 //						if ( !info->Prompt(
351 //								utf8_to_unicode( "SFTP_" ).data(),
352 //								carray_cat<unicode_t>( userName.GetUnicode(), userSymbol, _operParam.server.Data() ).data(),
353 //								&data, 1 ) ) { throw int( SSH_INTERROR_STOPPED ); }
354 //
355 //						char* password = ( char* )FSString( data.prompt.Data() ).Get( _operParam.charset );
356 //
357 //						ret = libssh2_userauth_publickey_fromfile( sshSession,
358 //								charUserName, public_key.GetUtf8(), private_key.GetUtf8(), password );
359 //						if ( ret != LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED ) break;
360 //					}
361 //				}
362 
363 				if ( ret )
364 				{
365 					// http://www.libssh2.org/libssh2_session_last_error.html
366 					// Do I get it right that when want_buf==0 I don't need to release the buffer?
367 					char* buf;
368 					libssh2_session_last_error( sshSession, &buf, NULL, 0 );
369 					fprintf( stderr, "Authentication using key failed: %s!\n", buf );
370 				}
371 			}
372 			else if ( !strcmp( authorizationMethod, passId ) )
373 			{
374 				FSPromptData data;
375 				data.visible = false;
376 				data.prompt = "Password:";
377 
378 				if ( !info->Prompt(
379 						utf8_to_unicode( "SFTP_" ).data(),
380 						carray_cat<unicode_t>( userName.GetUnicode(), userSymbol, utf8str_to_unicode(_operParam.server).data() ).data(),
381 						&data, 1 ) ) { throw int( SSH_INTERROR_STOPPED ); }
382 
383 				WHILE_EAGAIN_( ret, libssh2_userauth_password( sshSession,
384 															   ( char* )FSString( _operParam.user.c_str() ).Get( _operParam.charset ),
385 															   ( char* )FSString( data.prompt.c_str() ).Get( _operParam.charset ) ) );
386 
387 				if ( !ret ) { break; }
388 			}
389 			else if ( !strcmp( authorizationMethod, kInterId ) )
390 			{
391 				MutexLock lock( &kbdIntMutex );
392 				kbdIntInfo = info;
393 				kbdIntParam = &_operParam;
394 
395 				WHILE_EAGAIN_( ret,
396 							   libssh2_userauth_keyboard_interactive( sshSession,
397 																	  ( char* )FSString( _operParam.user.c_str() ).Get( _operParam.charset ),
398 																	  KbIntCallback )
399 							 );
400 
401 				if ( ret == 0 ) { break; }
402 			}
403 
404 		};
405 
406 		if ( ret != 0 ) { throw int( ret - 1000 ); }
407 
408 		while ( true )
409 		{
410 			sftpSession = libssh2_sftp_init( sshSession );
411 
412 			if ( sftpSession ) { break; }
413 
414 			if ( !sftpSession )
415 			{
416 				int e = libssh2_session_last_errno( sshSession );
417 
418 				if ( e != LIBSSH2_ERROR_EAGAIN ) { throw int( e - 1000 ); }
419 			}
420 
421 			WaitSocket( info );
422 		}
423 
424 		return 0;
425 
426 	}
427 	catch ( int e )
428 	{
429 		if ( err ) { *err = e; }
430 
431 		if ( sshSession ) { libssh2_session_free( sshSession ); }
432 
433 		sshSession = 0;
434 		sftpSession = 0;
435 		_sock.Close( false );
436 		return ( e == -2 ) ? -2 : -1;
437 	}
438 
439 }
440 
CloseSession()441 void FSSftp::CloseSession()
442 {
443 	if ( sshSession ) { libssh2_session_free( sshSession ); }
444 
445 	sshSession = 0;
446 	sftpSession = 0;
447 
448 	if ( _sock.IsValid() ) { _sock.Close( false ); }
449 }
450 
451 
Flags()452 unsigned FSSftp::Flags() { return HAVE_READ | HAVE_WRITE | HAVE_SYMLINK | HAVE_SEEK; }
453 
IsEEXIST(int err)454 bool  FSSftp::IsEEXIST( int err ) { return err == EEXIST; }
IsENOENT(int err)455 bool  FSSftp::IsENOENT( int err ) { return err == ENOENT; }
IsEXDEV(int err)456 bool  FSSftp::IsEXDEV( int err ) { return err == EXDEV; }
457 
Equal(FS * fs)458 bool FSSftp::Equal( FS* fs )
459 {
460 	if ( !fs || fs->Type() != FS::SFTP ) { return false; }
461 
462 	if ( fs == this ) { return true; }
463 
464 	FSSftp* f = ( FSSftp* )fs;
465 
466 	MutexLock l1( &infoMutex );
467 	MutexLock l2( &( f->infoMutex ) );
468 
469 	if ( _infoParam.isSet != f->_infoParam.isSet )
470 	{
471 		return false;
472 	}
473 
474 	return _infoParam.server == f->_infoParam.server &&
475 		   _infoParam.user == f->_infoParam.user &&
476 		   _infoParam.port == f->_infoParam.port &&
477 		   _infoParam.charset == f->_infoParam.charset;
478 }
479 
480 
481 
StrError(int err)482 FSString FSSftp::StrError( int err )
483 {
484 	const char* s = "";
485 
486 	if ( err < -500 )
487 	{
488 		switch ( err + 1000 )
489 		{
490 			case LIBSSH2_ERROR_SOCKET_NONE:
491 				s = "LIBSSH2_ERROR_SOCKET_NONE";
492 				break;
493 
494 			case LIBSSH2_ERROR_BANNER_RECV:
495 				s = "LIBSSH2_ERROR_BANNER_RECV";
496 				break;
497 
498 			case LIBSSH2_ERROR_BANNER_SEND:
499 				s = "LIBSSH2_ERROR_BANNER_SEND";
500 				break;
501 
502 			case LIBSSH2_ERROR_INVALID_MAC:
503 				s = "LIBSSH2_ERROR_INVALID_MAC";
504 				break;
505 
506 			case LIBSSH2_ERROR_KEX_FAILURE:
507 				s = "LIBSSH2_ERROR_KEX_FAILURE";
508 				break;
509 
510 			case LIBSSH2_ERROR_ALLOC:
511 				s = "LIBSSH2_ERROR_ALLOC";
512 				break;
513 
514 			case LIBSSH2_ERROR_SOCKET_SEND:
515 				s = "LIBSSH2_ERROR_SOCKET_SEND";
516 				break;
517 
518 			case LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE:
519 				s = "LIBSSH2_ERROR_KEY_EXCHANGE_FAILURE";
520 				break;
521 
522 			case LIBSSH2_ERROR_TIMEOUT:
523 				s = "LIBSSH2_ERROR_TIMEOUT";
524 				break;
525 
526 			case LIBSSH2_ERROR_HOSTKEY_INIT:
527 				s = "LIBSSH2_ERROR_HOSTKEY_INIT";
528 				break;
529 
530 			case LIBSSH2_ERROR_HOSTKEY_SIGN:
531 				s = "LIBSSH2_ERROR_HOSTKEY_SIGN";
532 				break;
533 
534 			case LIBSSH2_ERROR_DECRYPT:
535 				s = "LIBSSH2_ERROR_DECRYPT";
536 				break;
537 
538 			case LIBSSH2_ERROR_SOCKET_DISCONNECT:
539 				s = "LIBSSH2_ERROR_SOCKET_DISCONNECT";
540 				break;
541 
542 			case LIBSSH2_ERROR_PROTO:
543 				s = "LIBSSH2_ERROR_PROTO";
544 				break;
545 
546 			case LIBSSH2_ERROR_PASSWORD_EXPIRED:
547 				s = "LIBSSH2_ERROR_PASSWORD_EXPIRED";
548 				break;
549 
550 			case LIBSSH2_ERROR_FILE:
551 				s = "LIBSSH2_ERROR_FILE";
552 				break;
553 
554 			case LIBSSH2_ERROR_METHOD_NONE:
555 				s = "LIBSSH2_ERROR_METHOD_NONE";
556 				break;
557 
558 			case LIBSSH2_ERROR_AUTHENTICATION_FAILED:
559 				s = "Authentication failed";
560 				break;
561 
562 			case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
563 				s = "LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED";
564 				break;
565 
566 			case LIBSSH2_ERROR_CHANNEL_OUTOFORDER:
567 				s = "LIBSSH2_ERROR_CHANNEL_OUTOFORDER";
568 				break;
569 
570 			case LIBSSH2_ERROR_CHANNEL_FAILURE:
571 				s = "LIBSSH2_ERROR_CHANNEL_FAILURE";
572 				break;
573 
574 			case LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED:
575 				s = "LIBSSH2_ERROR_CHANNEL_REQUEST_DENIED";
576 				break;
577 
578 			case LIBSSH2_ERROR_CHANNEL_UNKNOWN:
579 				s = "LIBSSH2_ERROR_CHANNEL_UNKNOWN";
580 				break;
581 
582 			case LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED:
583 				s = "LIBSSH2_ERROR_CHANNEL_WINDOW_EXCEEDED";
584 				break;
585 
586 			case LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED:
587 				s = "LIBSSH2_ERROR_CHANNEL_PACKET_EXCEEDED";
588 				break;
589 
590 			case LIBSSH2_ERROR_CHANNEL_CLOSED:
591 				s = "LIBSSH2_ERROR_CHANNEL_CLOSED";
592 				break;
593 
594 			case LIBSSH2_ERROR_CHANNEL_EOF_SENT:
595 				s = "LIBSSH2_ERROR_CHANNEL_EOF_SENT";
596 				break;
597 
598 			case LIBSSH2_ERROR_SCP_PROTOCOL:
599 				s = "LIBSSH2_ERROR_SCP_PROTOCOL";
600 				break;
601 
602 			case LIBSSH2_ERROR_ZLIB:
603 				s = "LIBSSH2_ERROR_ZLIB";
604 				break;
605 
606 			case LIBSSH2_ERROR_SOCKET_TIMEOUT:
607 				s = "LIBSSH2_ERROR_SOCKET_TIMEOUT";
608 				break;
609 
610 			case LIBSSH2_ERROR_SFTP_PROTOCOL:
611 				s = "LIBSSH2_ERROR_SFTP_PROTOCOL";
612 				break;
613 
614 			case LIBSSH2_ERROR_REQUEST_DENIED:
615 				s = "LIBSSH2_ERROR_REQUEST_DENIED";
616 				break;
617 
618 			case LIBSSH2_ERROR_METHOD_NOT_SUPPORTED:
619 				s = "LIBSSH2_ERROR_METHOD_NOT_SUPPORTED";
620 				break;
621 
622 			case LIBSSH2_ERROR_INVAL:
623 				s = "LIBSSH2_ERROR_INVAL";
624 				break;
625 
626 			case LIBSSH2_ERROR_INVALID_POLL_TYPE:
627 				s = "LIBSSH2_ERROR_INVALID_POLL_TYPE";
628 				break;
629 
630 			case LIBSSH2_ERROR_PUBLICKEY_PROTOCOL:
631 				s = "LIBSSH2_ERROR_PUBLICKEY_PROTOCOL";
632 				break;
633 
634 			case LIBSSH2_ERROR_EAGAIN:
635 				s = "LIBSSH2_ERROR_EAGAIN";
636 				break;
637 
638 			case LIBSSH2_ERROR_BUFFER_TOO_SMALL:
639 				s = "LIBSSH2_ERROR_BUFFER_TOO_SMALL";
640 				break;
641 
642 			case LIBSSH2_ERROR_BAD_USE:
643 				s = "LIBSSH2_ERROR_BAD_USE";
644 				break;
645 
646 			case LIBSSH2_ERROR_COMPRESS:
647 				s = "LIBSSH2_ERROR_COMPRESS";
648 				break;
649 
650 			case LIBSSH2_ERROR_OUT_OF_BOUNDARY:
651 				s = "LIBSSH2_ERROR_OUT_OF_BOUNDARY";
652 				break;
653 
654 			case LIBSSH2_ERROR_AGENT_PROTOCOL:
655 				s = "LIBSSH2_ERROR_AGENT_PROTOCOL";
656 				break;
657 
658 			case LIBSSH2_ERROR_SOCKET_RECV:
659 				s = "LIBSSH2_ERROR_SOCKET_RECV";
660 				break;
661 
662 			case LIBSSH2_ERROR_ENCRYPT:
663 				s = "LIBSSH2_ERROR_ENCRYPT";
664 				break;
665 
666 			case LIBSSH2_ERROR_BAD_SOCKET:
667 				s = "LIBSSH2_ERROR_BAD_SOCKET";
668 				break;
669 
670 			default:
671 				s = "LIBSSH2_ERROR_???";
672 				break;
673 		}
674 
675 	}
676 	else
677 	{
678 		switch ( err )
679 		{
680 			case SSH_INTERROR_NOTSUPPORT:
681 				s = "not supported operation";
682 				break;
683 
684 			case SSH_INTERROR_X3:
685 				s = "X3";
686 				break;
687 
688 			case SSH_INTERROR_CONNECT:
689 				s = "connection failed";
690 				break;
691 
692 			case SSH_INTERROR_AUTH:
693 				s = "authorization failed";
694 				break;
695 
696 			case SSH_INTERROR_FATAL:
697 				s = "fatal ssh error";
698 				break;
699 
700 			case SSH_INTERROR_STOPPED:
701 				s = "Process stopped";
702 				break;
703 
704 			default:
705 				if ( err >= 0 )
706 				{
707 					sys_char_t buf[0x100];
708 					FSString str;
709 					str.SetSys( sys_error_str( err, buf, 0x100 ) );
710 					return str;
711 				}
712 
713 				char buf[0x100];
714 				Lsnprintf( buf, sizeof( buf ), "err : %i ???", err );
715 				FSString str( CS_UTF8, buf );
716 				return str;
717 		}
718 	}
719 
720 	return FSString( CS_UTF8, s );
721 }
722 
OpenRead(FSPath & path,int flags,int * err,FSCInfo * info)723 int FSSftp::OpenRead ( FSPath& path, int flags, int* err, FSCInfo* info )
724 {
725 	MutexLock lock( &mutex );
726 	int ret = CheckSession( err, info );
727 
728 	if ( ret ) { return ret; }
729 
730 	int n = 0;
731 
732 	for ( ; n < MAX_FILES; n++ )
733 		if ( !fileTable[n] ) { break; }
734 
735 	if ( n >= MAX_FILES )
736 	{
737 		if ( err ) { *err = SSH_INTERROR_OUTOF; }
738 
739 		return -1;
740 	}
741 
742 	try
743 	{
744 		LIBSSH2_SFTP_HANDLE* fd = 0;
745 
746 		while ( true )
747 		{
748 			fd = libssh2_sftp_open( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ),
749 									LIBSSH2_FXF_READ,
750 									0 );
751 
752 			if ( fd ) { break; }
753 
754 			CheckSFTPEagain();
755 			WaitSocket( info );
756 		}
757 
758 		fileTable[n] = fd;
759 
760 	}
761 	catch ( int e )
762 	{
763 		if ( err ) { *err = e; }
764 
765 		return ( e == -2 ) ? -2 : -1;
766 	}
767 
768 	return n;
769 }
770 
OpenCreate(FSPath & path,bool overwrite,int mode,int flags,int * err,FSCInfo * info)771 int FSSftp::OpenCreate  ( FSPath& path, bool overwrite, int mode, int flags, int* err, FSCInfo* info )
772 {
773 	MutexLock lock( &mutex );
774 	int ret = CheckSession( err, info );
775 
776 	if ( ret ) { return ret; }
777 
778 	int n = 0;
779 
780 	try
781 	{
782 		if ( !overwrite )
783 		{
784 			/* странная херня, при наличии файла с  O_EXCL,  выдает не EEXIST, а "прерван системный вызов"
785 			   поэтому встанил эту дурацкую проверку на наличие
786 			*/
787 			LIBSSH2_SFTP_ATTRIBUTES attr;
788 			int ret;
789 			WHILE_EAGAIN_( ret, libssh2_sftp_lstat( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ), &attr ) );
790 
791 			if ( !ret ) { if ( err ) { *err = EEXIST; } return -1; }
792 		}
793 
794 		for ( n = 0; n < MAX_FILES; n++ )
795 			if ( !fileTable[n] ) { break; }
796 
797 		if ( n >= MAX_FILES )
798 		{
799 			if ( err ) { *err = SSH_INTERROR_OUTOF; }
800 
801 			return -1;
802 		}
803 
804 
805 		LIBSSH2_SFTP_HANDLE* fd = 0;
806 
807 		while ( true )
808 		{
809 			fd = libssh2_sftp_open( sftpSession,
810 									( char* )path.GetString( _operParam.charset, '/' ),
811 									LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE | ( overwrite ? LIBSSH2_FXF_TRUNC : LIBSSH2_FXF_EXCL ),
812 									mode );
813 
814 			if ( fd ) { break; }
815 
816 			CheckSFTPEagain();
817 			WaitSocket( info );
818 		}
819 
820 		fileTable[n] = fd;
821 
822 	}
823 	catch ( int e )
824 	{
825 		if ( err ) { *err = e; }
826 
827 		return ( e == -2 ) ? -2 : -1;
828 	}
829 
830 	return n;
831 }
832 
Close(int fd,int * err,FSCInfo * info)833 int FSSftp::Close ( int fd, int* err, FSCInfo* info )
834 {
835 	MutexLock lock( &mutex );
836 	int ret = CheckSession( err, info );
837 
838 	if ( ret ) { return ret; }
839 
840 	if ( fd < 0 || fd >= MAX_FILES || !fileTable[fd] )
841 	{
842 		if ( err ) { *err = EINVAL; }
843 
844 		return -1;
845 	}
846 
847 	try
848 	{
849 		int ret;
850 		WHILE_EAGAIN_( ret, libssh2_sftp_close( fileTable[fd] ) );
851 		CheckSFTP( ret );
852 
853 	}
854 	catch ( int e )
855 	{
856 		if ( err ) { *err = e; }
857 
858 		return ( e == -2 ) ? -2 : -1;
859 	}
860 
861 	fileTable[fd] = 0;
862 	return 0;
863 }
864 
Read(int fd,void * buf,int size,int * err,FSCInfo * info)865 int FSSftp::Read  ( int fd, void* buf, int size, int* err, FSCInfo* info )
866 {
867 	MutexLock lock( &mutex );
868 	int ret = CheckSession( err, info );
869 
870 	if ( ret ) { return ret; }
871 
872 	if ( fd < 0 || fd >= MAX_FILES || !fileTable[fd] )
873 	{
874 		if ( err ) { *err = EINVAL; }
875 
876 		return -1;
877 	}
878 
879 	try
880 	{
881 		int bytes;
882 		WHILE_EAGAIN_( bytes, libssh2_sftp_read( fileTable[fd], ( char* )buf, size ) );
883 
884 		if ( bytes < 0 ) { CheckSFTP( bytes ); }
885 
886 		return bytes;
887 	}
888 	catch ( int e )
889 	{
890 		if ( err ) { *err = e; }
891 
892 		return ( e == -2 ) ? -2 : -1;
893 	}
894 }
895 
896 
Write(int fd,void * buf,int size,int * err,FSCInfo * info)897 int FSSftp::Write ( int fd, void* buf, int size, int* err, FSCInfo* info )
898 {
899 	MutexLock lock( &mutex );
900 	int ret = CheckSession( err, info );
901 
902 	if ( ret ) { return ret; }
903 
904 	if ( fd < 0 || fd >= MAX_FILES || !fileTable[fd] )
905 	{
906 		if ( err ) { *err = EINVAL; }
907 
908 		return -1;
909 	}
910 
911 	try
912 	{
913 		int bytes = 0;
914 		char* s = ( char* )buf;
915 
916 		while ( size > 0 )
917 		{
918 			int ret;
919 			WHILE_EAGAIN_( ret, libssh2_sftp_write( fileTable[fd], s, size ) );
920 
921 			if ( ret < 0 ) { CheckSFTP( ret ); }
922 
923 			if ( !ret ) { break; }
924 
925 			bytes += ret;
926 			size -= ret;
927 			s += ret;
928 		}
929 
930 		return bytes;
931 	}
932 	catch ( int e )
933 	{
934 		if ( err ) { *err = e; }
935 
936 		return ( e == -2 ) ? -2 : -1;
937 	}
938 }
939 
Seek(int fd,SEEK_FILE_MODE mode,seek_t pos,seek_t * pRet,int * err,FSCInfo * info)940 int FSSftp::Seek( int fd, SEEK_FILE_MODE mode, seek_t pos, seek_t* pRet,  int* err, FSCInfo* info )
941 {
942 	MutexLock lock( &mutex );
943 	int ret = CheckSession( err, info );
944 
945 	if ( ret ) { return ret; }
946 
947 	if ( fd < 0 || fd >= MAX_FILES || !fileTable[fd] )
948 	{
949 		if ( err ) { *err = EINVAL; }
950 
951 		return -1;
952 	}
953 
954 	//???
955 	if ( mode == FSEEK_BEGIN )
956 	{
957 		libssh2_sftp_seek64( fileTable[fd],   pos );
958 
959 		if ( pRet ) { *pRet = pos; }
960 
961 		return 0;
962 	}
963 
964 	if ( err )
965 	{
966 		*err = EINVAL;
967 	}
968 
969 	return -1;
970 }
971 
972 
Rename(FSPath & oldpath,FSPath & newpath,int * err,FSCInfo * info)973 int FSSftp::Rename   ( FSPath&  oldpath, FSPath& newpath, int* err,  FSCInfo* info )
974 {
975 	MutexLock lock( &mutex );
976 	int ret = CheckSession( err, info );
977 
978 	if ( ret ) { return ret; }
979 
980 	try
981 	{
982 		int ret;
983 		WHILE_EAGAIN_( ret, libssh2_sftp_rename( sftpSession, ( char* ) oldpath.GetString( _operParam.charset, '/' ), ( char* ) newpath.GetString( _operParam.charset, '/' ) ) );
984 		CheckSFTP( ret );
985 	}
986 	catch ( int e )
987 	{
988 
989 		if ( err ) { *err = e; }
990 
991 		return ( e == -2 ) ? -2 : -1;
992 	}
993 
994 	return 0;
995 }
996 
997 
MkDir(FSPath & path,int mode,int * err,FSCInfo * info)998 int FSSftp::MkDir ( FSPath& path, int mode, int* err,  FSCInfo* info )
999 {
1000 	MutexLock lock( &mutex );
1001 	int ret = CheckSession( err, info );
1002 
1003 	if ( ret ) { return ret; }
1004 
1005 	try
1006 	{
1007 		int ret;
1008 		WHILE_EAGAIN_( ret, libssh2_sftp_mkdir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ), mode ) );
1009 		CheckSFTP( ret );
1010 	}
1011 	catch ( int e )
1012 	{
1013 		if ( err ) { *err = e; }
1014 
1015 		return ( e == -2 ) ? -2 : -1;
1016 	}
1017 
1018 	return 0;
1019 }
1020 
Delete(FSPath & path,int * err,FSCInfo * info)1021 int FSSftp::Delete   ( FSPath& path, int* err, FSCInfo* info )
1022 {
1023 	MutexLock lock( &mutex );
1024 	int ret = CheckSession( err, info );
1025 
1026 	if ( ret ) { return ret; }
1027 
1028 	try
1029 	{
1030 		int ret;
1031 		WHILE_EAGAIN_( ret, libssh2_sftp_unlink( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) ) );
1032 		CheckSFTP( ret );
1033 	}
1034 	catch ( int e )
1035 	{
1036 		if ( err ) { *err = e; }
1037 
1038 		return ( e == -2 ) ? -2 : -1;
1039 	}
1040 
1041 	return 0;
1042 }
1043 
RmDir(FSPath & path,int * err,FSCInfo * info)1044 int FSSftp::RmDir ( FSPath& path, int* err, FSCInfo* info )
1045 {
1046 	MutexLock lock( &mutex );
1047 	int ret = CheckSession( err, info );
1048 
1049 	if ( ret ) { return ret; }
1050 
1051 	try
1052 	{
1053 		int ret;
1054 		WHILE_EAGAIN_( ret, libssh2_sftp_rmdir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) ) );
1055 		CheckSFTP( ret );
1056 	}
1057 	catch ( int e )
1058 	{
1059 		if ( err ) { *err = e; }
1060 
1061 		return ( e == -2 ) ? -2 : -1;
1062 	}
1063 
1064 	return 0;
1065 }
1066 
SetFileTime(FSPath & path,FSTime cTime,FSTime aTime,FSTime mTime,int * err,FSCInfo * info)1067 int FSSftp::SetFileTime ( FSPath& path, FSTime cTime, FSTime aTime, FSTime mTime, int* err, FSCInfo* info )
1068 {
1069 	MutexLock lock( &mutex );
1070 	int ret = CheckSession( err, info );
1071 
1072 	if ( ret ) { return ret; }
1073 
1074 	LIBSSH2_SFTP_ATTRIBUTES attr;
1075 	attr.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
1076 	attr.atime = ( unsigned long )aTime;
1077 	attr.mtime = ( unsigned long )mTime;
1078 
1079 	try
1080 	{
1081 		int ret;
1082 		WHILE_EAGAIN_( ret, libssh2_sftp_setstat( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ), &attr ) );
1083 		CheckSFTP( ret );
1084 	}
1085 	catch ( int e )
1086 	{
1087 		if ( err ) { *err = e; }
1088 
1089 		return ( e == -2 ) ? -2 : -1;
1090 	}
1091 
1092 	return 0;
1093 }
1094 
CloseHandle(LIBSSH2_SFTP_HANDLE * h,FSCInfo * info)1095 void FSSftp::CloseHandle( LIBSSH2_SFTP_HANDLE* h, FSCInfo* info )
1096 {
1097 	int ret;
1098 	WHILE_EAGAIN_( ret, libssh2_sftp_close_handle( h ) );
1099 
1100 	if ( ret ) { throw int( ret - 1000 ); }
1101 }
1102 
1103 struct SftpAttr
1104 {
1105 	LIBSSH2_SFTP_ATTRIBUTES attr;
PermissionsSftpAttr1106 	int Permissions() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS ) ? attr.permissions : 0; }
SizeSftpAttr1107 	long long Size() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_SIZE ) ? attr.filesize : 0; }
UidSftpAttr1108 	int Uid() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_UIDGID ) ? attr.uid : 0; }
GidSftpAttr1109 	int Gid() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_UIDGID ) ? attr.gid : 0; }
MTimeSftpAttr1110 	time_t MTime() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_ACMODTIME ) ? attr.mtime : 0; }
ATimeSftpAttr1111 	time_t ATime() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_ACMODTIME ) ? attr.atime : 0; }
IsLinkSftpAttr1112 	bool IsLink() const { return ( attr.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS ) != 0 && ( attr.permissions & S_IFMT ) == S_IFLNK; }
1113 };
1114 
1115 
ReadDir(FSList * list,FSPath & path,int * err,FSCInfo * info)1116 int FSSftp::ReadDir  ( FSList* list, FSPath& path, int* err, FSCInfo* info )
1117 {
1118 	MutexLock lock( &mutex );
1119 	int ret = CheckSession( err, info );
1120 
1121 	if ( ret ) { return ret; }
1122 
1123 	if ( !list ) { return 0; }
1124 
1125 	list->Clear();
1126 
1127 	try
1128 	{
1129 
1130 		LIBSSH2_SFTP_HANDLE* dir = 0;
1131 
1132 		try
1133 		{
1134 
1135 			while ( true )
1136 			{
1137 				dir = libssh2_sftp_opendir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) );
1138 
1139 				if ( dir ) { break; }
1140 
1141 				CheckSFTPEagain();
1142 				WaitSocket( info );
1143 			}
1144 
1145 			while ( true )
1146 			{
1147 				char buf[4096];
1148 				int len = 0;
1149 				SftpAttr attr;
1150 
1151 
1152 				WHILE_EAGAIN_( len, libssh2_sftp_readdir( dir, buf, sizeof( buf ) - 1, &attr.attr ) );
1153 
1154 				if ( len < 0 ) { CheckSFTP( len ); }
1155 
1156 				if ( len == 0 ) { break; }
1157 
1158 				if ( buf[0] == '.' && ( !buf[1] || ( buf[1] == '.' && !buf[2] ) ) )
1159 				{
1160 					continue;
1161 				}
1162 
1163 				clPtr<FSNode> pNode = new FSNode();
1164 
1165 #if defined(__APPLE__)
1166 				if ( _operParam.charset == CS_UTF8 )
1167 				{
1168 					std::string normname = normalize_utf8_NFC( buf );
1169 					pNode->name.Set( _operParam.charset, normname.data() );
1170 				}
1171 				else
1172 				{
1173 					pNode->name.Set( _operParam.charset, buf );
1174 				}
1175 #else
1176 				pNode->name.Set( _operParam.charset, buf );
1177 #endif
1178 
1179 				if ( attr.IsLink() )
1180 				{
1181 					FSPath pt = path;
1182 					pt.Push( _operParam.charset, buf );
1183 					char* fullPath = ( char* )pt.GetString( _operParam.charset, '/' );
1184 
1185 					WHILE_EAGAIN_( len, libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) - 1 ) );
1186 
1187 					if ( len < 0 ) { CheckSFTP( len ); }
1188 
1189 					pNode->st.link.Set( _operParam.charset, buf );
1190 
1191 					int ret;
1192 					WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) );
1193 				}
1194 
1195 				pNode->st.mode = attr.Permissions();
1196 				pNode->st.size = attr.Size();
1197 				pNode->st.uid = attr.Uid();
1198 				pNode->st.gid = attr.Gid();
1199 				pNode->st.m_CreationTime = 0;
1200 				pNode->st.m_LastAccessTime = attr.ATime();
1201 				pNode->st.m_LastWriteTime = attr.MTime();
1202 				pNode->st.m_ChangeTime = attr.MTime();
1203 
1204 				list->Append( pNode );
1205 			}
1206 
1207 		}
1208 		catch ( ... )
1209 		{
1210 			if ( dir ) { CloseHandle( dir, info ); }
1211 
1212 			throw;
1213 		}
1214 
1215 		if ( dir ) { CloseHandle( dir, info ); }
1216 
1217 	}
1218 	catch ( int e )
1219 	{
1220 		if ( err ) { *err = e; }
1221 
1222 		return ( e == -2 ) ? -2 : -1;
1223 	}
1224 
1225 	return 0;
1226 }
1227 
1228 
Stat(FSPath & path,FSStat * st,int * err,FSCInfo * info)1229 int FSSftp::Stat  ( FSPath& path, FSStat* st, int* err, FSCInfo* info )
1230 {
1231 	MutexLock lock( &mutex );
1232 	int ret = CheckSession( err, info );
1233 
1234 	if ( ret ) { return ret; }
1235 
1236 	char* fullPath = ( char* ) path.GetString( _operParam.charset, '/' );
1237 
1238 	try
1239 	{
1240 		SftpAttr attr;
1241 		int ret;
1242 		WHILE_EAGAIN_( ret, libssh2_sftp_lstat( sftpSession, fullPath, &attr.attr ) );
1243 		CheckSFTP( ret );
1244 
1245 		if ( attr.IsLink() )
1246 		{
1247 			char buf[4096];
1248 			int len;
1249 
1250 			WHILE_EAGAIN_( len,  libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) ) );
1251 
1252 			if ( len < 0 ) { CheckSFTP( len ); };
1253 
1254 			st->link.Set( _operParam.charset, buf );
1255 
1256 			int ret;
1257 
1258 			WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) );
1259 
1260 			if ( ret ) { attr.attr.permissions = 0; }
1261 		}
1262 
1263 		st->mode  = attr.Permissions();
1264 		st->size  = attr.Size();
1265 		st->uid   = attr.Uid();
1266 		st->gid   = attr.Gid();
1267 		st->m_CreationTime = 0;
1268 		st->m_LastAccessTime = attr.ATime();
1269 		st->m_LastWriteTime = attr.MTime();
1270 		st->m_ChangeTime = attr.MTime();
1271 	}
1272 	catch ( int e )
1273 	{
1274 		st->mode = 0;
1275 
1276 		if ( err ) { *err = e; }
1277 
1278 		return ( e == -2 ) ? -2 : -1;
1279 	}
1280 
1281 	return 0;
1282 }
1283 
FStat(int fd,FSStat * st,int * err,FSCInfo * info)1284 int FSSftp::FStat ( int fd, FSStat* st, int* err, FSCInfo* info )
1285 {
1286 	MutexLock lock( &mutex );
1287 	int ret = CheckSession( err, info );
1288 
1289 	if ( ret ) { return ret; }
1290 
1291 	if ( fd < 0 || fd >= MAX_FILES || !fileTable[fd] )
1292 	{
1293 		if ( err ) { *err = EINVAL; }
1294 
1295 		return -1;
1296 	}
1297 
1298 	try
1299 	{
1300 		SftpAttr attr;
1301 		int ret;
1302 		WHILE_EAGAIN_( ret, libssh2_sftp_fstat( fileTable[fd], &attr.attr ) );
1303 		CheckSFTP( ret );
1304 
1305 		st->mode  = attr.Permissions();
1306 		st->size  = attr.Size();
1307 		st->uid   = attr.Uid();
1308 		st->gid   = attr.Gid();
1309 		st->m_LastAccessTime = attr.ATime();
1310 		st->m_LastWriteTime = attr.MTime();
1311 		st->m_ChangeTime = attr.MTime();
1312 	}
1313 	catch ( int e )
1314 	{
1315 		st->mode = 0;
1316 
1317 		if ( err ) { *err = e; }
1318 
1319 		return ( e == -2 ) ? -2 : -1;
1320 	}
1321 
1322 	return 0;
1323 
1324 
1325 }
1326 
Symlink(FSPath & path,FSString & str,int * err,FSCInfo * info)1327 int FSSftp::Symlink  ( FSPath& path, FSString& str, int* err, FSCInfo* info )
1328 {
1329 	MutexLock lock( &mutex );
1330 	int ret = CheckSession( err, info );
1331 
1332 	if ( ret ) { return ret; }
1333 
1334 	try
1335 	{
1336 		int ret;
1337 		WHILE_EAGAIN_( ret, libssh2_sftp_symlink( sftpSession, ( char* )str.Get( _operParam.charset ),  ( char* )path.GetString( _operParam.charset, '/' ) ) );
1338 		CheckSFTP( ret );
1339 	}
1340 	catch ( int e )
1341 	{
1342 		if ( err ) { *err = e; }
1343 
1344 		return ( e == -2 ) ? -2 : -1;
1345 	}
1346 
1347 	return 0;
1348 }
1349 
StatVfs(FSPath & path,FSStatVfs * vst,int * err,FSCInfo * info)1350 int FSSftp::StatVfs( FSPath& path, FSStatVfs* vst, int* err, FSCInfo* info )
1351 {
1352 	vst->size = 0;
1353 	vst->avail = 0;
1354 
1355 	if ( err ) { *err = 0; }
1356 
1357 	return 0;
1358 
1359 	///////////////////// отключено
1360 	///////////////////// зависает (libssh2_sftp_statvfs постоянно возвращает LIBSSH2_ERROR_EAGAIN)
1361 	/*
1362 	printf( "FSSftp::StatVfs 1 \n" );
1363 	MutexLock lock( &mutex );
1364 	int ret = CheckSession( err, info );
1365 	if ( ret ) return ret;
1366 	printf( "FSSftp::StatVfs 2 \n" );
1367 	char *fullPath = ( char* )path.GetString( _operParam.charset, '/' );
1368 
1369 	try {
1370 	   printf( "FSSftp::StatVfs 3 \n" );
1371 	   struct _LIBSSH2_SFTP_STATVFS st;
1372 	   int ret;
1373 	   WHILE_EAGAIN_COUNT( ret, libssh2_sftp_statvfs( sftpSession, fullPath, strlen( fullPath ), &st ), 2 );
1374 	   if ( ret == LIBSSH2_ERROR_EAGAIN )
1375 		  throw( int( 0 ) );
1376 	   printf( "FSSftp::StatVfs 4 \n" );
1377 	   CheckSFTP( ret );
1378 	   printf( "FSSftp::StatVfs 5 \n" );
1379 	   vst->size = int64_t( st.f_blocks ) * st.f_frsize;
1380 	   vst->avail = int64_t( st.f_bavail ) * st.f_bsize;
1381 
1382 	}
1383 	catch ( int e ) {
1384 	   vst->size = 0;
1385 	   vst->avail = 0;
1386 	   if ( err ) *err = e;
1387 	   return ( e == -2 ) ? -2 : -1;
1388 	}
1389 	return 0;
1390 	*/
1391 }
1392 
Uri(FSPath & path)1393 FSString FSSftp::Uri( FSPath& path )
1394 {
1395 	MutexLock lock( &infoMutex ); //infoMutex!!!
1396 
1397 	std::string a;
1398 
1399 	char port[0x100];
1400 	Lsnprintf( port, sizeof( port ), ":%i", _infoParam.port );
1401 
1402 	a = std::string( "sftp://" ) + _infoParam.user + "@" + _infoParam.server + std::string(port) + path.GetUtf8( '/' );
1403 
1404 	return FSString( CS_UTF8, a.data() );
1405 }
1406 
1407 
~FSSftp()1408 FSSftp::~FSSftp()
1409 {
1410 	CloseSession();
1411 }
1412 
1413 #endif
1414 
1415