Skip to content

Commit

Permalink
Implementing SftpChannel::downloadDir
Browse files Browse the repository at this point in the history
  • Loading branch information
Andres Pagliano committed Aug 12, 2013
1 parent 53863e1 commit 6cc1f28
Show file tree
Hide file tree
Showing 5 changed files with 228 additions and 28 deletions.
200 changes: 178 additions & 22 deletions src/libs/ssh/sftpchannel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 80,32 @@ namespace {
return response.status == SSH_FX_OK ? QString()
: errorMessage(response.errorString, alternativeMessage);
}

QSharedPointer<QFile> openFile(const QString &localFilePath, SftpOverwriteMode mode)
{
QSharedPointer<QFile> localFile(new QFile(localFilePath));

if (mode == SftpSkipExisting && localFile->exists())
return QSharedPointer<QFile>();

QIODevice::OpenMode openMode = QIODevice::WriteOnly;
if (mode == SftpOverwriteExisting)
openMode |= QIODevice::Truncate;
else if (mode == SftpAppendToExisting)
openMode |= QIODevice::Append;

if (!localFile->open(openMode))
return QSharedPointer<QFile>();

return localFile;
}
} // anonymous namespace
} // namespace Internal

//--------------------------------------------------------------------------------------------------
// SftpChannel
//--------------------------------------------------------------------------------------------------

SftpChannel::SftpChannel(quint32 channelId,
Internal::SshSendFacility &sendFacility)
: d(new Internal::SftpChannelPrivate(channelId, sendFacility, this))
Expand Down Expand Up @@ -194,15 217,8 @@ SftpJobId SftpChannel::uploadFile(const QString &localFilePath,
SftpJobId SftpChannel::downloadFile(const QString &remoteFilePath,
const QString &localFilePath, SftpOverwriteMode mode)
{
QSharedPointer<QFile> localFile(new QFile(localFilePath));
if (mode == SftpSkipExisting && localFile->exists())
return SftpInvalidJob;
QIODevice::OpenMode openMode = QIODevice::WriteOnly;
if (mode == SftpOverwriteExisting)
openMode |= QIODevice::Truncate;
else if (mode == SftpAppendToExisting)
openMode |= QIODevice::Append;
if (!localFile->open(openMode))
QSharedPointer<QFile> localFile = Internal::openFile(localFilePath, mode);
if (localFile.isNull())
return SftpInvalidJob;
return d->createJob(Internal::SftpDownload::Ptr(
new Internal::SftpDownload( d->m_nextJobId, remoteFilePath, localFile)));
Expand All @@ -228,11 244,31 @@ SftpJobId SftpChannel::uploadDir(const QString &localDirPath,
return uploadDirOp->jobId;
}

SftpJobId SftpChannel::downloadDir(const QString &remoteDirPath,
const QString &localDirPath, SftpOverwriteMode mode)
{
if (state() != Initialized)
return SftpInvalidJob;
if (!QDir().mkpath(localDirPath))
return SftpInvalidJob;
const Internal::SftpDownloadDir::Ptr downloadDirOp(
new Internal::SftpDownloadDir( d->m_nextJobId, mode));
const Internal::SftpListDir::Ptr lsdirOp(
new Internal::SftpListDir( d->m_nextJobId, remoteDirPath, downloadDirOp));
downloadDirOp->lsdirsInProgress.insert(lsdirOp,
Internal::SftpDownloadDir::Dir(localDirPath, remoteDirPath));
d->createJob(lsdirOp);
return downloadDirOp->jobId;
}

SftpChannel::~SftpChannel()
{
delete d;
}

//--------------------------------------------------------------------------------------------------
// SftpChannelPrivate
//--------------------------------------------------------------------------------------------------

namespace Internal {

Expand Down Expand Up @@ -554,9 590,15 @@ void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it,
const SftpStatusResponse &response)
{
SftpListDir::Ptr op = it.value().staticCast<SftpListDir>();

if (op->parentJob && op->parentJob->hasError) {
m_jobs.erase(it);
return;
}

switch (op->state) {
case SftpListDir::OpenRequested:
emit finished(op->jobId, errorMessage(response.errorString,
reportRequestError(op, errorMessage(response.errorString,
tr("Remote directory could not be opened for reading.")));
m_jobs.erase(it);
break;
Expand All @@ -569,10 611,31 @@ void SftpChannelPrivate::handleLsStatus(const JobMap::Iterator &it,
op->jobId).rawData());
break;
case SftpListDir::CloseRequested:
if (!op->hasError) {
if (op->hasError || (op->parentJob && op->parentJob->hasError)) {
m_jobs.erase(it);
return;
}

{
const QString error = errorMessage(response,
tr("Failed to close remote directory."));
emit finished(op->jobId, error);

if (op->parentJob) {
if (!error.isEmpty()) {
op->parentJob->setError();
}
if (op->parentJob->hasError) {
emit finished(op->parentJob->jobId, error);
} else {
op->parentJob->lsdirsInProgress.remove(op);
if (op->parentJob->lsdirsInProgress.isEmpty() &&
op->parentJob->downloadsInProgress.isEmpty()) {
emit finished(op->parentJob->jobId);
}
}
} else {
emit finished(op->jobId, error);
}
}
m_jobs.erase(it);
break;
Expand All @@ -586,11 649,16 @@ void SftpChannelPrivate::handleGetStatus(const JobMap::Iterator &it,
const SftpStatusResponse &response)
{
SftpDownload::Ptr op = it.value().staticCast<SftpDownload>();

if (op->parentJob && op->parentJob->hasError) {
m_jobs.erase(it);
return;
}

switch (op->state) {
case SftpDownload::OpenRequested:
emit finished(op->jobId,
errorMessage(response.errorString,
tr("Failed to open remote file for reading.")));
reportRequestError(op, errorMessage(response.errorString,
tr("Failed to open remote file for reading.")));
m_jobs.erase(it);
break;
case SftpDownload::Open:
Expand All @@ -609,11 677,20 @@ void SftpChannelPrivate::handleGetStatus(const JobMap::Iterator &it,
case SftpDownload::CloseRequested:
Q_ASSERT(op->inFlightCount == 1);
if (!op->hasError) {
if (response.status == SSH_FX_OK)
emit finished(op->jobId);
else
reportRequestError(op, errorMessage(response.errorString,
tr("Failed to close remote file.")));
if (response.status == SSH_FX_OK) {
if (op->parentJob) {
op->parentJob->downloadsInProgress.removeOne(op);
if (op->parentJob->lsdirsInProgress.isEmpty()
&& op->parentJob->downloadsInProgress.isEmpty())
emit finished(op->parentJob->jobId);
} else {
emit finished(op->jobId);
}
} else {
const QString error = errorMessage(response.errorString,
tr("Failed to close remote file."));
reportRequestError(op, error);
}
}
removeTransferRequest(it);
break;
Expand Down Expand Up @@ -719,7 796,13 @@ void SftpChannelPrivate::handleName()
attributesToFileInfo(file.attributes, fileInfo);
fileInfoList << fileInfo;
}
emit fileInfoAvailable(op->jobId, fileInfoList);

if (op->parentJob) {
handleDownloadDir(op, fileInfoList);
} else {
emit fileInfoAvailable(op->jobId, fileInfoList);
}

sendData(m_outgoingPacket.generateReadDir(op->remoteHandle,
op->jobId).rawData());
break;
Expand Down Expand Up @@ -820,6 903,58 @@ void SftpChannelPrivate::handleAttrs()
}
}

void SftpChannelPrivate::handleDownloadDir(SftpListDir::Ptr op,
const QList<SftpFileInfo> &fileInfoList)
{
if (op->parentJob->hasError) {
return;
}

foreach (SftpFileInfo fileInfo, fileInfoList) {
Internal::SftpDownloadDir::Dir dir = op->parentJob->lsdirsInProgress[op];
QString fullPathRemote = QDir(dir.remoteDir).path() "/" fileInfo.name;
QString fullPathLocal = QDir(dir.localDir).path() "/" fileInfo.name;

if (fileInfo.type == FileTypeRegular) {
QSharedPointer<QFile> localFile
= Internal::openFile(fullPathLocal, op->parentJob->mode);

if (localFile.isNull()) {
// andres.pagliano TODO handle error
//std::cout << "paglian: ERROR cannot open file: " << fullPathLocal.toStdString() << "\n";
continue;
}

Internal::SftpDownload::Ptr downloadJob = Internal::SftpDownload::Ptr(
new Internal::SftpDownload( m_nextJobId, fullPathRemote, localFile, op->parentJob));

op->parentJob->downloadsInProgress.append(downloadJob);
createJob(downloadJob);

} else if (fileInfo.type == FileTypeDirectory) {
if (fileInfo.name == "." || fileInfo.name == "..") {
continue;
}

if (!QDir().mkpath(fullPathLocal)) {
// andres.pagliano TODO handle error
//std::cout << "paglian: ERROR cannot create dir: " << fullPathLocal.toStdString() << "\n";
continue;
}

Internal::SftpListDir::Ptr lsdir = Internal::SftpListDir::Ptr(
new Internal::SftpListDir( m_nextJobId, fullPathRemote, op->parentJob));

op->parentJob->lsdirsInProgress.insert(lsdir,
Internal::SftpDownloadDir::Dir(fullPathLocal, fullPathRemote));
createJob(lsdir);

} else {
// andres.pagliano TODO handle?
}
}
}

SftpChannelPrivate::JobMap::Iterator SftpChannelPrivate::lookupJob(SftpJobId id)
{
JobMap::Iterator it = m_jobs.find(id);
Expand Down Expand Up @@ -873,7 1008,28 @@ void SftpChannelPrivate::sendReadRequest(const SftpDownload::Ptr &job,
void SftpChannelPrivate::reportRequestError(const AbstractSftpOperationWithHandle::Ptr &job,
const QString &error)
{
emit finished(job->jobId, error);
// andres.pagliano TODO refactor

// Report list error during download dir
SftpListDir::Ptr lsjob = job.dynamicCast<SftpListDir>();
if (!lsjob.isNull() && lsjob->parentJob) {
if (!lsjob->parentJob->hasError) {
emit finished(lsjob->parentJob->jobId, error);
lsjob->parentJob->hasError = true;
}
} else {
// Report download error during recursive download dir
SftpDownload::Ptr djob = job.dynamicCast<SftpDownload>();
if (!djob.isNull() && djob->parentJob) {
if (!djob->parentJob->hasError) {
emit finished(djob->parentJob->jobId, error);
djob->parentJob->hasError = true;
}
} else {
// Other error
emit finished(job->jobId, error);
}
}
job->hasError = true;
}

Expand Down
2 changes: 2 additions & 0 deletions src/libs/ssh/sftpchannel.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 79,8 @@ class QSSH_EXPORT SftpChannel : public QObject
const QString &localFilePath, SftpOverwriteMode mode);
SftpJobId uploadDir(const QString &localDirPath,
const QString &remoteParentDirPath);
SftpJobId downloadDir(const QString &remoteDirPath,
const QString &localDirPath, SftpOverwriteMode mode);

~SftpChannel();

Expand Down
2 changes: 2 additions & 0 deletions src/libs/ssh/sftpchannel_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 88,8 @@ class SftpChannelPrivate : public AbstractSshChannel
void handleReadData();
void handleAttrs();

void handleDownloadDir(SftpListDir::Ptr op, const QList<SftpFileInfo> & fileInfoList);

void handleStatusGeneric(const JobMap::Iterator &it,
const SftpStatusResponse &response);
void handleMkdirStatus(const JobMap::Iterator &it,
Expand Down
11 changes: 7 additions & 4 deletions src/libs/ssh/sftpoperation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 119,9 @@ AbstractSftpOperationWithHandle::AbstractSftpOperationWithHandle(SftpJobId jobId
AbstractSftpOperationWithHandle::~AbstractSftpOperationWithHandle() { }


SftpListDir::SftpListDir(SftpJobId jobId, const QString &path)
: AbstractSftpOperationWithHandle(jobId, path)
SftpListDir::SftpListDir(SftpJobId jobId, const QString &path,
const QSharedPointer<SftpDownloadDir> &parentJob)
: AbstractSftpOperationWithHandle(jobId, path), parentJob(parentJob)
{
}

Expand Down Expand Up @@ -172,8 173,10 @@ void AbstractSftpTransfer::calculateInFlightCount(quint32 chunkSize)


SftpDownload::SftpDownload(SftpJobId jobId, const QString &remotePath,
const QSharedPointer<QFile> &localFile)
: AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob)
const QSharedPointer<QFile> &localFile,
const QSharedPointer<QSsh::Internal::SftpDownloadDir> &parentJob)
: AbstractSftpTransfer(jobId, remotePath, localFile), eofId(SftpInvalidJob),
parentJob(parentJob)
{
}

Expand Down
Loading

0 comments on commit 6cc1f28

Please sign in to comment.