예제 #1
0
int FSSys::Stat( FSPath& path, FSStat* fsStat, int* err, FSCInfo* info )
{
	fsStat->link.Clear();

#ifdef S_IFLNK
	struct stat st_link;

	if ( lstat( ( char* )path.GetString( sys_charset_id ), &st_link ) )
	{
		SetError( err, errno );
		return -1;
	};

	if ( ( st_link.st_mode & S_IFMT ) == S_IFLNK )
	{
		char buf[1024];
		ssize_t ret = readlink( ( char* )path.GetString( sys_charset_id ), buf, sizeof( buf ) );

		if ( ret >= sizeof( buf ) ) { ret = sizeof( buf ) - 1; }

		if ( ret >= 0 ) { buf[ret] = 0; }
		else { buf[0] = 0; }

		if ( ret >= 0 ) { fsStat->link.Set( sys_charset_id, buf ); }
	}
	else
	{
		fsStat->mode = st_link.st_mode;
		fsStat->size   = st_link.st_size;
		fsStat->mtime  = st_link.st_mtime;
		fsStat->gid = st_link.st_gid;
		fsStat->uid = st_link.st_uid;

		fsStat->dev = st_link.st_dev;
		fsStat->ino = st_link.st_ino;

		return 0;
	}

#endif

	struct stat st;

	if ( stat( ( char* )path.GetString( sys_charset_id ), &st ) )
	{
		SetError( err, errno );
		return -1;
	}

	fsStat->mode = st.st_mode;
	fsStat->size   = st.st_size;
	fsStat->mtime  = st.st_mtime;
	fsStat->gid = st.st_gid;
	fsStat->uid = st.st_uid;

	fsStat->dev = st.st_dev;
	fsStat->ino = st.st_ino;

	return 0;
}
예제 #2
0
int FSSys::Rename ( FSPath&  oldpath, FSPath& newpath, int* err,  FSCInfo* info )
{
	if ( rename( ( char* ) oldpath.GetString( sys_charset_id, '/' ), ( char* ) newpath.GetString( sys_charset_id, '/' ) ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;
}
예제 #3
0
int FSSftp::OpenCreate  ( FSPath& path, bool overwrite, int mode, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	if ( !overwrite )
	{
		/*
		   заебался выяснять почему sftp_open  с  O_EXCL выдает "generc error" при наличии файла, а не EEXIST какой нибудь
		   поэтому встанил эту дурацкую проверку на наличие
		*/
		sftp_attributes a = sftp_lstat( sftpSession, ( char* ) path.GetString( _operParam.charset, '/' ) );

		if ( a )
		{
			sftp_attributes_free( a ); //!!!

			if ( err ) { *err = SSH_FX_FILE_ALREADY_EXISTS; }

			return -1;
		}
	}


	int n = 0;

	for ( ; n < MAX_FILES; n++ )
		if ( !fileTable[n] ) { break; }

	if ( n >= MAX_FILES )
	{
		if ( err ) { *err = SSH_INTERROR_OUTOF; }

		return -1;
	}

	sftp_file f = sftp_open( sftpSession, ( char* ) path.GetString( _operParam.charset, '/' ),
	                         O_CREAT | O_WRONLY | ( overwrite ? O_TRUNC : O_EXCL ),
	                         mode );

	if ( !f )
	{
//printf("ssh-err:'%s'\n",ssh_get_error(sshSession));
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	fileTable[n] = f;

	return n;
}
예제 #4
0
void WcmConfig::Save( NCWin* nc )
{
	if ( nc )
	{
		leftPanelPath = new_char_str( nc->GetLeftPanel()->GetPath().GetUtf8() );
		rightPanelPath = new_char_str( nc->GetRightPanel()->GetPath().GetUtf8() );
		crect Rect = nc->ScreenRect();
		windowX = Rect.top;
		windowY = Rect.left;
		windowWidth = Rect.Width();
		windowHeight = Rect.Height();
	}
	
#ifdef _WIN32
	for (int i = 0; i<mapList.count(); i++)
	{
		Node &node = mapList[i];
		if (node.type == MT_BOOL && node.ptr.pBool != 0)
			RegWriteInt(node.section, node.name, *node.ptr.pBool);
		else
		if (node.type == MT_INT && node.ptr.pInt != 0)
			RegWriteInt(node.section, node.name, *node.ptr.pInt);
		else
		if (node.type == MT_STR && node.ptr.pStr != 0)
			RegWriteString(node.section, node.name, node.ptr.pStr->ptr());
	}
#else 
	IniHash hash;
	FSPath path = configDirPath;
	path.Push(CS_UTF8, "config");
	hash.Load((sys_char_t*)path.GetString(sys_charset_id));

	for (int i = 0; i<mapList.count(); i++)
	{
		Node &node = mapList[i];
		if (node.type == MT_BOOL && node.ptr.pBool != 0)
			hash.SetBoolValue(node.section, node.name, *node.ptr.pBool);
		else
		if (node.type == MT_INT && node.ptr.pInt != 0)
			hash.SetIntValue(node.section, node.name, *node.ptr.pInt);
		else
		if (node.type == MT_STR && node.ptr.pStr != 0)
			hash.SetStrValue(node.section, node.name, node.ptr.pStr->ptr());
	}
	
	hash.Save((sys_char_t*)path.GetString(sys_charset_id));
#endif
}
예제 #5
0
int FSSftp::SetFileTime ( FSPath& path, FSTime aTime, FSTime mTime, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );

	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	struct timeval tv[2];

	tv[0].tv_sec  = aTime;

	tv[0].tv_usec = 0;

	tv[1].tv_sec  = mTime;

	tv[1].tv_usec = 0;

	if ( sftp_utimes( sftpSession, ( char* )path.GetString( _operParam.charset ), tv ) )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	return 0;
}
예제 #6
0
int FSSftp::SetFileTime ( FSPath& path, FSTime aTime, FSTime mTime, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	LIBSSH2_SFTP_ATTRIBUTES attr;
	attr.flags = LIBSSH2_SFTP_ATTR_ACMODTIME;
	attr.atime = aTime;
	attr.mtime = mTime;

	try
	{
		int ret;
		WHILE_EAGAIN_( ret, libssh2_sftp_setstat( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ), &attr ) );
		CheckSFTP( ret );
	}
	catch ( int e )
	{
		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return 0;
}
예제 #7
0
int FSSftp::OpenRead ( FSPath& path, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	int n = 0;

	for ( ; n < MAX_FILES; n++ )
		if ( !fileTable[n] ) { break; }

	if ( n >= MAX_FILES )
	{
		if ( err ) { *err = SSH_INTERROR_OUTOF; }

		return -1;
	}

	sftp_file f = sftp_open( sftpSession, ( char* ) path.GetString( _operParam.charset, '/' ), O_RDONLY, 0 );

	if ( !f )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	fileTable[n] = f;

	return n;
}
예제 #8
0
void SaveStringList(const char *section, ccollect< carray<char> > &list)
{
	try {
		SysTextFileOut out;
				
		FSPath path = configDirPath;
		path.Push(CS_UTF8, carray_cat<char>(section, ".cfg").ptr());
		out.Open( (sys_char_t*)path.GetString(sys_charset_id) );
		
		for (int i = 0; i<list.count(); i++)
		{
			if (list[i].ptr() && list[i][0])
			{
				out.Put(list[i].ptr());
				out.PutC('\n');
			}
		}
		
		out.Flush();
		out.Close();
		
	} catch (cexception *ex) {
		ex->destroy();
		return ;
	}
}
예제 #9
0
int FSSftp::Stat  ( FSPath& path, FSStat* st, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	char* fullPath = ( char* ) path.GetString( _operParam.charset );

	sftp_attributes la = sftp_lstat( sftpSession, fullPath );

	if ( !la )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	if ( la->type == SSH_FILEXFER_TYPE_SYMLINK )
	{
		char* s = sftp_readlink( sftpSession, fullPath );

		if ( s ) { st->link.Set( _operParam.charset, s ); }

		sftp_attributes_free( la ); //!!!
	}
	else
	{
		st->mode  = la->permissions;
		st->size  = la->size;
		st->uid   = la->uid;
		st->gid   = la->gid;
		st->mtime = la->mtime;

		sftp_attributes_free( la ); //!!!

		return 0;
	}

	sftp_attributes a = sftp_stat( sftpSession, fullPath );

	if ( !a )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	st->mode  = la->permissions;
	st->size  = la->size;
	st->uid   = la->uid;
	st->gid   = la->gid;
	st->mtime = la->mtime;

	sftp_attributes_free( a ); //!!!

	return 0;
}
예제 #10
0
int FSSys::OpenRead  ( FSPath& path, int flags, int* err, FSCInfo* info )
{
	int n =  open( ( char* ) path.GetString( sys_charset_id, '/' ),
	               O_RDONLY | OPENFLAG_LARGEFILE, 0 );

	if ( n < 0 ) { SetError( err, errno ); return -1; }

	return n;
}
예제 #11
0
int FSSys::OpenCreate   ( FSPath& path, bool overwrite, int mode, int flags,   int* err, FSCInfo* info )
{
	int n =  open( ( char* ) path.GetString( sys_charset_id, '/' ),
	               O_CREAT | O_WRONLY | O_TRUNC | OPENFLAG_LARGEFILE | ( overwrite ? 0 : O_EXCL ) , mode );

	if ( n < 0 ) { SetError( err, errno ); return -1; }

	return n;
}
예제 #12
0
int FSSys::Symlink( FSPath& path, FSString& str, int* err, FSCInfo* info )
{
	if ( symlink( ( char* )str.Get( sys_charset_id ), ( char* )path.GetString( sys_charset_id ) ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;
}
예제 #13
0
int FSSys::Delete( FSPath& path, int* err, FSCInfo* info )
{
	if ( unlink( ( char* ) path.GetString( sys_charset_id, '/' ) ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;
}
예제 #14
0
int FSSys::RmDir( FSPath& path, int* err, FSCInfo* info )
{
	if ( rmdir( ( char* ) path.GetString( sys_charset_id, '/' ) ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;
}
예제 #15
0
int FSSys::MkDir( FSPath& path, int mode, int* err,  FSCInfo* info )
{
	if ( mkdir( ( char* ) path.GetString( sys_charset_id, '/' ), mode ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;

}
예제 #16
0
int FSSftp::Stat  ( FSPath& path, FSStat* st, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	char* fullPath = ( char* ) path.GetString( _operParam.charset, '/' );

	try
	{
		SftpAttr attr;
		int ret;
		WHILE_EAGAIN_( ret, libssh2_sftp_lstat( sftpSession, fullPath, &attr.attr ) );
		CheckSFTP( ret );

		if ( attr.IsLink() )
		{
			char buf[4096];
			int len;

			WHILE_EAGAIN_( len,  libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) ) );

			if ( len < 0 ) { CheckSFTP( len ); };

			st->link.Set( _operParam.charset, buf );

			int ret;

			WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) );

			if ( ret ) { attr.attr.permissions = 0; }
		}

		st->mode  = attr.Permissions();
		st->size  = attr.Size();
		st->uid   = attr.Uid();
		st->gid   = attr.Gid();
		st->mtime = attr.MTime();
	}
	catch ( int e )
	{
		st->mode = 0;

		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return 0;
}
예제 #17
0
int FSSftp::OpenRead ( FSPath& path, int flags, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	int n = 0;

	for ( ; n < MAX_FILES; n++ )
		if ( !fileTable[n] ) { break; }

	if ( n >= MAX_FILES )
	{
		if ( err ) { *err = SSH_INTERROR_OUTOF; }

		return -1;
	}

	try
	{
		LIBSSH2_SFTP_HANDLE* fd = 0;

		while ( true )
		{
			fd = libssh2_sftp_open( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ),
			                        LIBSSH2_FXF_READ,
			                        0 );

			if ( fd ) { break; }

			CheckSFTPEagain();
			WaitSocket( info );
		}

		fileTable[n] = fd;

	}
	catch ( int e )
	{
		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return n;
}
예제 #18
0
int FSSftp::MkDir ( FSPath& path, int mode, int* err,  FSCInfo* info )
{
	MutexLock lock( &mutex );

	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	if ( sftp_mkdir( sftpSession, ( char* )path.GetString( _operParam.charset ), mode ) )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	return 0;
}
예제 #19
0
int FSSys::SetFileTime  ( FSPath& path, FSTime aTime, FSTime mTime, int* err, FSCInfo* info )
{
	struct timeval tv[2];
	tv[0].tv_sec  = aTime;
	tv[0].tv_usec = 0;
	tv[1].tv_sec  = mTime;
	tv[1].tv_usec = 0;

	if ( utimes( ( char* ) path.GetString( sys_charset_id, '/' ), tv ) )
	{
		SetError( err, errno );
		return -1;
	}

	return 0;

}
예제 #20
0
int FSSftp::Symlink  ( FSPath& path, FSString& str, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	if ( sftp_symlink( sftpSession, ( char* )str.Get( _operParam.charset ),  ( char* )path.GetString( _operParam.charset ) ) )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	return 0;

}
예제 #21
0
void WcmConfig::Load()
{
#ifdef _WIN32
	
	for (int i = 0; i<mapList.count(); i++)
	{
		Node &node = mapList[i];
		if (node.type == MT_BOOL && node.ptr.pBool != 0)
			*node.ptr.pBool = RegReadInt(node.section, node.name, node.def.defBool)!=0;
		else
		if (node.type == MT_INT && node.ptr.pInt != 0)
			*node.ptr.pInt = RegReadInt(node.section, node.name, node.def.defInt);
		else
		if (node.type == MT_STR && node.ptr.pStr != 0)
			*node.ptr.pStr = RegReadString(node.section, node.name, node.def.defStr);
	}

#else 
	IniHash hash;
	FSPath path = configDirPath;
	path.Push(CS_UTF8, "config");
	
	hash.Load(DEFAULT_CONFIG_PATH);
	hash.Load((sys_char_t*)path.GetString(sys_charset_id));

	for (int i = 0; i<mapList.count(); i++)
	{
		Node &node = mapList[i];
		if (node.type == MT_BOOL && node.ptr.pBool != 0)
			*node.ptr.pBool = hash.GetBoolValue(node.section, node.name, node.def.defBool);
		else
		if (node.type == MT_INT && node.ptr.pInt != 0)
			*node.ptr.pInt = hash.GetIntValue(node.section, node.name, node.def.defInt);
		else
		if (node.type == MT_STR && node.ptr.pStr != 0)
		{
			const char *s = hash.GetStrValue(node.section, node.name, node.def.defStr);
			if (s) *node.ptr.pStr = new_char_str(s);
			else (*node.ptr.pStr) = 0;
		}

	}
#endif
	if (editTabSize<=0 || editTabSize >64) editTabSize = 8;
}
예제 #22
0
int FSSftp::Rename   ( FSPath&  oldpath, FSPath& newpath, int* err,  FSCInfo* info )
{
	MutexLock lock( &mutex );

	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }


	if ( sftp_rename( sftpSession, ( char* ) oldpath.GetString( _operParam.charset, '/' ), ( char* ) newpath.GetString( _operParam.charset, '/' ) ) )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	return 0;
}
예제 #23
0
bool LoadStringList(const char *section, ccollect< carray<char> > &list)
{
	try {
		SysTextFileIn in;
				
		FSPath path = configDirPath;
		path.Push(CS_UTF8, carray_cat<char>(section, ".cfg").ptr());
		in.Open( (sys_char_t*)path.GetString(sys_charset_id) );
		
		char buf[4096];
		while (in.GetLine(buf, sizeof(buf))) 
		{
			char *s = buf;
			while (*s>0 && *s<=' ') s++;
			if (*s) list.append(new_char_str(s));
		}
	} catch (cexception *ex) {
		ex->destroy();
		return false;
	}
	return true;
}
예제 #24
0
int FSSftp::RmDir ( FSPath& path, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	try
	{
		int ret;
		WHILE_EAGAIN_( ret, libssh2_sftp_rmdir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) ) );
		CheckSFTP( ret );
	}
	catch ( int e )
	{
		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return 0;
}
예제 #25
0
int FSSftp::OpenCreate  ( FSPath& path, bool overwrite, int mode, int flags, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	int n = 0;

	try
	{
		if ( !overwrite )
		{
			/* странная херня, при наличии файла с  O_EXCL,  выдает не EEXIST, а "прерван системный вызов"
			   поэтому встанил эту дурацкую проверку на наличие
			*/
			LIBSSH2_SFTP_ATTRIBUTES attr;
			int ret;
			WHILE_EAGAIN_( ret, libssh2_sftp_lstat( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ), &attr ) );

			if ( !ret ) { if ( err ) { *err = EEXIST; } return -1; }
		}

		for ( n = 0; n < MAX_FILES; n++ )
			if ( !fileTable[n] ) { break; }

		if ( n >= MAX_FILES )
		{
			if ( err ) { *err = SSH_INTERROR_OUTOF; }

			return -1;
		}


		LIBSSH2_SFTP_HANDLE* fd = 0;

		while ( true )
		{
			fd = libssh2_sftp_open( sftpSession,
			                        ( char* )path.GetString( _operParam.charset, '/' ),
			                        LIBSSH2_FXF_CREAT | LIBSSH2_FXF_WRITE | ( overwrite ? LIBSSH2_FXF_TRUNC : LIBSSH2_FXF_EXCL ),
			                        mode );

			if ( fd ) { break; }

			CheckSFTPEagain();
			WaitSocket( info );
		}

		fileTable[n] = fd;

	}
	catch ( int e )
	{
		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return n;
}
예제 #26
0
int FSSftp::ReadDir  ( FSList* list, FSPath& path, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	if ( !list ) { return 0; }

	list->Clear();

	sftp_dir dir = sftp_opendir( sftpSession, ( char* )path.GetString( _operParam.charset ) );

	if ( !dir )
	{
		if ( err ) { *err = sftp_get_error( sftpSession ); }

		return -1;
	}

	try
	{

		while ( true )
		{
			if ( info && info->Stopped() )
			{
				sftp_closedir( dir );
				return -2;
			}

			sftp_attributes attr = sftp_readdir( sftpSession, dir );

			if ( !attr )
			{
				if ( sftp_dir_eof( dir ) ) { break; }

				if ( err ) { *err = sftp_get_error( sftpSession ); }

				return -1;
			}

			try
			{
				//skip . and ..
				if ( !attr->name || attr->name[0] == '.' && ( !attr->name[1] || ( attr->name[1] == '.' && !attr->name[2] ) ) )
				{
					continue;
				}

				clPtr<FSNode> pNode = new FSNode();
				pNode->name.Set( _operParam.charset, attr->name );

				pNode->st.size = attr->size;
				pNode->st.uid = attr->uid;
				pNode->st.gid = attr->gid;
				pNode->st.mtime = attr->mtime;

				if ( attr->type == SSH_FILEXFER_TYPE_SYMLINK )
				{
					FSPath pt = path;
					pt.Push( _operParam.charset, attr->name );
					char* fullPath = ( char* )pt.GetString( _operParam.charset );
					char* s = sftp_readlink( sftpSession, fullPath );

					if ( s ) { pNode->st.link.Set( _operParam.charset, s ); }

					sftp_attributes a = sftp_stat( sftpSession, fullPath );

					if ( a )
					{
						pNode->st.mode  = a->permissions;
						pNode->st.mtime = a->mtime;
						sftp_attributes_free( a );
					}
					else
					{
						pNode->st.mode = 0;
					}
				}
				else
				{
					pNode->st.mode = attr->permissions;
				}

				list->Append( pNode );

				sftp_attributes_free( attr );

			}
			catch ( ... )
			{
				sftp_attributes_free( attr );
				throw;
			}
		};

		sftp_closedir( dir );
	}
	catch ( ... )
	{
		sftp_closedir( dir );
		throw;
	}

	return 0;
}
예제 #27
0
int FSSftp::ReadDir  ( FSList* list, FSPath& path, int* err, FSCInfo* info )
{
	MutexLock lock( &mutex );
	int ret = CheckSession( err, info );

	if ( ret ) { return ret; }

	if ( !list ) { return 0; }

	list->Clear();

	try
	{

		LIBSSH2_SFTP_HANDLE* dir = 0;

		try
		{

			while ( true )
			{
				dir = libssh2_sftp_opendir( sftpSession, ( char* )path.GetString( _operParam.charset, '/' ) );

				if ( dir ) { break; }

				CheckSFTPEagain();
				WaitSocket( info );
			}

			while ( true )
			{
				char buf[4096];
				int len = 0;
				SftpAttr attr;


				WHILE_EAGAIN_( len, libssh2_sftp_readdir( dir, buf, sizeof( buf ) - 1, &attr.attr ) );

				if ( len < 0 ) { CheckSFTP( len ); }

				if ( len == 0 ) { break; }

				if ( buf[0] == '.' && ( !buf[1] || ( buf[1] == '.' && !buf[2] ) ) )
				{
					continue;
				}

				clPtr<FSNode> pNode = new FSNode();
				pNode->name.Set( _operParam.charset, buf );

				if ( attr.IsLink() )
				{
					FSPath pt = path;
					pt.Push( _operParam.charset, buf );
					char* fullPath = ( char* )pt.GetString( _operParam.charset, '/' );

					WHILE_EAGAIN_( len, libssh2_sftp_readlink( sftpSession, fullPath, buf, sizeof( buf ) - 1 ) );

					if ( len < 0 ) { CheckSFTP( len ); }

					pNode->st.link.Set( _operParam.charset, buf );

					int ret;
					WHILE_EAGAIN_( ret, libssh2_sftp_stat( sftpSession, fullPath, &attr.attr ) );
				}

				pNode->st.mode = attr.Permissions();
				pNode->st.size = attr.Size();
				pNode->st.uid = attr.Uid();
				pNode->st.gid = attr.Gid();
				pNode->st.mtime = attr.MTime();

				list->Append( pNode );
			}

		}
		catch ( ... )
		{
			if ( dir ) { CloseHandle( dir, info ); }

			throw;
		}

		if ( dir ) { CloseHandle( dir, info ); }

	}
	catch ( int e )
	{
		if ( err ) { *err = e; }

		return ( e == -2 ) ? -2 : -1;
	}

	return 0;
}