4#include <QLoggingCategory>
5#include "ChannelSFTP.h"
6#include "BackendFileTransfer.h"
7#include "RemoteFileSystemModel.h"
8#include "ListFileModel.h"
19 #define S_IRWXU (S_IREAD | S_IWRITE | S_IEXEC)
22static Q_LOGGING_CATEGORY(log,
"Channel.SFTP")
25 bool bWakeUp, QObject *parent)
27 , m_SessionSftp(
nullptr)
32 check = connect(
this, SIGNAL(sigGetDir(
CRemoteFileSystem*, QVector<QSharedPointer<CRemoteFileSystem> >,
bool)),
33 pB, SIGNAL(sigGetDir(
CRemoteFileSystem*, QVector<QSharedPointer<CRemoteFileSystem> >,
bool)));
35 check = connect(
this, SIGNAL(sigFileTransferUpdate(QSharedPointer<CFileTransfer>)),
36 pB, SIGNAL(sigFileTransferUpdate(QSharedPointer<CFileTransfer>)));
38 check = connect(
this, SIGNAL(sigError(
int,QString)),
39 pB, SIGNAL(sigError(
int,QString)));
44int CChannelSFTP::Process()
48 struct timeval timeout = {0, DEFAULT_TIMEOUT};
49 ssh_channel channels[2], channel_out[2];
50 channels[0] =
nullptr;
51 channels[1] =
nullptr;
55 socket_t fdEvent = SSH_INVALID_SOCKET;
57 fdEvent = m_pEvent->GetFd();
58 if(SSH_INVALID_SOCKET != fdEvent)
59 FD_SET(fdEvent, &set);
61 socket_t sshFd = ssh_get_fd(m_Session);
62 if(SSH_INVALID_SOCKET != sshFd)
65 socket_t f = qMax(sshFd, fdEvent);
67 nRet = ssh_select(channels, channel_out, f + 1, &set, &timeout);
74 szErr =
"ssh_channel_select failed: " + QString::number(nRet);
75 szErr += ssh_get_error(m_Session);
76 qCritical(log) << szErr;
77 setErrorString(szErr);
81 if(SSH_INVALID_SOCKET != fdEvent && FD_ISSET(fdEvent, &set)) {
84 nRet = m_pEvent->Reset();
86 QString szErr =
"Reset event fail";
87 qCritical(log) << szErr;
88 setErrorString(szErr);
101QSharedPointer<CRemoteFileSystem> CChannelSFTP::GetFileNode(
102 const QString& szPath, sftp_attributes attributes)
104 if(!attributes)
return nullptr;
108 QString szName = QString::fromUtf8(attributes->name);
109 if(
"." == szName ||
".." == szName)
111 CRemoteFileSystem::TYPE type = CRemoteFileSystem::TYPE::NO;
112 switch(attributes->type) {
113 case SSH_FILEXFER_TYPE_DIRECTORY:
114 type = CRemoteFileSystem::TYPE::DIR;
116 case SSH_FILEXFER_TYPE_SYMLINK:
117 type = CRemoteFileSystem::TYPE::SYMLINK;
119 case SSH_FILEXFER_TYPE_REGULAR:
120 type = CRemoteFileSystem::TYPE::FILE;
122 case SSH_FILEXFER_TYPE_SPECIAL:
123 type = CRemoteFileSystem::TYPE::SPECIAL;
126 qWarning(log) <<
"Unsupported type:" << attributes->type;
130 if(szPath.right(1) ==
'/')
131 szName = szPath + szName;
133 szName = szPath +
"/" + szName;
135 p->SetSize(attributes->size);
136 p->SetPermissions((QFileDevice::Permissions)attributes->permissions);
137 p->SetLastModified(QDateTime::fromSecsSinceEpoch(attributes->mtime));
138 p->SetCreateTime(QDateTime::fromSecsSinceEpoch(attributes->createtime));
145 if(!m_SessionSftp || !p)
147 sftp_dir dir =
nullptr;
148 sftp_attributes attributes =
nullptr;
150 QString szPath = p->GetPath();
151 QVector<QSharedPointer<CRemoteFileSystem> > vFileNode;
152 dir = sftp_opendir(m_SessionSftp, szPath.toStdString().c_str());
155 QString szErr =
"Directory not opened:"
156 + QString::number(sftp_get_error(m_SessionSftp))
157 + ssh_get_error(m_Session);
158 qCritical(log) << szErr;
163 while ((attributes = sftp_readdir(m_SessionSftp, dir)) != NULL)
165 qDebug(log) <<
"name:" << attributes->name <<
"size:" << attributes->size;
166 auto p = GetFileNode(szPath, attributes);
169 sftp_attributes_free(attributes);
172 if (!sftp_dir_eof(dir))
174 qCritical(log) <<
"Can't list directory:"
175 << sftp_get_error(m_SessionSftp)
176 << ssh_get_error(m_Session);
181 nRet = sftp_closedir(dir);
184 qCritical(log) <<
"Can't close directory:"
185 << sftp_get_error(m_SessionSftp)
186 << ssh_get_error(m_Session);
190 emit sigGetDir(p, vFileNode,
true);
195int CChannelSFTP::MakeDir(
const QString &dir)
197 int nRet = SSH_FX_OK;
199 return SSH_FX_NO_CONNECTION;
200 nRet = sftp_mkdir(m_SessionSftp, dir.toStdString().c_str(), S_IRWXU);
203 if (sftp_get_error(m_SessionSftp) != SSH_FX_FILE_ALREADY_EXISTS)
205 QString szErr =
"Can't create directory: "
206 + dir + QString::number(nRet)
207 + ssh_get_error(m_Session);
208 qCritical(log) << szErr;
211 qDebug(log) <<
"Create directory:" << dir;
216int CChannelSFTP::RemoveDir(
const QString& dir)
219 return SSH_FX_NO_CONNECTION;
222 sftp_dir sftpDir = sftp_opendir(m_SessionSftp, dir.toStdString().c_str());
224 qCritical(log) <<
"Failed to open directory for remove:" << dir;
226 int ret = sftp_rmdir(m_SessionSftp, dir.toStdString().c_str());
228 qDebug(log) <<
"Removed directory (directly):" << dir;
231 QString szErr =
"Can't remove directory:" + dir + ssh_get_error(m_Session);
232 qCritical(log) << szErr;
239 sftp_attributes attr;
240 while ((attr = sftp_readdir(m_SessionSftp, sftpDir)) != NULL) {
241 QString name = QString::fromUtf8(attr->name);
242 if (name ==
"." || name ==
"..") {
243 sftp_attributes_free(attr);
246 QString fullPath = dir +
"/" + name;
247 if (attr->type == SSH_FILEXFER_TYPE_DIRECTORY) {
252 int ret = sftp_unlink(m_SessionSftp, fullPath.toStdString().c_str());
254 QString szErr =
"Can't remove file:" + fullPath + ssh_get_error(m_Session);
255 qCritical(log) << szErr;
258 qDebug(log) <<
"Removed file:" << fullPath;
261 sftp_attributes_free(attr);
264 sftp_closedir(sftpDir);
267 int ret = sftp_rmdir(m_SessionSftp, dir.toStdString().c_str());
269 QString szErr =
"Can't remove directory:" + dir + ssh_get_error(m_Session);
270 qCritical(log) << szErr;
273 qDebug(log) <<
"Removed directory:" << dir;
278int CChannelSFTP::RemoveFile(
const QString &file)
281 int ret = sftp_unlink(m_SessionSftp, file.toStdString().c_str());
283 QString szErr =
"Can't remove file:" + file + ssh_get_error(m_Session);
284 qCritical(log) << szErr;
287 qDebug(log) <<
"Removed file:" << file;
292int CChannelSFTP::Rename(
const QString &oldPath,
const QString &newPath)
294 int nRet = SSH_FX_OK;
296 return SSH_FX_NO_CONNECTION;
297 nRet = sftp_rename(m_SessionSftp,
298 oldPath.toStdString().c_str(),
299 newPath.toStdString().c_str());
302 QString szErr =
"Fail: Can't rename: " + QString::number(nRet)
303 + ssh_get_error(m_Session)
304 +
" " + oldPath +
" to " + newPath;
305 qCritical(log) << szErr;
308 qDebug(log) <<
"Rename:" << oldPath <<
"to" << newPath;
312qint64 CChannelSFTP::readData(
char *data, qint64 maxlen)
319qint64 CChannelSFTP::writeData(
const char *data, qint64 len)
326int CChannelSFTP::OnOpen(ssh_session session)
330 m_SessionSftp = sftp_new(session);
333 QString szErr =
"Error allocating SFTP session: ";
334 szErr += ssh_get_error(session);
335 qCritical(log) << szErr;
340 nRet = sftp_init(m_SessionSftp);
343 QString szErr =
"Error initializing SFTP session:" + sftp_get_error(m_SessionSftp);
344 qCritical(log) << szErr;
346 sftp_free(m_SessionSftp);
347 m_SessionSftp =
nullptr;
354void CChannelSFTP::OnClose()
356 foreach (
auto d, m_vDirs) {
358 sftp_closedir(d->sftp);
363 foreach(
auto f, m_vFiles) {
365 sftp_close(f->remote);
375 sftp_free(m_SessionSftp);
376 m_SessionSftp =
nullptr;
382 if(szPath.isEmpty() || !p) {
383 qCritical(log) <<
"The path is empty";
386 foreach(
auto d, m_vDirs) {
387 if(d->remoteFileSystem == p) {
388 qDebug(log) << szPath <<
"already exists";
392 QSharedPointer<DIR_READER> dir(
new DIR_READER());
396 dir->szPath = szPath;
397 dir->state = STATE::OPEN;
398 dir->remoteFileSystem = p;
399 dir->Error = SSH_FX_OK;
404int CChannelSFTP::AsyncReadDir()
407 for(
auto it = m_vDirs.begin(); it != m_vDirs.end();) {
411 d->sftp = sftp_opendir(m_SessionSftp, d->szPath.toStdString().c_str());
413 d->state = STATE::READ;
416 int err = sftp_get_error(m_SessionSftp);
417 if (err == SSH_FX_OK || err == SSH_FX_EOF) {
418 d->state = STATE::FINISH;
421 if (err == SSH_FX_FAILURE && ssh_get_error_code(m_Session) == SSH_REQUEST_DENIED) {
422 qDebug(log) <<
"Request denied:" << d->szPath;
425 qCritical(log) <<
"Error opening directory:" << d->szPath
427 << sftp_get_error(m_SessionSftp)
428 << ssh_get_error(m_Session);
429 d->state = STATE::ERR;
434 sftp_attributes attributes =
nullptr;
435 while ((attributes = sftp_readdir(m_SessionSftp, d->sftp)) != NULL) {
436 auto p = GetFileNode(d->szPath, attributes);
438 d->vFileNode.append(p);
439 sftp_attributes_free(attributes);
442 if (sftp_dir_eof(d->sftp)) {
443 d->state = STATE::CLOSE;
446 int err = sftp_get_error(m_SessionSftp);
447 if (err == SSH_FX_OK)
449 if (err == SSH_FX_EOF) {
451 d->state = STATE::CLOSE;
453 qCritical(log) <<
"Error reading directory:" << d->szPath
454 <<
"Error:" << err << ssh_get_error(m_Session);
455 d->state = STATE::ERR;
461 d->state = STATE::FINISH;
464 int rc = sftp_closedir(d->sftp);
465 if(SSH_NO_ERROR == rc) {
466 d->state = STATE::FINISH;
470 int err = ssh_get_error_code(m_Session);
471 qCritical(log) <<
"Error close directory:" << d->szPath
472 <<
"Error:" << err << ssh_get_error(m_Session);
473 d->state = STATE::FINISH;
478 if(d && STATE::FINISH == d->state) {
479 qDebug(log) <<
"Remote get path finish:" << d->szPath << d->vFileNode.size();
480 emit sigGetDir(d->remoteFileSystem, d->vFileNode,
true);
481 it = m_vDirs.erase(it);
485 d->state = STATE::CLOSE;
497void CChannelSFTP::slotStartFileTransfer(QSharedPointer<CFileTransfer> f)
499 f->slotSetstate(CFileTransfer::State::Opening);
500 QSharedPointer<_AFILE> file(
new _AFILE);
501 memset(file.data(), 0,
sizeof(_AFILE));
503 file->remote =
nullptr;
504 file->state = STATE::OPEN;
505 file->fileTransfer = f;
506#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
507 file->nChunkSize = BUF_SIZE;
508 file->nConcurrentCount = 5;
510 m_vFiles.append(file);
511 emit sigFileTransferUpdate(f);
515void CChannelSFTP::slotStopFileTransfer(QSharedPointer<CFileTransfer> f)
517 foreach(
auto file, m_vFiles) {
518 if(file->fileTransfer == f) {
519 m_vFiles.removeAll(file);
520 if(-1 != file->local) {
521 ::close(file->local);
525 sftp_close(file->remote);
526 file->remote =
nullptr;
528 f->slotSetstate(CFileTransfer::State::Stop);
529 emit sigFileTransferUpdate(f);
535int CChannelSFTP::AsyncFile()
537 for(
auto it = m_vFiles.begin(); it != m_vFiles.end();) {
539 switch(file->state) {
541 int remoteFlag = O_WRONLY | O_CREAT | O_TRUNC;
542 int localFlag = O_RDONLY;
543 quint32 permission = file->fileTransfer->GetRemotePermission();
545 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
546 remoteFlag = O_RDONLY;
547 localFlag = O_WRONLY | O_CREAT | O_TRUNC;
550 file->remote = sftp_open(
552 file->fileTransfer->GetRemoteFile().toStdString().c_str(),
553 remoteFlag, permission);
556 file->state = STATE::ERR;
557 QString szErr =
"Can't open remote file: " + file->fileTransfer->GetRemoteFile()
558 + ssh_get_error(m_Session);
559 file->fileTransfer->slotSetExplanation(szErr);
560 qCritical(log) << szErr;
563 qDebug(log) <<
"Open remote file:" << file->fileTransfer->GetRemoteFile();
565 sftp_file_set_nonblocking(file->remote);
568 file->fileTransfer->GetLocalFile().toStdString().c_str(),
569 localFlag, permission);
570 if(-1 == file->local) {
571 file->state = STATE::ERR;
572 QString szErr =
"Can't open local file: " + file->fileTransfer->GetLocalFile() +
" " + strerror(errno);
573 file->fileTransfer->slotSetExplanation(szErr);
574 qCritical(log) << szErr;
577 qDebug(log) <<
"Open local file:" << file->fileTransfer->GetLocalFile();
579 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
580#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
581 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
582 sftp_limits_t lim = sftp_limits(m_SessionSftp);
584 file->nChunkSize = lim->max_read_length;
585 qDebug(log) <<
"limits: max_open_handles:" << lim->max_open_handles
586 <<
"max_packet_length" << lim->max_packet_length
587 <<
"max_read_length" << lim->max_read_length
588 <<
"max_write_length:" << lim->max_write_length;
589 sftp_limits_free(lim);
592 quint64 nRequestBytes = 0;
594 i < file->nConcurrentCount
595 && nRequestBytes < file->fileTransfer->GetFileSize();
597 sftp_aio aio =
nullptr;
598 quint64 nRequest = file->fileTransfer->GetFileSize() - nRequestBytes;
599 if(nRequest > file->nChunkSize)
600 nRequest = file->nChunkSize;
601 ssize_t nRet = sftp_aio_begin_read(file->remote, nRequest, &aio);
603 int rc = ssh_get_error_code(m_Session);
604 if (rc != SSH_NO_ERROR) {
605 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
606 szErr += ssh_get_error(m_Session);
607 qCritical(log) << szErr;
611 Q_ASSERT(nRequest == nRet);
612 nRequestBytes += nRet;
613 file->aio.append(aio);
617 file->asyncReadId = sftp_async_read_begin(file->remote, BUF_SIZE);
618 if(file->asyncReadId < 0) {
619 file->state = STATE::ERR;
620 QString szErr =
"sftp_async_read_begin failed." + sftp_get_error(m_SessionSftp);
621 file->fileTransfer->slotSetExplanation(szErr);
622 qCritical(log) << szErr;
627#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
628 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
629 sftp_limits_t lim = sftp_limits(m_SessionSftp);
631 file->nChunkSize = lim->max_write_length;
632 qDebug(log) <<
"limits: max_open_handles:" << lim->max_open_handles
633 <<
"max_packet_length" << lim->max_packet_length
634 <<
"max_read_length" << lim->max_read_length
635 <<
"max_write_length:" << lim->max_write_length;
636 sftp_limits_free(lim);
640 file->buffer =
new char[file->nChunkSize];
642 file->state = STATE::ERR;
647 i < file->nConcurrentCount
648 && file->nRequests < file->fileTransfer->GetFileSize();
650 sftp_aio aio =
nullptr;
651 quint64 nRequest = file->fileTransfer->GetFileSize() - file->nRequests;
652 if(nRequest > file->nChunkSize)
653 nRequest = file->nChunkSize;
654 ssize_t nLen = ::read(file->local, file->buffer, nRequest);
655 Q_ASSERT(nLen == nRequest);
656 ssize_t nRet = sftp_aio_begin_write(file->remote, file->buffer, nLen, &aio);
658 int rc = ssh_get_error_code(m_Session);
659 if (rc != SSH_NO_ERROR) {
660 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
661 szErr += ssh_get_error(m_Session);
662 qCritical(log) << szErr;
666 Q_ASSERT(nRequest == nRet);
667 file->nRequests += nRet;
668 file->aio.append(aio);
674 file->state = STATE::READ;
675 file->fileTransfer->slotSetstate(CFileTransfer::State::Transferring);
676 emit sigFileTransferUpdate(file->fileTransfer);
679 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
680#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
681 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
682 for(
auto it = file->aio.begin(); it != file->aio.end();) {
684 if(
nullptr == file->buffer)
685 file->buffer =
new char[file->nChunkSize];
686 if(!(aio && file->buffer))
688 ssize_t nRet = sftp_aio_wait_read(&aio, file->buffer, file->nChunkSize);
690 if(SSH_AGAIN == nRet)
692 int rc = ssh_get_error_code(m_Session);
693 if (rc != SSH_NO_ERROR) {
694 file->state = STATE::ERR;
695 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
696 szErr += ssh_get_error(m_Session);
697 qCritical(log) << szErr;
701 file->nTransfers += nRet;
702 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
703 file->state = STATE::CLOSE;
705 it = file->aio.erase(it);
707 int nLen = ::write(file->local, file->buffer, nRet);
710 file->state = STATE::ERR;
714 qCritical(log) <<
"IO is buse, Write file error:" << file->fileTransfer->GetLocalFile();
717 file->fileTransfer->slotTransferSize(nRet);
718 emit sigFileTransferUpdate(file->fileTransfer);
720 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
721 file->state = STATE::CLOSE;
724 if(file->aio.size() > 0)
727 quint64 nRequestBytes = file->nTransfers;
729 i < file->nConcurrentCount
730 && nRequestBytes < file->fileTransfer->GetFileSize();
732 sftp_aio aio =
nullptr;
733 quint64 nRequest = file->fileTransfer->GetFileSize() - nRequestBytes;
734 if(nRequest > file->nChunkSize)
735 nRequest = file->nChunkSize;
736 ssize_t nRet = sftp_aio_begin_read(file->remote, nRequest, &aio);
738 int rc = ssh_get_error_code(m_Session);
739 if (rc != SSH_NO_ERROR) {
740 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
741 szErr += ssh_get_error(m_Session);
742 qCritical(log) << szErr;
746 if (nRequest != nRet) {
748 "Error during sftp aio download: sftp_aio_begin_read() "
749 "requesting less bytes even when the number of bytes "
750 "asked to read are within the max limit";
751 qWarning(log) << szErr << nRequest << nRet;
754 nRequestBytes += nRet;
755 file->aio.append(aio);
758 file->state = STATE::ERR;
759 QString szErr = tr(
"Error: Asynchronous uploads are not supported");
760 file->fileTransfer->slotSetExplanation(szErr);
761 qCritical(log) << szErr;
765 int nbytes = sftp_async_read(file->remote, file->buffer + file->offset, BUF_SIZE, file->asyncReadId);
766 if (nbytes > 0 || SSH_AGAIN == nbytes) {
768 int nLen = ::write(file->local, file->buffer + file->offset, nbytes);
770 file->fileTransfer->slotTransferSize(nLen);
772 emit sigFileTransferUpdate(file->fileTransfer);
774 file->state = STATE::ERR;
775 QString szErr =
"Write local file fail:" + sftp_get_error(m_SessionSftp);
776 file->fileTransfer->slotSetExplanation(szErr);
780 if (file->asyncReadId = sftp_async_read_begin(file->remote, BUF_SIZE) < 0) {
781 file->state = STATE::ERR;
782 QString szErr =
"sftp_async_read_begin failed." + sftp_get_error(m_SessionSftp);
783 file->fileTransfer->slotSetExplanation(szErr);
784 qCritical(log) << szErr;
786 }
else if (nbytes == 0) {
787 file->state = STATE::CLOSE;
788 file->asyncReadId = -1;
790 file->state = STATE::ERR;
791 QString szErr =
"sftp_async_read failed." + sftp_get_error(m_SessionSftp);
792 file->fileTransfer->slotSetExplanation(szErr);
793 qCritical(log) << szErr;
797 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
798 for(
auto it = file->aio.begin(); it != file->aio.end();) {
800 ssize_t nRet = sftp_aio_wait_write(&aio);
802 if(SSH_AGAIN == nRet)
804 int rc = ssh_get_error_code(m_Session);
805 if (rc != SSH_NO_ERROR) {
806 file->state = STATE::ERR;
807 QString szErr =
"Error during sftp aio upload: " + QString::number(rc);
808 szErr += ssh_get_error(m_Session);
809 qCritical(log) << szErr;
813 file->nTransfers += nRet;
814 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
815 file->state = STATE::CLOSE;
817 it = file->aio.erase(it);
819 if(file->aio.size() >= file->nConcurrentCount)
821 int size = file->nConcurrentCount - file->aio.size();
824 && file->nRequests < file->fileTransfer->GetFileSize();
826 sftp_aio aio =
nullptr;
827 quint64 nRequest = file->fileTransfer->GetFileSize() - file->nRequests;
828 if(nRequest > file->nChunkSize)
829 nRequest = file->nChunkSize;
830 ssize_t nLen = ::read(file->local, file->buffer, nRequest);
831 Q_ASSERT(nLen == nRequest);
832 ssize_t nRet = sftp_aio_begin_write(file->remote, file->buffer, nLen, &aio);
834 int rc = ssh_get_error_code(m_Session);
835 if (rc != SSH_NO_ERROR) {
836 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
837 szErr += ssh_get_error(m_Session);
838 qCritical(log) << szErr;
842 Q_ASSERT(nRequest == nRet);
843 file->nRequests += nRet;
844 file->aio.append(aio);
851 file->state = STATE::FINISH;
852 file->fileTransfer->slotSetstate(CFileTransfer::State::Closing);
853 emit sigFileTransferUpdate(file->fileTransfer);
856 case STATE::FINISH: {
857#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
860 it = m_vFiles.erase(it);
861 file->fileTransfer->slotSetstate(CFileTransfer::State::Finish);
862 emit sigFileTransferUpdate(file->fileTransfer);
866#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
867 foreach (
auto aio, file->aio) {
873 it = m_vFiles.erase(it);
874 file->fileTransfer->slotSetstate(CFileTransfer::State::Fail);
875 emit sigFileTransferUpdate(file->fileTransfer);
885int CChannelSFTP::CleanFileAIO(QSharedPointer<_AFILE> file)
888 delete []file->buffer;
889 file->buffer =
nullptr;
892 sftp_close(file->remote);
893 file->remote =
nullptr;
895 if(-1 != file->local) {
896 ::close(file->local);
后端接口。它由协议插件实现。 它默认启动一个定时器来开启一个非 Qt 事件循环(就是普通的循环处理)。 详见: Start()、 slotTimeOut()、 OnProcess() 。 当然,它仍然支...
int GetDir(CRemoteFileSystem *p)
Synchronize to get the directory
void slotGetDir(const QString &szPath, CRemoteFileSystem *p)
Get the directory asynchronously
virtual bool open(OpenMode mode) override
void sigError(int nErr, const QString &szErr)
emit when the channel is error