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);
 
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