forked from qt-creator/qt-creator
SSH: Add SFTP operations needed to implement remote FS traversal.
Change-Id: I3e7b52513211959a976545667e8e8372f2001c7e Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
@@ -95,6 +95,9 @@ SftpChannel::SftpChannel(quint32 channelId,
|
||||
SIGNAL(initializationFailed(QString)), Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(dataAvailable(Utils::SftpJobId, QString)), this,
|
||||
SIGNAL(dataAvailable(Utils::SftpJobId, QString)), Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(fileInfoAvailable(Utils::SftpJobId, QList<Utils::SftpFileInfo>)), this,
|
||||
SIGNAL(fileInfoAvailable(Utils::SftpJobId, QList<Utils::SftpFileInfo>)),
|
||||
Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(finished(Utils::SftpJobId,QString)), this,
|
||||
SIGNAL(finished(Utils::SftpJobId,QString)), Qt::QueuedConnection);
|
||||
connect(d, SIGNAL(closed()), this, SIGNAL(closed()), Qt::QueuedConnection);
|
||||
@@ -131,6 +134,12 @@ void SftpChannel::closeChannel()
|
||||
d->closeChannel();
|
||||
}
|
||||
|
||||
SftpJobId SftpChannel::statFile(const QString &path)
|
||||
{
|
||||
return d->createJob(Internal::SftpStatFile::Ptr(
|
||||
new Internal::SftpStatFile(++d->m_nextJobId, path)));
|
||||
}
|
||||
|
||||
SftpJobId SftpChannel::listDirectory(const QString &path)
|
||||
{
|
||||
return d->createJob(Internal::SftpListDir::Ptr(
|
||||
@@ -453,6 +462,7 @@ void SftpChannelPrivate::handleStatus()
|
||||
case AbstractSftpOperation::MakeDir:
|
||||
handleMkdirStatus(it, response);
|
||||
break;
|
||||
case AbstractSftpOperation::StatFile:
|
||||
case AbstractSftpOperation::RmDir:
|
||||
case AbstractSftpOperation::Rm:
|
||||
case AbstractSftpOperation::Rename:
|
||||
@@ -702,10 +712,16 @@ void SftpChannelPrivate::handleName()
|
||||
"Unexpected SSH_FXP_NAME packet.");
|
||||
}
|
||||
|
||||
QList<SftpFileInfo> fileInfoList;
|
||||
for (int i = 0; i < response.files.count(); ++i) {
|
||||
const SftpFile &file = response.files.at(i);
|
||||
emit dataAvailable(op->jobId, file.fileName);
|
||||
|
||||
SftpFileInfo fileInfo;
|
||||
fileInfo.name = file.fileName;
|
||||
attributesToFileInfo(file.attributes, fileInfo);
|
||||
fileInfoList << fileInfo;
|
||||
}
|
||||
emit fileInfoAvailable(op->jobId, fileInfoList);
|
||||
sendData(m_outgoingPacket.generateReadDir(op->remoteHandle,
|
||||
op->jobId).rawData());
|
||||
break;
|
||||
@@ -753,6 +769,18 @@ void SftpChannelPrivate::handleAttrs()
|
||||
{
|
||||
const SftpAttrsResponse &response = m_incomingPacket.asAttrsResponse();
|
||||
JobMap::Iterator it = lookupJob(response.requestId);
|
||||
|
||||
SftpStatFile::Ptr statOp = it.value().dynamicCast<SftpStatFile>();
|
||||
if (statOp) {
|
||||
SftpFileInfo fileInfo;
|
||||
fileInfo.name = QFileInfo(statOp->path).fileName();
|
||||
attributesToFileInfo(response.attrs, fileInfo);
|
||||
emit fileInfoAvailable(it.key(), QList<SftpFileInfo>() << fileInfo);
|
||||
emit finished(it.key());
|
||||
m_jobs.erase(it);
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractSftpTransfer::Ptr transfer
|
||||
= it.value().dynamicCast<AbstractSftpTransfer>();
|
||||
if (!transfer || transfer->state != AbstractSftpTransfer::Open
|
||||
@@ -866,6 +894,43 @@ void SftpChannelPrivate::sendTransferCloseHandle(const AbstractSftpTransfer::Ptr
|
||||
job->state = SftpDownload::CloseRequested;
|
||||
}
|
||||
|
||||
void SftpChannelPrivate::attributesToFileInfo(const SftpFileAttributes &attributes,
|
||||
SftpFileInfo &fileInfo) const
|
||||
{
|
||||
if (attributes.sizePresent) {
|
||||
fileInfo.sizeValid = true;
|
||||
fileInfo.size = attributes.size;
|
||||
}
|
||||
if (attributes.permissionsPresent) {
|
||||
if (attributes.permissions & 0x8000) // S_IFREG
|
||||
fileInfo.type = FileTypeRegular;
|
||||
else if (attributes.permissions & 0x4000) // S_IFDIR
|
||||
fileInfo.type = FileTypeDirectory;
|
||||
else
|
||||
fileInfo.type = FileTypeOther;
|
||||
fileInfo.permissionsValid = true;
|
||||
fileInfo.permissions = 0;
|
||||
if (attributes.permissions & 00001) // S_IXOTH
|
||||
fileInfo.permissions |= QFile::ExeOther;
|
||||
if (attributes.permissions & 00002) // S_IWOTH
|
||||
fileInfo.permissions |= QFile::WriteOther;
|
||||
if (attributes.permissions & 00004) // S_IROTH
|
||||
fileInfo.permissions |= QFile::ReadOther;
|
||||
if (attributes.permissions & 00010) // S_IXGRP
|
||||
fileInfo.permissions |= QFile::ExeGroup;
|
||||
if (attributes.permissions & 00020) // S_IWGRP
|
||||
fileInfo.permissions |= QFile::WriteGroup;
|
||||
if (attributes.permissions & 00040) // S_IRGRP
|
||||
fileInfo.permissions |= QFile::ReadGroup;
|
||||
if (attributes.permissions & 00100) // S_IXUSR
|
||||
fileInfo.permissions |= QFile::ExeUser | QFile::ExeOwner;
|
||||
if (attributes.permissions & 00200) // S_IWUSR
|
||||
fileInfo.permissions |= QFile::WriteUser | QFile::WriteOwner;
|
||||
if (attributes.permissions & 00400) // S_IRUSR
|
||||
fileInfo.permissions |= QFile::ReadUser | QFile::ReadOwner;
|
||||
}
|
||||
}
|
||||
|
||||
void SftpChannelPrivate::removeTransferRequest(const JobMap::Iterator &it)
|
||||
{
|
||||
--it.value().staticCast<AbstractSftpTransfer>()->inFlightCount;
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
void initialize();
|
||||
void closeChannel();
|
||||
|
||||
SftpJobId statFile(const QString &path);
|
||||
SftpJobId listDirectory(const QString &dirPath);
|
||||
SftpJobId createDirectory(const QString &dirPath);
|
||||
SftpJobId removeDirectory(const QString &dirPath);
|
||||
@@ -91,13 +92,16 @@ signals:
|
||||
// error.isEmpty <=> finished successfully
|
||||
void finished(Utils::SftpJobId job, const QString &error = QString());
|
||||
|
||||
/*
|
||||
* This signal is only emitted by the "List Directory" operation,
|
||||
* one file at a time.
|
||||
// TODO: Also emit for each file copied by uploadDir().
|
||||
*/
|
||||
void dataAvailable(Utils::SftpJobId job, const QString &data);
|
||||
|
||||
/*
|
||||
* This signal is emitted as a result of:
|
||||
* - statFile() (with the list having exactly one element)
|
||||
* - listDirectory() (potentially more than once)
|
||||
*/
|
||||
void fileInfoAvailable(Utils::SftpJobId job, const QList<Utils::SftpFileInfo> &fileInfoList);
|
||||
|
||||
private:
|
||||
SftpChannel(quint32 channelId, Internal::SshSendFacility &sendFacility);
|
||||
|
||||
|
||||
@@ -65,6 +65,7 @@ signals:
|
||||
void closed();
|
||||
void finished(Utils::SftpJobId job, const QString &error = QString());
|
||||
void dataAvailable(Utils::SftpJobId job, const QString &data);
|
||||
void fileInfoAvailable(Utils::SftpJobId job, const QList<Utils::SftpFileInfo> &fileInfoList);
|
||||
|
||||
private:
|
||||
typedef QMap<SftpJobId, AbstractSftpOperation::Ptr> JobMap;
|
||||
@@ -116,6 +117,8 @@ private:
|
||||
void sendTransferCloseHandle(const AbstractSftpTransfer::Ptr &job,
|
||||
quint32 requestId);
|
||||
|
||||
void attributesToFileInfo(const SftpFileAttributes &attributes, SftpFileInfo &fileInfo) const;
|
||||
|
||||
JobMap::Iterator lookupJob(SftpJobId id);
|
||||
JobMap m_jobs;
|
||||
SftpOutgoingPacket m_outgoingPacket;
|
||||
|
||||
@@ -35,7 +35,8 @@
|
||||
|
||||
#include <utils/utils_global.h>
|
||||
|
||||
#include <QtCore/QtGlobal>
|
||||
#include <QFile>
|
||||
#include <QString>
|
||||
|
||||
namespace Utils {
|
||||
|
||||
@@ -46,6 +47,23 @@ enum SftpOverwriteMode {
|
||||
SftpOverwriteExisting, SftpAppendToExisting, SftpSkipExisting
|
||||
};
|
||||
|
||||
enum SftpFileType { FileTypeRegular, FileTypeDirectory, FileTypeOther, FileTypeUnknown };
|
||||
|
||||
class QTCREATOR_UTILS_EXPORT SftpFileInfo
|
||||
{
|
||||
public:
|
||||
SftpFileInfo() : type(FileTypeUnknown), sizeValid(false), permissionsValid(false) { }
|
||||
|
||||
QString name;
|
||||
SftpFileType type;
|
||||
quint64 size;
|
||||
QFile::Permissions permissions;
|
||||
|
||||
// The RFC allows an SFTP server not to support any file attributes beyond the name.
|
||||
bool sizeValid;
|
||||
bool permissionsValid;
|
||||
};
|
||||
|
||||
} // namespace Utils
|
||||
|
||||
#endif // SFTPDEFS_H
|
||||
|
||||
@@ -46,6 +46,16 @@ AbstractSftpOperation::AbstractSftpOperation(SftpJobId jobId) : jobId(jobId)
|
||||
AbstractSftpOperation::~AbstractSftpOperation() { }
|
||||
|
||||
|
||||
SftpStatFile::SftpStatFile(SftpJobId jobId, const QString &path)
|
||||
: AbstractSftpOperation(jobId), path(path)
|
||||
{
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpStatFile::initialPacket(SftpOutgoingPacket &packet)
|
||||
{
|
||||
return packet.generateStat(path, jobId);
|
||||
}
|
||||
|
||||
SftpMakeDir::SftpMakeDir(SftpJobId jobId, const QString &path,
|
||||
const SftpUploadDir::Ptr &parentJob)
|
||||
: AbstractSftpOperation(jobId), parentJob(parentJob), remoteDir(path)
|
||||
|
||||
@@ -53,7 +53,7 @@ struct AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<AbstractSftpOperation> Ptr;
|
||||
enum Type {
|
||||
ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile
|
||||
StatFile, ListDir, MakeDir, RmDir, Rm, Rename, CreateLink, CreateFile, Download, UploadFile
|
||||
};
|
||||
|
||||
AbstractSftpOperation(SftpJobId jobId);
|
||||
@@ -70,6 +70,17 @@ private:
|
||||
|
||||
struct SftpUploadDir;
|
||||
|
||||
struct SftpStatFile : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpStatFile> Ptr;
|
||||
|
||||
SftpStatFile(SftpJobId jobId, const QString &path);
|
||||
virtual Type type() const { return StatFile; }
|
||||
virtual SftpOutgoingPacket &initialPacket(SftpOutgoingPacket &packet);
|
||||
|
||||
const QString path;
|
||||
};
|
||||
|
||||
struct SftpMakeDir : public AbstractSftpOperation
|
||||
{
|
||||
typedef QSharedPointer<SftpMakeDir> Ptr;
|
||||
|
||||
@@ -60,6 +60,11 @@ SftpOutgoingPacket &SftpOutgoingPacket::generateInit(quint32 version)
|
||||
return init(SSH_FXP_INIT, 0).appendInt(version).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateStat(const QString &path, quint32 requestId)
|
||||
{
|
||||
return init(SSH_FXP_LSTAT, requestId).appendString(path).finalize();
|
||||
}
|
||||
|
||||
SftpOutgoingPacket &SftpOutgoingPacket::generateOpenDir(const QString &path,
|
||||
quint32 requestId)
|
||||
{
|
||||
|
||||
@@ -44,6 +44,7 @@ class SftpOutgoingPacket : public AbstractSftpPacket
|
||||
public:
|
||||
SftpOutgoingPacket();
|
||||
SftpOutgoingPacket &generateInit(quint32 version);
|
||||
SftpOutgoingPacket &generateStat(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateOpenDir(const QString &path, quint32 requestId);
|
||||
SftpOutgoingPacket &generateReadDir(const QByteArray &handle,
|
||||
quint32 requestId);
|
||||
|
||||
@@ -76,6 +76,8 @@ namespace {
|
||||
Botan::LibraryInitializer::initialize("thread_safe=true");
|
||||
qRegisterMetaType<Utils::SshError>("Utils::SshError");
|
||||
qRegisterMetaType<Utils::SftpJobId>("Utils::SftpJobId");
|
||||
qRegisterMetaType<Utils::SftpFileInfo>("Utils::SftpFileInfo");
|
||||
qRegisterMetaType<QList <Utils::SftpFileInfo> >("QList<Utils::SftpFileInfo>");
|
||||
staticInitializationsDone = true;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user