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;
383 QString szPath = p->GetPath();
384 if(szPath.isEmpty()) {
385 qCritical(log) <<
"The path is empty";
388 foreach(
auto d, m_vDirs) {
389 if(d->remoteFileSystem == p) {
390 qDebug(log) << szPath <<
"already exists";
394 QSharedPointer<DIR_READER> dir(
new DIR_READER());
398 dir->szPath = szPath;
399 dir->state = STATE::OPEN;
400 dir->remoteFileSystem = p;
401 dir->Error = SSH_FX_OK;
406int CChannelSFTP::AsyncReadDir()
409 for(
auto it = m_vDirs.begin(); it != m_vDirs.end();) {
413 d->sftp = sftp_opendir(m_SessionSftp, d->szPath.toStdString().c_str());
415 d->state = STATE::READ;
418 int err = sftp_get_error(m_SessionSftp);
419 if (err == SSH_FX_OK || err == SSH_FX_EOF) {
420 d->state = STATE::FINISH;
423 if (err == SSH_FX_FAILURE && ssh_get_error_code(m_Session) == SSH_REQUEST_DENIED) {
424 qDebug(log) <<
"Request denied:" << d->szPath;
427 qCritical(log) <<
"Error opening directory:" << d->szPath
429 << sftp_get_error(m_SessionSftp)
430 << ssh_get_error(m_Session);
431 d->state = STATE::ERR;
436 sftp_attributes attributes =
nullptr;
437 while ((attributes = sftp_readdir(m_SessionSftp, d->sftp)) != NULL) {
438 auto p = GetFileNode(d->szPath, attributes);
440 d->vFileNode.append(p);
441 sftp_attributes_free(attributes);
444 if (sftp_dir_eof(d->sftp)) {
445 d->state = STATE::CLOSE;
448 int err = sftp_get_error(m_SessionSftp);
449 if (err == SSH_FX_OK)
451 if (err == SSH_FX_EOF) {
453 d->state = STATE::CLOSE;
455 qCritical(log) <<
"Error reading directory:" << d->szPath
456 <<
"Error:" << err << ssh_get_error(m_Session);
457 d->state = STATE::ERR;
463 d->state = STATE::FINISH;
466 int rc = sftp_closedir(d->sftp);
467 if(SSH_NO_ERROR == rc) {
468 d->state = STATE::FINISH;
472 int err = ssh_get_error_code(m_Session);
473 qCritical(log) <<
"Error close directory:" << d->szPath
474 <<
"Error:" << err << ssh_get_error(m_Session);
475 d->state = STATE::FINISH;
480 if(d && STATE::FINISH == d->state) {
481 qDebug(log) <<
"Remote" << d->szPath << d->vFileNode.size();
482 emit sigGetDir(d->remoteFileSystem, d->vFileNode,
true);
483 it = m_vDirs.erase(it);
487 d->state = STATE::CLOSE;
499void CChannelSFTP::slotStartFileTransfer(QSharedPointer<CFileTransfer> f)
501 f->slotSetstate(CFileTransfer::State::Opening);
502 QSharedPointer<_AFILE> file(
new _AFILE);
503 memset(file.data(), 0,
sizeof(_AFILE));
505 file->remote =
nullptr;
506 file->state = STATE::OPEN;
507 file->fileTransfer = f;
508#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
509 file->nChunkSize = BUF_SIZE;
510 file->nConcurrentCount = 5;
512 m_vFiles.append(file);
513 emit sigFileTransferUpdate(f);
517void CChannelSFTP::slotStopFileTransfer(QSharedPointer<CFileTransfer> f)
519 foreach(
auto file, m_vFiles) {
520 if(file->fileTransfer == f) {
521 m_vFiles.removeAll(file);
522 if(-1 != file->local) {
523 ::close(file->local);
527 sftp_close(file->remote);
528 file->remote =
nullptr;
530 f->slotSetstate(CFileTransfer::State::Stop);
531 emit sigFileTransferUpdate(f);
537int CChannelSFTP::AsyncFile()
539 for(
auto it = m_vFiles.begin(); it != m_vFiles.end();) {
541 switch(file->state) {
543 int remoteFlag = O_WRONLY | O_CREAT | O_TRUNC;
544 int localFlag = O_RDONLY;
545 quint32 permission = file->fileTransfer->GetRemotePermission();
547 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
548 remoteFlag = O_RDONLY;
549 localFlag = O_WRONLY | O_CREAT | O_TRUNC;
552 file->remote = sftp_open(
554 file->fileTransfer->GetRemoteFile().toStdString().c_str(),
555 remoteFlag, permission);
558 file->state = STATE::ERR;
559 QString szErr =
"Can't open remote file: " + file->fileTransfer->GetRemoteFile()
560 + ssh_get_error(m_Session);
561 file->fileTransfer->slotSetExplanation(szErr);
562 qCritical(log) << szErr;
565 qDebug(log) <<
"Open remote file:" << file->fileTransfer->GetRemoteFile();
567 sftp_file_set_nonblocking(file->remote);
570 file->fileTransfer->GetLocalFile().toStdString().c_str(),
571 localFlag, permission);
572 if(-1 == file->local) {
573 file->state = STATE::ERR;
574 QString szErr =
"Can't open local file: " + file->fileTransfer->GetLocalFile() +
" " + strerror(errno);
575 file->fileTransfer->slotSetExplanation(szErr);
576 qCritical(log) << szErr;
579 qDebug(log) <<
"Open local file:" << file->fileTransfer->GetLocalFile();
581 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
582#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
583 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
584 sftp_limits_t lim = sftp_limits(m_SessionSftp);
586 file->nChunkSize = lim->max_read_length;
587 qDebug(log) <<
"limits: max_open_handles:" << lim->max_open_handles
588 <<
"max_packet_length" << lim->max_packet_length
589 <<
"max_read_length" << lim->max_read_length
590 <<
"max_write_length:" << lim->max_write_length;
591 sftp_limits_free(lim);
594 quint64 nRequestBytes = 0;
596 i < file->nConcurrentCount
597 && nRequestBytes < file->fileTransfer->GetFileSize();
599 sftp_aio aio =
nullptr;
600 quint64 nRequest = file->fileTransfer->GetFileSize() - nRequestBytes;
601 if(nRequest > file->nChunkSize)
602 nRequest = file->nChunkSize;
603 ssize_t nRet = sftp_aio_begin_read(file->remote, nRequest, &aio);
605 int rc = ssh_get_error_code(m_Session);
606 if (rc != SSH_NO_ERROR) {
607 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
608 szErr += ssh_get_error(m_Session);
609 qCritical(log) << szErr;
613 Q_ASSERT(nRequest == nRet);
614 nRequestBytes += nRet;
615 file->aio.append(aio);
619 file->asyncReadId = sftp_async_read_begin(file->remote, BUF_SIZE);
620 if(file->asyncReadId < 0) {
621 file->state = STATE::ERR;
622 QString szErr =
"sftp_async_read_begin failed." + sftp_get_error(m_SessionSftp);
623 file->fileTransfer->slotSetExplanation(szErr);
624 qCritical(log) << szErr;
629#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
630 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
631 sftp_limits_t lim = sftp_limits(m_SessionSftp);
633 file->nChunkSize = lim->max_write_length;
634 qDebug(log) <<
"limits: max_open_handles:" << lim->max_open_handles
635 <<
"max_packet_length" << lim->max_packet_length
636 <<
"max_read_length" << lim->max_read_length
637 <<
"max_write_length:" << lim->max_write_length;
638 sftp_limits_free(lim);
642 file->buffer =
new char[file->nChunkSize];
644 file->state = STATE::ERR;
649 i < file->nConcurrentCount
650 && file->nRequests < file->fileTransfer->GetFileSize();
652 sftp_aio aio =
nullptr;
653 quint64 nRequest = file->fileTransfer->GetFileSize() - file->nRequests;
654 if(nRequest > file->nChunkSize)
655 nRequest = file->nChunkSize;
656 ssize_t nLen = ::read(file->local, file->buffer, nRequest);
657 Q_ASSERT(nLen == nRequest);
658 ssize_t nRet = sftp_aio_begin_write(file->remote, file->buffer, nLen, &aio);
660 int rc = ssh_get_error_code(m_Session);
661 if (rc != SSH_NO_ERROR) {
662 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
663 szErr += ssh_get_error(m_Session);
664 qCritical(log) << szErr;
668 Q_ASSERT(nRequest == nRet);
669 file->nRequests += nRet;
670 file->aio.append(aio);
676 file->state = STATE::READ;
677 file->fileTransfer->slotSetstate(CFileTransfer::State::Transferring);
678 emit sigFileTransferUpdate(file->fileTransfer);
681 if(file->fileTransfer->GetDirection() == CFileTransfer::Direction::Download) {
682#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
683 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
684 for(
auto it = file->aio.begin(); it != file->aio.end();) {
686 if(
nullptr == file->buffer)
687 file->buffer =
new char[file->nChunkSize];
688 if(!(aio && file->buffer))
690 ssize_t nRet = sftp_aio_wait_read(&aio, file->buffer, file->nChunkSize);
692 if(SSH_AGAIN == nRet)
694 int rc = ssh_get_error_code(m_Session);
695 if (rc != SSH_NO_ERROR) {
696 file->state = STATE::ERR;
697 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
698 szErr += ssh_get_error(m_Session);
699 qCritical(log) << szErr;
703 file->nTransfers += nRet;
704 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
705 file->state = STATE::CLOSE;
707 it = file->aio.erase(it);
709 int nLen = ::write(file->local, file->buffer, nRet);
712 file->state = STATE::ERR;
716 qCritical(log) <<
"IO is buse, Write file error:" << file->fileTransfer->GetLocalFile();
719 file->fileTransfer->slotTransferSize(nRet);
720 emit sigFileTransferUpdate(file->fileTransfer);
722 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
723 file->state = STATE::CLOSE;
726 if(file->aio.size() > 0)
729 quint64 nRequestBytes = file->nTransfers;
731 i < file->nConcurrentCount
732 && nRequestBytes < file->fileTransfer->GetFileSize();
734 sftp_aio aio =
nullptr;
735 quint64 nRequest = file->fileTransfer->GetFileSize() - nRequestBytes;
736 if(nRequest > file->nChunkSize)
737 nRequest = file->nChunkSize;
738 ssize_t nRet = sftp_aio_begin_read(file->remote, nRequest, &aio);
740 int rc = ssh_get_error_code(m_Session);
741 if (rc != SSH_NO_ERROR) {
742 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
743 szErr += ssh_get_error(m_Session);
744 qCritical(log) << szErr;
748 if (nRequest != nRet) {
750 "Error during sftp aio download: sftp_aio_begin_read() "
751 "requesting less bytes even when the number of bytes "
752 "asked to read are within the max limit";
753 qWarning(log) << szErr << nRequest << nRet;
756 nRequestBytes += nRet;
757 file->aio.append(aio);
760 file->state = STATE::ERR;
761 QString szErr = tr(
"Error: Asynchronous uploads are not supported");
762 file->fileTransfer->slotSetExplanation(szErr);
763 qCritical(log) << szErr;
767 int nbytes = sftp_async_read(file->remote, file->buffer + file->offset, BUF_SIZE, file->asyncReadId);
768 if (nbytes > 0 || SSH_AGAIN == nbytes) {
770 int nLen = ::write(file->local, file->buffer + file->offset, nbytes);
772 file->fileTransfer->slotTransferSize(nLen);
774 emit sigFileTransferUpdate(file->fileTransfer);
776 file->state = STATE::ERR;
777 QString szErr =
"Write local file fail:" + sftp_get_error(m_SessionSftp);
778 file->fileTransfer->slotSetExplanation(szErr);
782 if (file->asyncReadId = sftp_async_read_begin(file->remote, BUF_SIZE) < 0) {
783 file->state = STATE::ERR;
784 QString szErr =
"sftp_async_read_begin failed." + sftp_get_error(m_SessionSftp);
785 file->fileTransfer->slotSetExplanation(szErr);
786 qCritical(log) << szErr;
788 }
else if (nbytes == 0) {
789 file->state = STATE::CLOSE;
790 file->asyncReadId = -1;
792 file->state = STATE::ERR;
793 QString szErr =
"sftp_async_read failed." + sftp_get_error(m_SessionSftp);
794 file->fileTransfer->slotSetExplanation(szErr);
795 qCritical(log) << szErr;
799 if(ssh_version(SSH_VERSION_INT(0, 11,0))) {
800 for(
auto it = file->aio.begin(); it != file->aio.end();) {
802 ssize_t nRet = sftp_aio_wait_write(&aio);
804 if(SSH_AGAIN == nRet)
806 int rc = ssh_get_error_code(m_Session);
807 if (rc != SSH_NO_ERROR) {
808 file->state = STATE::ERR;
809 QString szErr =
"Error during sftp aio upload: " + QString::number(rc);
810 szErr += ssh_get_error(m_Session);
811 qCritical(log) << szErr;
815 file->nTransfers += nRet;
816 if(file->fileTransfer->GetFileSize() == file->nTransfers) {
817 file->state = STATE::CLOSE;
819 it = file->aio.erase(it);
821 if(file->aio.size() >= file->nConcurrentCount)
823 int size = file->nConcurrentCount - file->aio.size();
826 && file->nRequests < file->fileTransfer->GetFileSize();
828 sftp_aio aio =
nullptr;
829 quint64 nRequest = file->fileTransfer->GetFileSize() - file->nRequests;
830 if(nRequest > file->nChunkSize)
831 nRequest = file->nChunkSize;
832 ssize_t nLen = ::read(file->local, file->buffer, nRequest);
833 Q_ASSERT(nLen == nRequest);
834 ssize_t nRet = sftp_aio_begin_write(file->remote, file->buffer, nLen, &aio);
836 int rc = ssh_get_error_code(m_Session);
837 if (rc != SSH_NO_ERROR) {
838 QString szErr =
"Error during sftp aio download: " + QString::number(rc);
839 szErr += ssh_get_error(m_Session);
840 qCritical(log) << szErr;
844 Q_ASSERT(nRequest == nRet);
845 file->nRequests += nRet;
846 file->aio.append(aio);
853 file->state = STATE::FINISH;
854 file->fileTransfer->slotSetstate(CFileTransfer::State::Closing);
855 emit sigFileTransferUpdate(file->fileTransfer);
858 case STATE::FINISH: {
859#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
862 it = m_vFiles.erase(it);
863 file->fileTransfer->slotSetstate(CFileTransfer::State::Finish);
864 emit sigFileTransferUpdate(file->fileTransfer);
868#if LIBSSH_VERSION_INT >= SSH_VERSION_INT(0, 11, 0)
869 foreach (
auto aio, file->aio) {
875 it = m_vFiles.erase(it);
876 file->fileTransfer->slotSetstate(CFileTransfer::State::Fail);
877 emit sigFileTransferUpdate(file->fileTransfer);
887int CChannelSFTP::CleanFileAIO(QSharedPointer<_AFILE> file)
890 delete []file->buffer;
891 file->buffer =
nullptr;
894 sftp_close(file->remote);
895 file->remote ==
nullptr;
897 if(-1 != file->local) {
898 ::close(file->local);
int GetDir(CRemoteFileSystem *p)
Synchronize to get the directory.
void slotGetDir(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