using namespace KIO;
extern "C"
{
- int KDE_EXPORT kdemain( int argc, char **argv )
- {
- QCoreApplication app(argc, argv);
- KComponentData componentData( "kio_sftp" );
- (void) KGlobal::locale();
+ int KDE_EXPORT kdemain( int argc, char **argv )
+ {
+ QCoreApplication app(argc, argv);
+ KComponentData componentData( "kio_sftp" );
+ (void) KGlobal::locale();
- kDebug(KIO_SFTP_DB) << "*** Starting kio_sftp ";
+ kDebug(KIO_SFTP_DB) << "*** Starting kio_sftp ";
- if (argc != 4) {
- kDebug(KIO_SFTP_DB) << "Usage: kio_sftp protocol domain-socket1 domain-socket2";
- exit(-1);
- }
+ if (argc != 4) {
+ kDebug(KIO_SFTP_DB) << "Usage: kio_sftp protocol domain-socket1 domain-socket2";
+ exit(-1);
+ }
- sftpProtocol slave(argv[2], argv[3]);
- slave.dispatchLoop();
+ sftpProtocol slave(argv[2], argv[3]);
+ slave.dispatchLoop();
- kDebug(KIO_SFTP_DB) << "*** kio_sftp Done";
- return 0;
- }
+ kDebug(KIO_SFTP_DB) << "*** kio_sftp Done";
+ return 0;
+ }
}
// Converts SSH error into KIO error
static int toKIOError (const int err)
{
- switch (err) {
- case SSH_FX_OK:
- break;
- case SSH_FX_NO_SUCH_FILE:
- case SSH_FX_NO_SUCH_PATH:
- return KIO::ERR_DOES_NOT_EXIST;
- case SSH_FX_PERMISSION_DENIED:
- return KIO::ERR_ACCESS_DENIED;
- case SSH_FX_FILE_ALREADY_EXISTS:
- return KIO::ERR_FILE_ALREADY_EXIST;
- case SSH_FX_INVALID_HANDLE:
- return KIO::ERR_MALFORMED_URL;
- case SSH_FX_OP_UNSUPPORTED:
- return KIO::ERR_UNSUPPORTED_ACTION;
- case SSH_FX_BAD_MESSAGE:
- return KIO::ERR_UNKNOWN;
- default:
- return KIO::ERR_INTERNAL;
- }
- return 0;
+ switch (err) {
+ case SSH_FX_OK:
+ break;
+ case SSH_FX_NO_SUCH_FILE:
+ case SSH_FX_NO_SUCH_PATH:
+ return KIO::ERR_DOES_NOT_EXIST;
+ case SSH_FX_PERMISSION_DENIED:
+ return KIO::ERR_ACCESS_DENIED;
+ case SSH_FX_FILE_ALREADY_EXISTS:
+ return KIO::ERR_FILE_ALREADY_EXIST;
+ case SSH_FX_INVALID_HANDLE:
+ return KIO::ERR_MALFORMED_URL;
+ case SSH_FX_OP_UNSUPPORTED:
+ return KIO::ERR_UNSUPPORTED_ACTION;
+ case SSH_FX_BAD_MESSAGE:
+ return KIO::ERR_UNKNOWN;
+ default:
+ return KIO::ERR_INTERNAL;
+ }
+ return 0;
}
// Writes 'len' bytes from 'buf' to the file handle 'fd'.
ssize_t written = write(fd, buf, len);
if (written >= 0) {
- buf += written;
- len -= written;
- continue;
+ buf += written;
+ len -= written;
+ continue;
}
switch(errno) {
case EINTR:
case EAGAIN:
- continue;
+ continue;
case EPIPE:
- return ERR_CONNECTION_BROKEN;
+ return ERR_CONNECTION_BROKEN;
case ENOSPC:
- return ERR_DISK_FULL;
+ return ERR_DISK_FULL;
default:
- return ERR_COULD_NOT_WRITE;
+ return ERR_COULD_NOT_WRITE;
}
}
return 0;
static int auth_callback(const char *prompt, char *buf, size_t len,
int echo, int verify, void *userdata)
{
- if (userdata == NULL) {
- return -1;
- }
+ if (userdata == NULL) {
+ return -1;
+ }
- sftpProtocol *slave = (sftpProtocol *) userdata;
+ sftpProtocol *slave = (sftpProtocol *) userdata;
- if (slave->auth_callback(prompt, buf, len, echo, verify, userdata) < 0) {
- return -1;
- }
+ if (slave->auth_callback(prompt, buf, len, echo, verify, userdata) < 0) {
+ return -1;
+ }
- return 0;
+ return 0;
}
static void log_callback(int priority, const char *function, const char *buffer,
}
int sftpProtocol::auth_callback(const char *prompt, char *buf, size_t len,
- int echo, int verify, void *userdata) {
-
- // unused variables
- (void) echo;
- (void) verify;
- (void) userdata;
-
- QString errMsg;
- if (!mPublicKeyAuthInfo) {
- mPublicKeyAuthInfo = new KIO::AuthInfo;
- } else {
- errMsg = i18n("Incorrect or invalid passphrase");
- }
+ int echo, int verify, void *userdata)
+{
- mPublicKeyAuthInfo->url.setProtocol(QLatin1String("sftp"));
- mPublicKeyAuthInfo->url.setHost(mHost);
- if (mPort > 0 && mPort != DEFAULT_SFTP_PORT) {
- mPublicKeyAuthInfo->url.setPort(mPort);
- }
- mPublicKeyAuthInfo->url.setUser(mUsername);
-
- KUrl u (mPublicKeyAuthInfo->url);
- u.setPath(QString());
- mPublicKeyAuthInfo->comment = u.url();
- mPublicKeyAuthInfo->readOnly = true;
- mPublicKeyAuthInfo->prompt = QString::fromUtf8(prompt);
- mPublicKeyAuthInfo->keepPassword = false; // don't save passwords for public key,
- // that's the task of ssh-agent.
- mPublicKeyAuthInfo->setExtraField(QLatin1String("hide-username-line"), true);
- mPublicKeyAuthInfo->setModified(false);
-
- kDebug(KIO_SFTP_DB) << "Entering authentication callback, prompt=" << mPublicKeyAuthInfo->prompt;
-
- if (!openPasswordDialog(*mPublicKeyAuthInfo, errMsg)) {
- kDebug(KIO_SFTP_DB) << "User canceled public key passpharse dialog";
- return -1;
- }
+ // unused variables
+ (void) echo;
+ (void) verify;
+ (void) userdata;
- strncpy(buf, mPublicKeyAuthInfo->password.toUtf8().constData(), len - 1);
+ QString errMsg;
+ if (!mPublicKeyAuthInfo) {
+ mPublicKeyAuthInfo = new KIO::AuthInfo;
+ } else {
+ errMsg = i18n("Incorrect or invalid passphrase");
+ }
+
+ mPublicKeyAuthInfo->url.setProtocol(QLatin1String("sftp"));
+ mPublicKeyAuthInfo->url.setHost(mHost);
+ if (mPort > 0 && mPort != DEFAULT_SFTP_PORT) {
+ mPublicKeyAuthInfo->url.setPort(mPort);
+ }
+ mPublicKeyAuthInfo->url.setUser(mUsername);
- mPublicKeyAuthInfo->password.fill('x');
- mPublicKeyAuthInfo->password.clear();
+ KUrl u (mPublicKeyAuthInfo->url);
+ u.setPath(QString());
+ mPublicKeyAuthInfo->comment = u.url();
+ mPublicKeyAuthInfo->readOnly = true;
+ mPublicKeyAuthInfo->prompt = QString::fromUtf8(prompt);
+ mPublicKeyAuthInfo->keepPassword = false; // don't save passwords for public key,
+ // that's the task of ssh-agent.
+ mPublicKeyAuthInfo->setExtraField(QLatin1String("hide-username-line"), true);
+ mPublicKeyAuthInfo->setModified(false);
- return 0;
+ kDebug(KIO_SFTP_DB) << "Entering authentication callback, prompt=" << mPublicKeyAuthInfo->prompt;
+
+ if (!openPasswordDialog(*mPublicKeyAuthInfo, errMsg)) {
+ kDebug(KIO_SFTP_DB) << "User canceled public key passpharse dialog";
+ return -1;
+ }
+
+ strncpy(buf, mPublicKeyAuthInfo->password.toUtf8().constData(), len - 1);
+
+ mPublicKeyAuthInfo->password.fill('x');
+ mPublicKeyAuthInfo->password.clear();
+
+ return 0;
}
void sftpProtocol::log_callback(int priority, const char *function, const char *buffer,
int sftpProtocol::authenticateKeyboardInteractive(AuthInfo &info) {
- int err = ssh_userauth_kbdint(mSession, NULL, NULL);
+ int err = ssh_userauth_kbdint(mSession, NULL, NULL);
+
+ while (err == SSH_AUTH_INFO) {
+ const QString name = QString::fromUtf8(ssh_userauth_kbdint_getname(mSession));
+ const QString instruction = QString::fromUtf8(ssh_userauth_kbdint_getinstruction(mSession));
+ const int n = ssh_userauth_kbdint_getnprompts(mSession);
+
+ kDebug(KIO_SFTP_DB) << "name=" << name << " instruction=" << instruction << " prompts=" << n;
+
+ for (int i = 0; i < n; ++i) {
+ char echo;
+ const char *answer = "";
+
+ const QString prompt = QString::fromUtf8(ssh_userauth_kbdint_getprompt(mSession, i, &echo));
+ kDebug(KIO_SFTP_DB) << "prompt=" << prompt << " echo=" << QString::number(echo);
+ if (echo) {
+ // See RFC4256 Section 3.3 User Interface
+ KIO::AuthInfo infoKbdInt;
+
+ infoKbdInt.url.setProtocol("sftp");
+ infoKbdInt.url.setHost(mHost);
+ if (mPort > 0 && mPort != DEFAULT_SFTP_PORT) {
+ infoKbdInt.url.setPort(mPort);
+ }
+
+ if (!name.isEmpty()) {
+ infoKbdInt.caption = QString(i18n("SFTP Login") + " - " + name);
+ } else {
+ infoKbdInt.caption = i18n("SFTP Login");
+ }
+
+ infoKbdInt.comment = "sftp://" + mUsername + "@" + mHost;
+
+ QString newPrompt;
+ if (!instruction.isEmpty()) {
+ newPrompt = instruction + "<br /><br />";
+ }
+ newPrompt.append(prompt);
+ infoKbdInt.prompt = newPrompt;
+
+ infoKbdInt.readOnly = false;
+ infoKbdInt.keepPassword = false;
+
+ if (openPasswordDialog(infoKbdInt, i18n("Use the username input field to answer this question."))) {
+ kDebug(KIO_SFTP_DB) << "Got the answer from the password dialog";
+ answer = info.username.toUtf8().constData();
+ }
+
+ if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) {
+ kDebug(KIO_SFTP_DB) << "An error occurred setting the answer: "
+ << ssh_get_error(mSession);
+ return SSH_AUTH_ERROR;
+ }
+ break;
+ } else {
+ if (prompt.startsWith(QLatin1String("password:"), Qt::CaseInsensitive)) {
+ info.prompt = i18n("Please enter your password.");
+ } else {
+ info.prompt = prompt;
+ }
+ info.comment = info.url.url();
+ info.commentLabel = i18n("Site:");
+ info.setExtraField(QLatin1String("hide-username-line"), true);
+
+ if (openPasswordDialog(info)) {
+ kDebug(KIO_SFTP_DB) << "Got the answer from the password dialog";
+ answer = info.password.toUtf8().constData();
+ }
+
+ if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) {
+ kDebug(KIO_SFTP_DB) << "An error occurred setting the answer: "
+ << ssh_get_error(mSession);
+ return SSH_AUTH_ERROR;
+ }
+ }
+ }
+ err = ssh_userauth_kbdint(mSession, NULL, NULL);
+ }
- while (err == SSH_AUTH_INFO) {
- const QString name = QString::fromUtf8(ssh_userauth_kbdint_getname(mSession));
- const QString instruction = QString::fromUtf8(ssh_userauth_kbdint_getinstruction(mSession));
- const int n = ssh_userauth_kbdint_getnprompts(mSession);
+ return err;
+}
- kDebug(KIO_SFTP_DB) << "name=" << name << " instruction=" << instruction << " prompts=" << n;
+void sftpProtocol::reportError(const KUrl &url, const int err)
+{
+ kDebug(KIO_SFTP_DB) << "url = " << url << " - err=" << err;
- for (int i = 0; i < n; ++i) {
- char echo;
- const char *answer = "";
+ const int kioError = toKIOError(err);
+ if (kioError) {
+ error(kioError, url.prettyUrl());
+ }
+}
- const QString prompt = QString::fromUtf8(ssh_userauth_kbdint_getprompt(mSession, i, &echo));
- kDebug(KIO_SFTP_DB) << "prompt=" << prompt << " echo=" << QString::number(echo);
- if (echo) {
- // See RFC4256 Section 3.3 User Interface
- KIO::AuthInfo infoKbdInt;
+bool sftpProtocol::createUDSEntry(const QString &filename, const QByteArray &path,
+ UDSEntry &entry, short int details)
+{
+ mode_t type;
+ mode_t access;
+ char *link;
- infoKbdInt.url.setProtocol("sftp");
- infoKbdInt.url.setHost(mHost);
- if (mPort > 0 && mPort != DEFAULT_SFTP_PORT) {
- infoKbdInt.url.setPort(mPort);
- }
+ Q_ASSERT(entry.count() == 0);
- if (!name.isEmpty()) {
- infoKbdInt.caption = QString(i18n("SFTP Login") + " - " + name);
- } else {
- infoKbdInt.caption = i18n("SFTP Login");
- }
+ sftp_attributes sb = sftp_lstat(mSftp, path.constData());
+ if (sb == NULL) {
+ return false;
+ }
- infoKbdInt.comment = "sftp://" + mUsername + "@" + mHost;
+ entry.insert(KIO::UDSEntry::UDS_NAME, filename);
- QString newPrompt;
- if (!instruction.isEmpty()) {
- newPrompt = instruction + "<br /><br />";
+ if (sb->type == SSH_FILEXFER_TYPE_SYMLINK) {
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
+ link = sftp_readlink(mSftp, path.constData());
+ if (link == NULL) {
+ sftp_attributes_free(sb);
+ return false;
+ }
+ entry.insert(KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName(link));
+ delete link;
+ // A symlink -> follow it only if details > 1
+ if (details > 1) {
+ sftp_attributes sb2 = sftp_stat(mSftp, path.constData());
+ if (sb2 == NULL) {
+ // It is a link pointing to nowhere
+ type = S_IFMT - 1;
+ access = S_IRWXU | S_IRWXG | S_IRWXO;
+ entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type);
+ entry.insert( KIO::UDSEntry::UDS_ACCESS, access);
+ entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
+
+ goto notype;
+ }
+ sftp_attributes_free(sb);
+ sb = sb2;
}
- newPrompt.append(prompt);
- infoKbdInt.prompt = newPrompt;
+ }
- infoKbdInt.readOnly = false;
- infoKbdInt.keepPassword = false;
+ switch (sb->type) {
+ case SSH_FILEXFER_TYPE_REGULAR:
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
+ break;
+ case SSH_FILEXFER_TYPE_DIRECTORY:
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
+ break;
+ case SSH_FILEXFER_TYPE_SYMLINK:
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFLNK);
+ break;
+ case SSH_FILEXFER_TYPE_SPECIAL:
+ case SSH_FILEXFER_TYPE_UNKNOWN:
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFMT - 1);
+ break;
+ }
- if (openPasswordDialog(infoKbdInt, i18n("Use the username input field to answer this question."))) {
- kDebug(KIO_SFTP_DB) << "Got the answer from the password dialog";
- answer = info.username.toUtf8().constData();
- }
+ access = sb->permissions & 07777;
+ entry.insert(KIO::UDSEntry::UDS_ACCESS, access);
- if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) {
- kDebug(KIO_SFTP_DB) << "An error occurred setting the answer: "
- << ssh_get_error(mSession);
- return SSH_AUTH_ERROR;
- }
- break;
- } else {
- if (prompt.startsWith(QLatin1String("password:"), Qt::CaseInsensitive)) {
- info.prompt = i18n("Please enter your password.");
+ entry.insert(KIO::UDSEntry::UDS_SIZE, sb->size);
+
+notype:
+ if (details > 0) {
+ if (sb->owner) {
+ entry.insert(KIO::UDSEntry::UDS_USER, QString::fromUtf8(sb->owner));
} else {
- info.prompt = prompt;
+ entry.insert(KIO::UDSEntry::UDS_USER, QString::number(sb->uid));
}
- info.comment = info.url.url();
- info.commentLabel = i18n("Site:");
- info.setExtraField(QLatin1String("hide-username-line"), true);
- if (openPasswordDialog(info)) {
- kDebug(KIO_SFTP_DB) << "Got the answer from the password dialog";
- answer = info.password.toUtf8().constData();
+ if (sb->group) {
+ entry.insert(KIO::UDSEntry::UDS_GROUP, QString::fromUtf8(sb->group));
+ } else {
+ entry.insert(KIO::UDSEntry::UDS_GROUP, QString::number(sb->gid));
}
- if (ssh_userauth_kbdint_setanswer(mSession, i, answer) < 0) {
- kDebug(KIO_SFTP_DB) << "An error occurred setting the answer: "
- << ssh_get_error(mSession);
- return SSH_AUTH_ERROR;
- }
- }
+ entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, sb->atime);
+ entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, sb->mtime);
+ entry.insert(KIO::UDSEntry::UDS_CREATION_TIME, sb->createtime);
}
- err = ssh_userauth_kbdint(mSession, NULL, NULL);
- }
-
- return err;
-}
-void sftpProtocol::reportError(const KUrl &url, const int err) {
- kDebug(KIO_SFTP_DB) << "url = " << url << " - err=" << err;
+ sftp_attributes_free(sb);
- const int kioError = toKIOError(err);
- if (kioError)
- error(kioError, url.prettyUrl());
+ return true;
}
-bool sftpProtocol::createUDSEntry(const QString &filename, const QByteArray &path,
- UDSEntry &entry, short int details) {
- mode_t type;
- mode_t access;
- char *link;
-
- Q_ASSERT(entry.count() == 0);
-
- sftp_attributes sb = sftp_lstat(mSftp, path.constData());
- if (sb == NULL) {
- return false;
- }
-
- entry.insert(KIO::UDSEntry::UDS_NAME, filename);
-
- if (sb->type == SSH_FILEXFER_TYPE_SYMLINK) {
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
- link = sftp_readlink(mSftp, path.constData());
- if (link == NULL) {
- sftp_attributes_free(sb);
- return false;
- }
- entry.insert(KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName(link));
- delete link;
- // A symlink -> follow it only if details > 1
- if (details > 1) {
- sftp_attributes sb2 = sftp_stat(mSftp, path.constData());
- if (sb2 == NULL) {
- // It is a link pointing to nowhere
- type = S_IFMT - 1;
- access = S_IRWXU | S_IRWXG | S_IRWXO;
- entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type);
- entry.insert( KIO::UDSEntry::UDS_ACCESS, access);
- entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
-
- goto notype;
- }
- sftp_attributes_free(sb);
- sb = sb2;
- }
- }
-
- switch (sb->type) {
- case SSH_FILEXFER_TYPE_REGULAR:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
- break;
- case SSH_FILEXFER_TYPE_DIRECTORY:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
- break;
- case SSH_FILEXFER_TYPE_SYMLINK:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFLNK);
- break;
- case SSH_FILEXFER_TYPE_SPECIAL:
- case SSH_FILEXFER_TYPE_UNKNOWN:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFMT - 1);
- break;
- }
-
- access = sb->permissions & 07777;
- entry.insert(KIO::UDSEntry::UDS_ACCESS, access);
-
- entry.insert(KIO::UDSEntry::UDS_SIZE, sb->size);
+QString sftpProtocol::canonicalizePath(const QString &path)
+{
+ kDebug(KIO_SFTP_DB) << "Path to canonicalize: " << path;
+ QString cPath;
+ char *sPath = NULL;
-notype:
- if (details > 0) {
- if (sb->owner) {
- entry.insert(KIO::UDSEntry::UDS_USER, QString::fromUtf8(sb->owner));
- } else {
- entry.insert(KIO::UDSEntry::UDS_USER, QString::number(sb->uid));
+ if (path.isEmpty()) {
+ return cPath;
}
- if (sb->group) {
- entry.insert(KIO::UDSEntry::UDS_GROUP, QString::fromUtf8(sb->group));
- } else {
- entry.insert(KIO::UDSEntry::UDS_GROUP, QString::number(sb->gid));
+ sPath = sftp_canonicalize_path(mSftp, path.toUtf8().constData());
+ if (sPath == NULL) {
+ kDebug(KIO_SFTP_DB) << "Could not canonicalize path: " << path;
+ return cPath;
}
- entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, sb->atime);
- entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, sb->mtime);
- entry.insert(KIO::UDSEntry::UDS_CREATION_TIME, sb->createtime);
- }
-
- sftp_attributes_free(sb);
-
- return true;
-}
-
-QString sftpProtocol::canonicalizePath(const QString &path) {
- kDebug(KIO_SFTP_DB) << "Path to canonicalize: " << path;
- QString cPath;
- char *sPath = NULL;
+ cPath = QFile::decodeName(sPath);
+ delete sPath;
- if (path.isEmpty()) {
- return cPath;
- }
+ kDebug(KIO_SFTP_DB) << "Canonicalized path: " << cPath;
- sPath = sftp_canonicalize_path(mSftp, path.toUtf8().constData());
- if (sPath == NULL) {
- kDebug(KIO_SFTP_DB) << "Could not canonicalize path: " << path;
return cPath;
- }
-
- cPath = QFile::decodeName(sPath);
- delete sPath;
-
- kDebug(KIO_SFTP_DB) << "Canonicalized path: " << cPath;
-
- return cPath;
}
sftpProtocol::sftpProtocol(const QByteArray &pool_socket, const QByteArray &app_socket)
- : SlaveBase("kio_sftp", pool_socket, app_socket),
- mConnected(false), mPort(-1), mSession(NULL), mSftp(NULL), mPublicKeyAuthInfo(0) {
- kDebug(KIO_SFTP_DB) << "pid = " << getpid();
+ : SlaveBase("kio_sftp", pool_socket, app_socket),
+ mConnected(false), mPort(-1), mSession(NULL), mSftp(NULL), mPublicKeyAuthInfo(0)
+{
+ kDebug(KIO_SFTP_DB) << "pid = " << getpid();
- kDebug(KIO_SFTP_DB) << "debug = " << getenv("KIO_SFTP_LOG_VERBOSITY");
+ kDebug(KIO_SFTP_DB) << "debug = " << getenv("KIO_SFTP_LOG_VERBOSITY");
- mCallbacks = (ssh_callbacks) malloc(sizeof(struct ssh_callbacks_struct));
- if (mCallbacks == NULL) {
- error(KIO::ERR_OUT_OF_MEMORY, i18n("Could not allocate callbacks"));
- return;
- }
- ZERO_STRUCTP(mCallbacks);
+ mCallbacks = (ssh_callbacks) malloc(sizeof(struct ssh_callbacks_struct));
+ if (mCallbacks == NULL) {
+ error(KIO::ERR_OUT_OF_MEMORY, i18n("Could not allocate callbacks"));
+ return;
+ }
+ ZERO_STRUCTP(mCallbacks);
- mCallbacks->userdata = this;
- mCallbacks->auth_function = ::auth_callback;
+ mCallbacks->userdata = this;
+ mCallbacks->auth_function = ::auth_callback;
- ssh_callbacks_init(mCallbacks);
+ ssh_callbacks_init(mCallbacks);
- char *verbosity = getenv("KIO_SFTP_LOG_VERBOSITY");
- if (verbosity != NULL) {
- int level = atoi(verbosity);
- int rc;
+ char *verbosity = getenv("KIO_SFTP_LOG_VERBOSITY");
+ if (verbosity != NULL) {
+ int level = atoi(verbosity);
+ int rc;
- rc = ssh_set_log_level(level);
- if (rc != SSH_OK) {
- error(KIO::ERR_INTERNAL, i18n("Could not set log verbosity."));
- return;
- }
+ rc = ssh_set_log_level(level);
+ if (rc != SSH_OK) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set log verbosity."));
+ return;
+ }
- rc = ssh_set_log_userdata(this);
- if (rc != SSH_OK) {
- error(KIO::ERR_INTERNAL, i18n("Could not set log userdata."));
- return;
- }
+ rc = ssh_set_log_userdata(this);
+ if (rc != SSH_OK) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set log userdata."));
+ return;
+ }
- rc = ssh_set_log_callback(::log_callback);
- if (rc != SSH_OK) {
- error(KIO::ERR_INTERNAL, i18n("Could not set log callback."));
- return;
+ rc = ssh_set_log_callback(::log_callback);
+ if (rc != SSH_OK) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set log callback."));
+ return;
+ }
}
- }
-
}
-sftpProtocol::~sftpProtocol() {
- kDebug(KIO_SFTP_DB) << "pid = " << getpid();
- closeConnection();
+sftpProtocol::~sftpProtocol()
+{
+ kDebug(KIO_SFTP_DB) << "pid = " << getpid();
+ closeConnection();
- delete mCallbacks;
- delete mPublicKeyAuthInfo; // for precaution
+ delete mCallbacks;
+ delete mPublicKeyAuthInfo; // for precaution
- /* cleanup and shut down cryto stuff */
- ssh_finalize();
+ /* cleanup and shut down cryto stuff */
+ ssh_finalize();
}
-void sftpProtocol::setHost(const QString& host, quint16 port, const QString& user, const QString& pass) {
- kDebug(KIO_SFTP_DB) << user << "@" << host << ":" << port;
+void sftpProtocol::setHost(const QString& host, quint16 port, const QString& user, const QString& pass)
+{
+ kDebug(KIO_SFTP_DB) << user << "@" << host << ":" << port;
- // Close connection if the request is to another server...
- if (host != mHost || port != mPort ||
- user != mUsername || pass != mPassword) {
- closeConnection();
- }
+ // Close connection if the request is to another server...
+ if (host != mHost || port != mPort ||
+ user != mUsername || pass != mPassword) {
+ closeConnection();
+ }
- mHost = host;
- mPort = port;
- mUsername = user;
- mPassword = pass;
+ mHost = host;
+ mPort = port;
+ mUsername = user;
+ mPassword = pass;
}
bool sftpProtocol::sftpOpenConnection (const AuthInfo& info)
{
- mSession = ssh_new();
- if (mSession == NULL) {
- error(KIO::ERR_OUT_OF_MEMORY, i18n("Could not create a new SSH session."));
- return false;
- }
-
- long timeout_sec = 30, timeout_usec = 0;
-
- kDebug(KIO_SFTP_DB) << "Creating the SSH session and setting options";
+ mSession = ssh_new();
+ if (mSession == NULL) {
+ error(KIO::ERR_OUT_OF_MEMORY, i18n("Could not create a new SSH session."));
+ return false;
+ }
- // Set timeout
- int rc = ssh_options_set(mSession, SSH_OPTIONS_TIMEOUT, &timeout_sec);
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set a timeout."));
- return false;
- }
- rc = ssh_options_set(mSession, SSH_OPTIONS_TIMEOUT_USEC, &timeout_usec);
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set a timeout."));
- return false;
- }
+ long timeout_sec = 30, timeout_usec = 0;
- // Don't use any compression
- rc = ssh_options_set(mSession, SSH_OPTIONS_COMPRESSION_C_S, "none");
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set compression."));
- return false;
- }
+ kDebug(KIO_SFTP_DB) << "Creating the SSH session and setting options";
- rc = ssh_options_set(mSession, SSH_OPTIONS_COMPRESSION_S_C, "none");
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set compression."));
- return false;
- }
+ // Set timeout
+ int rc = ssh_options_set(mSession, SSH_OPTIONS_TIMEOUT, &timeout_sec);
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set a timeout."));
+ return false;
+ }
+ rc = ssh_options_set(mSession, SSH_OPTIONS_TIMEOUT_USEC, &timeout_usec);
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set a timeout."));
+ return false;
+ }
- // Set host and port
- rc = ssh_options_set(mSession, SSH_OPTIONS_HOST, mHost.toUtf8().constData());
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set host."));
- return false;
- }
+ // Don't use any compression
+ rc = ssh_options_set(mSession, SSH_OPTIONS_COMPRESSION_C_S, "none");
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set compression."));
+ return false;
+ }
- if (mPort > 0) {
- rc = ssh_options_set(mSession, SSH_OPTIONS_PORT, &mPort);
+ rc = ssh_options_set(mSession, SSH_OPTIONS_COMPRESSION_S_C, "none");
if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set port."));
- return false;
+ error(KIO::ERR_INTERNAL, i18n("Could not set compression."));
+ return false;
}
- }
- // Set the username
- if (!info.username.isEmpty()) {
- rc = ssh_options_set(mSession, SSH_OPTIONS_USER, info.username.toUtf8().constData());
+ // Set host and port
+ rc = ssh_options_set(mSession, SSH_OPTIONS_HOST, mHost.toUtf8().constData());
if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not set username."));
- return false;
+ error(KIO::ERR_INTERNAL, i18n("Could not set host."));
+ return false;
}
- }
- // Read ~/.ssh/config
- rc = ssh_options_parse_config(mSession, NULL);
- if (rc < 0) {
- error(KIO::ERR_INTERNAL, i18n("Could not parse the config file."));
- return false;
- }
+ if (mPort > 0) {
+ rc = ssh_options_set(mSession, SSH_OPTIONS_PORT, &mPort);
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set port."));
+ return false;
+ }
+ }
- ssh_set_callbacks(mSession, mCallbacks);
+ // Set the username
+ if (!info.username.isEmpty()) {
+ rc = ssh_options_set(mSession, SSH_OPTIONS_USER, info.username.toUtf8().constData());
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not set username."));
+ return false;
+ }
+ }
+
+ // Read ~/.ssh/config
+ rc = ssh_options_parse_config(mSession, NULL);
+ if (rc < 0) {
+ error(KIO::ERR_INTERNAL, i18n("Could not parse the config file."));
+ return false;
+ }
- kDebug(KIO_SFTP_DB) << "Trying to connect to the SSH server";
+ ssh_set_callbacks(mSession, mCallbacks);
- /* try to connect */
- rc = ssh_connect(mSession);
- if (rc < 0) {
- error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
- closeConnection();
- return false;
- }
+ kDebug(KIO_SFTP_DB) << "Trying to connect to the SSH server";
- return true;
-}
+ /* try to connect */
+ rc = ssh_connect(mSession);
+ if (rc < 0) {
+ error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
+ closeConnection();
+ return false;
+ }
+ return true;
+}
-void sftpProtocol::openConnection() {
- if (mConnected) {
- return;
- }
+void sftpProtocol::openConnection()
+{
+ if (mConnected) {
+ return;
+ }
- const int effectivePort = mPort > 0 ? mPort : DEFAULT_SFTP_PORT;
+ const int effectivePort = mPort > 0 ? mPort : DEFAULT_SFTP_PORT;
- kDebug(KIO_SFTP_DB) << "username=" << mUsername << ", host=" << mHost << ", port=" << effectivePort;
+ kDebug(KIO_SFTP_DB) << "username=" << mUsername << ", host=" << mHost << ", port=" << effectivePort;
- infoMessage(i18n("Opening SFTP connection to host %1:<numid>%2</numid>", mHost, effectivePort));
+ infoMessage(i18n("Opening SFTP connection to host %1:<numid>%2</numid>", mHost, effectivePort));
- if (mHost.isEmpty()) {
- kDebug(KIO_SFTP_DB) << "openConnection(): Need hostname...";
- error(KIO::ERR_UNKNOWN_HOST, QString());
- return;
- }
+ if (mHost.isEmpty()) {
+ kDebug(KIO_SFTP_DB) << "openConnection(): Need hostname...";
+ error(KIO::ERR_UNKNOWN_HOST, QString());
+ return;
+ }
- AuthInfo info;
- info.url.setProtocol("sftp");
- info.url.setHost(mHost);
- if ( mPort > 0 && mPort != DEFAULT_SFTP_PORT ) {
- info.url.setPort(mPort);
- }
- info.url.setUser(mUsername);
- info.username = mUsername;
-
- // Check for cached authentication info if no password is specified...
- if (mPassword.isEmpty()) {
- kDebug(KIO_SFTP_DB) << "checking cache: info.username =" << info.username
- << ", info.url =" << info.url.prettyUrl();
- checkCachedAuthentication(info);
- } else {
- info.password = mPassword;
- }
+ AuthInfo info;
+ info.url.setProtocol("sftp");
+ info.url.setHost(mHost);
+ if ( mPort > 0 && mPort != DEFAULT_SFTP_PORT ) {
+ info.url.setPort(mPort);
+ }
+ info.url.setUser(mUsername);
+ info.username = mUsername;
- // Start the ssh connection.
- QString msg; // msg for dialog box
- QString caption; // dialog box caption
- unsigned char *hash = NULL; // the server hash
- ssh_key srv_pubkey;
- char *hexa;
- size_t hlen;
- int rc, state;
-
- // Attempt to start a ssh session and establish a connection with the server.
- if (!sftpOpenConnection(info)) {
- return;
- }
+ // Check for cached authentication info if no password is specified...
+ if (mPassword.isEmpty()) {
+ kDebug(KIO_SFTP_DB) << "checking cache: info.username =" << info.username
+ << ", info.url =" << info.url.prettyUrl();
+ checkCachedAuthentication(info);
+ } else {
+ info.password = mPassword;
+ }
- kDebug(KIO_SFTP_DB) << "Getting the SSH server hash";
+ // Start the ssh connection.
+ QString msg; // msg for dialog box
+ QString caption; // dialog box caption
+ unsigned char *hash = NULL; // the server hash
+ ssh_key srv_pubkey;
+ char *hexa;
+ size_t hlen;
+ int rc, state;
- /* get the hash */
- rc = ssh_get_publickey(mSession, &srv_pubkey);
- if (rc < 0) {
- error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
- closeConnection();
- return;
- }
+ // Attempt to start a ssh session and establish a connection with the server.
+ if (!sftpOpenConnection(info)) {
+ return;
+ }
- rc = ssh_get_publickey_hash(srv_pubkey,
- SSH_PUBLICKEY_HASH_SHA1,
- &hash,
- &hlen);
- ssh_key_free(srv_pubkey);
- if (rc < 0) {
- error(KIO::ERR_SLAVE_DEFINED,
- i18n("Could not create hash from server public key"));
- closeConnection();
- return;
- }
+ kDebug(KIO_SFTP_DB) << "Getting the SSH server hash";
- kDebug(KIO_SFTP_DB) << "Checking if the SSH server is known";
-
- /* check the server public key hash */
- state = ssh_is_server_known(mSession);
- switch (state) {
- case SSH_SERVER_KNOWN_OK:
- break;
- case SSH_SERVER_FOUND_OTHER:
- ssh_string_free_char((char *)hash);
- error(KIO::ERR_SLAVE_DEFINED, i18n("The host key for this server was "
- "not found, but another type of key exists.\n"
- "An attacker might change the default server key to confuse your "
- "client into thinking the key does not exist.\n"
- "Please contact your system administrator.\n%1", QString::fromUtf8(ssh_get_error(mSession))));
- closeConnection();
- return;
- case SSH_SERVER_KNOWN_CHANGED:
- hexa = ssh_get_hexa(hash, hlen);
- ssh_string_free_char((char *)hash);
- /* TODO print known_hosts file, port? */
- error(KIO::ERR_SLAVE_DEFINED, i18n("The host key for the server %1 has changed.\n"
- "This could either mean that DNS SPOOFING is happening or the IP "
- "address for the host and its host key have changed at the same time.\n"
- "The fingerprint for the key sent by the remote host is:\n %2\n"
- "Please contact your system administrator.\n%3",
- mHost, QString::fromUtf8(hexa), QString::fromUtf8(ssh_get_error(mSession))));
- ssh_string_free_char(hexa);
- closeConnection();
- return;
- case SSH_SERVER_FILE_NOT_FOUND:
- case SSH_SERVER_NOT_KNOWN:
- hexa = ssh_get_hexa(hash, hlen);
- ssh_string_free_char((char *)hash);
- caption = i18n("Warning: Cannot verify host's identity.");
- msg = i18n("The authenticity of host %1 cannot be established.\n"
- "The key fingerprint is: %2\n"
- "Are you sure you want to continue connecting?", mHost, hexa);
- ssh_string_free_char(hexa);
-
- if (KMessageBox::Yes != messageBox(WarningYesNo, msg, caption)) {
+ /* get the hash */
+ rc = ssh_get_publickey(mSession, &srv_pubkey);
+ if (rc < 0) {
+ error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
closeConnection();
- error(KIO::ERR_USER_CANCELED, QString());
return;
- }
+ }
- /* write the known_hosts file */
- kDebug(KIO_SFTP_DB) << "Adding server to known_hosts file.";
- if (ssh_write_knownhost(mSession) < 0) {
- error(KIO::ERR_USER_CANCELED, QString::fromUtf8(ssh_get_error(mSession)));
+ rc = ssh_get_publickey_hash(srv_pubkey,
+ SSH_PUBLICKEY_HASH_SHA1,
+ &hash,
+ &hlen);
+ ssh_key_free(srv_pubkey);
+ if (rc < 0) {
+ error(KIO::ERR_SLAVE_DEFINED,
+ i18n("Could not create hash from server public key"));
closeConnection();
return;
- }
- break;
- case SSH_SERVER_ERROR:
- ssh_string_free_char((char *)hash);
- error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
- return;
- }
+ }
- kDebug(KIO_SFTP_DB) << "Trying to authenticate with the server";
+ kDebug(KIO_SFTP_DB) << "Checking if the SSH server is known";
- // Try to login without authentication
- rc = ssh_userauth_none(mSession, NULL);
- if (rc == SSH_AUTH_ERROR) {
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
- }
+ /* check the server public key hash */
+ state = ssh_is_server_known(mSession);
+ switch (state) {
+ case SSH_SERVER_KNOWN_OK: {
+ break;
+ }
+ case SSH_SERVER_FOUND_OTHER: {
+ ssh_string_free_char((char *)hash);
+ error(KIO::ERR_SLAVE_DEFINED, i18n("The host key for this server was "
+ "not found, but another type of key exists.\n"
+ "An attacker might change the default server key to confuse your "
+ "client into thinking the key does not exist.\n"
+ "Please contact your system administrator.\n%1", QString::fromUtf8(ssh_get_error(mSession))));
+ closeConnection();
+ return;
+ }
+ case SSH_SERVER_KNOWN_CHANGED: {
+ hexa = ssh_get_hexa(hash, hlen);
+ ssh_string_free_char((char *)hash);
+ /* TODO print known_hosts file, port? */
+ error(KIO::ERR_SLAVE_DEFINED, i18n("The host key for the server %1 has changed.\n"
+ "This could either mean that DNS SPOOFING is happening or the IP "
+ "address for the host and its host key have changed at the same time.\n"
+ "The fingerprint for the key sent by the remote host is:\n %2\n"
+ "Please contact your system administrator.\n%3",
+ mHost, QString::fromUtf8(hexa), QString::fromUtf8(ssh_get_error(mSession))));
+ ssh_string_free_char(hexa);
+ closeConnection();
+ return;
+ }
+ case SSH_SERVER_FILE_NOT_FOUND:
+ case SSH_SERVER_NOT_KNOWN: {
+ hexa = ssh_get_hexa(hash, hlen);
+ ssh_string_free_char((char *)hash);
+ caption = i18n("Warning: Cannot verify host's identity.");
+ msg = i18n("The authenticity of host %1 cannot be established.\n"
+ "The key fingerprint is: %2\n"
+ "Are you sure you want to continue connecting?", mHost, hexa);
+ ssh_string_free_char(hexa);
+
+ if (KMessageBox::Yes != messageBox(WarningYesNo, msg, caption)) {
+ closeConnection();
+ error(KIO::ERR_USER_CANCELED, QString());
+ return;
+ }
- // This NEEDS to be called after ssh_userauth_none() !!!
- int method = ssh_auth_list(mSession);
- if (rc != SSH_AUTH_SUCCESS && method == 0) {
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed. The server "
- "didn't send any authentication methods"));
- return;
- }
+ /* write the known_hosts file */
+ kDebug(KIO_SFTP_DB) << "Adding server to known_hosts file.";
+ if (ssh_write_knownhost(mSession) < 0) {
+ error(KIO::ERR_USER_CANCELED, QString::fromUtf8(ssh_get_error(mSession)));
+ closeConnection();
+ return;
+ }
+ break;
+ }
+ case SSH_SERVER_ERROR: {
+ ssh_string_free_char((char *)hash);
+ error(KIO::ERR_SLAVE_DEFINED, QString::fromUtf8(ssh_get_error(mSession)));
+ return;
+ }
+ }
+
+ kDebug(KIO_SFTP_DB) << "Trying to authenticate with the server";
- // Try to authenticate with public key first
- if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_PUBLICKEY)) {
- kDebug(KIO_SFTP_DB) << "Trying to authenticate with public key";
- for(;;) {
- rc = ssh_userauth_publickey_auto(mSession, NULL, NULL);
- if (rc == SSH_AUTH_ERROR) {
- kDebug(KIO_SFTP_DB) << "Public key authentication failed:" <<
- QString::fromUtf8(ssh_get_error(mSession));
+ // Try to login without authentication
+ rc = ssh_userauth_none(mSession, NULL);
+ if (rc == SSH_AUTH_ERROR) {
closeConnection();
- clearPubKeyAuthInfo();
error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
return;
- } else if (rc != SSH_AUTH_DENIED || !mPublicKeyAuthInfo || !mPublicKeyAuthInfo->isModified()) {
- clearPubKeyAuthInfo();
- break;
- }
}
- }
- // Try to authenticate with GSSAPI
- if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_GSSAPI_MIC)) {
- kDebug(KIO_SFTP_DB) << "Trying to authenticate with GSSAPI";
- rc = ssh_userauth_gssapi(mSession);
- if (rc == SSH_AUTH_ERROR) {
- kDebug(KIO_SFTP_DB) << "Public key authentication failed:" <<
- QString::fromUtf8(ssh_get_error(mSession));
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
- }
- }
-
- // Try to authenticate with keyboard interactive
- if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_INTERACTIVE)) {
- kDebug(KIO_SFTP_DB) << "Trying to authenticate with keyboard interactive";
- AuthInfo info2 (info);
- rc = authenticateKeyboardInteractive(info2);
- if (rc == SSH_AUTH_SUCCESS) {
- info = info2;
- } else if (rc == SSH_AUTH_ERROR) {
- kDebug(KIO_SFTP_DB) << "Keyboard interactive authentication failed:"
- << QString::fromUtf8(ssh_get_error(mSession));
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
+ // This NEEDS to be called after ssh_userauth_none() !!!
+ int method = ssh_auth_list(mSession);
+ if (rc != SSH_AUTH_SUCCESS && method == 0) {
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed. The server "
+ "didn't send any authentication methods"));
+ return;
}
- }
- // Try to authenticate with password
- if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_PASSWORD)) {
- kDebug(KIO_SFTP_DB) << "Trying to authenticate with password";
-
- info.caption = i18n("SFTP Login");
- info.prompt = i18n("Please enter your username and password.");
- info.comment = info.url.url();
- info.commentLabel = i18n("Site:");
- bool isFirstLoginAttempt = true;
-
- for(;;) {
- if (!isFirstLoginAttempt || info.password.isEmpty()) {
- info.keepPassword = true; // make the "keep Password" check box visible to the user.
- info.setModified(false);
-
- QString username (info.username);
- const QString errMsg(isFirstLoginAttempt ? QString() : i18n("Incorrect username or password"));
-
- kDebug(KIO_SFTP_DB) << "Username:" << username << "first attempt?"
- << isFirstLoginAttempt << "error:" << errMsg;
-
- // Handle user canceled or dialog failed to open...
- if (!openPasswordDialog(info, errMsg)) {
- kDebug(KIO_SFTP_DB) << "User canceled password/retry dialog";
- closeConnection();
- error(KIO::ERR_USER_CANCELED, QString());
- return;
- }
-
- // If the user name changes, we have to restablish connection again
- // since the user name must always be set before calling ssh_connect.
- if (wasUsernameChanged(username, info)) {
- kDebug(KIO_SFTP_DB) << "Username changed to" << info.username;
- if (!info.url.user().isEmpty()) {
- info.url.setUser(info.username);
- }
- closeConnection();
- if (!sftpOpenConnection(info)) {
- return;
- }
+ // Try to authenticate with public key first
+ if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_PUBLICKEY)) {
+ kDebug(KIO_SFTP_DB) << "Trying to authenticate with public key";
+ for(;;) {
+ rc = ssh_userauth_publickey_auto(mSession, NULL, NULL);
+ if (rc == SSH_AUTH_ERROR) {
+ kDebug(KIO_SFTP_DB) << "Public key authentication failed:" <<
+ QString::fromUtf8(ssh_get_error(mSession));
+ closeConnection();
+ clearPubKeyAuthInfo();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
+ return;
+ } else if (rc != SSH_AUTH_DENIED || !mPublicKeyAuthInfo || !mPublicKeyAuthInfo->isModified()) {
+ clearPubKeyAuthInfo();
+ break;
+ }
}
- }
+ }
- rc = ssh_userauth_password(mSession, info.username.toUtf8().constData(), info.password.toUtf8().constData());
- if (rc == SSH_AUTH_SUCCESS) {
- break;
- } else if (rc == SSH_AUTH_ERROR) {
- kDebug(KIO_SFTP_DB) << "Password authentication failed:"
- << QString::fromUtf8(ssh_get_error(mSession));
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
- }
+ // Try to authenticate with GSSAPI
+ if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_GSSAPI_MIC)) {
+ kDebug(KIO_SFTP_DB) << "Trying to authenticate with GSSAPI";
+ rc = ssh_userauth_gssapi(mSession);
+ if (rc == SSH_AUTH_ERROR) {
+ kDebug(KIO_SFTP_DB) << "Public key authentication failed:" <<
+ QString::fromUtf8(ssh_get_error(mSession));
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
+ return;
+ }
+ }
- isFirstLoginAttempt = false; // failed attempt to login.
- info.password.clear(); // clear the password after failed attempts.
+ // Try to authenticate with keyboard interactive
+ if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_INTERACTIVE)) {
+ kDebug(KIO_SFTP_DB) << "Trying to authenticate with keyboard interactive";
+ AuthInfo info2 (info);
+ rc = authenticateKeyboardInteractive(info2);
+ if (rc == SSH_AUTH_SUCCESS) {
+ info = info2;
+ } else if (rc == SSH_AUTH_ERROR) {
+ kDebug(KIO_SFTP_DB) << "Keyboard interactive authentication failed:"
+ << QString::fromUtf8(ssh_get_error(mSession));
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
+ return;
+ }
}
- }
- // If we're still not authenticated then we need to leave.
- if (rc != SSH_AUTH_SUCCESS) {
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
- }
+ // Try to authenticate with password
+ if (rc != SSH_AUTH_SUCCESS && (method & SSH_AUTH_METHOD_PASSWORD)) {
+ kDebug(KIO_SFTP_DB) << "Trying to authenticate with password";
- // start sftp session
- kDebug(KIO_SFTP_DB) << "Trying to request the sftp session";
- mSftp = sftp_new(mSession);
- if (mSftp == NULL) {
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Unable to request the SFTP subsystem. "
- "Make sure SFTP is enabled on the server."));
- return;
- }
+ info.caption = i18n("SFTP Login");
+ info.prompt = i18n("Please enter your username and password.");
+ info.comment = info.url.url();
+ info.commentLabel = i18n("Site:");
+ bool isFirstLoginAttempt = true;
- kDebug(KIO_SFTP_DB) << "Trying to initialize the sftp session";
- if (sftp_init(mSftp) < 0) {
- closeConnection();
- error(KIO::ERR_COULD_NOT_LOGIN, i18n("Could not initialize the SFTP session."));
- return;
- }
+ for(;;) {
+ if (!isFirstLoginAttempt || info.password.isEmpty()) {
+ info.keepPassword = true; // make the "keep Password" check box visible to the user.
+ info.setModified(false);
- // Login succeeded!
- infoMessage(i18n("Successfully connected to %1", mHost));
- if (info.keepPassword) {
- kDebug(KIO_SFTP_DB) << "Caching info.username = " << info.username
- << ", info.url = " << info.url.prettyUrl();
- cacheAuthentication(info);
- }
+ QString username (info.username);
+ const QString errMsg(isFirstLoginAttempt ? QString() : i18n("Incorrect username or password"));
- // Update the original username in case it was changed!
- if (!mUsername.isEmpty()) {
- mUsername = info.username;
- }
+ kDebug(KIO_SFTP_DB) << "Username:" << username << "first attempt?"
+ << isFirstLoginAttempt << "error:" << errMsg;
- setTimeoutSpecialCommand(KIO_SFTP_SPECIAL_TIMEOUT);
+ // Handle user canceled or dialog failed to open...
+ if (!openPasswordDialog(info, errMsg)) {
+ kDebug(KIO_SFTP_DB) << "User canceled password/retry dialog";
+ closeConnection();
+ error(KIO::ERR_USER_CANCELED, QString());
+ return;
+ }
- mConnected = true;
- connected();
+ // If the user name changes, we have to restablish connection again
+ // since the user name must always be set before calling ssh_connect.
+ if (wasUsernameChanged(username, info)) {
+ kDebug(KIO_SFTP_DB) << "Username changed to" << info.username;
+ if (!info.url.user().isEmpty()) {
+ info.url.setUser(info.username);
+ }
+ closeConnection();
+ if (!sftpOpenConnection(info)) {
+ return;
+ }
+ }
+ }
- info.password.fill('x');
- info.password.clear();
-}
+ rc = ssh_userauth_password(mSession, info.username.toUtf8().constData(), info.password.toUtf8().constData());
+ if (rc == SSH_AUTH_SUCCESS) {
+ break;
+ } else if (rc == SSH_AUTH_ERROR) {
+ kDebug(KIO_SFTP_DB) << "Password authentication failed:"
+ << QString::fromUtf8(ssh_get_error(mSession));
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
+ return;
+ }
-void sftpProtocol::closeConnection() {
- kDebug(KIO_SFTP_DB);
+ isFirstLoginAttempt = false; // failed attempt to login.
+ info.password.clear(); // clear the password after failed attempts.
+ }
+ }
- if (mSftp) {
- sftp_free(mSftp);
- mSftp = NULL;
- }
+ // If we're still not authenticated then we need to leave.
+ if (rc != SSH_AUTH_SUCCESS) {
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
+ return;
+ }
- if (mSession) {
- ssh_disconnect(mSession);
- mSession = NULL;
- }
+ // start sftp session
+ kDebug(KIO_SFTP_DB) << "Trying to request the sftp session";
+ mSftp = sftp_new(mSession);
+ if (mSftp == NULL) {
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Unable to request the SFTP subsystem. "
+ "Make sure SFTP is enabled on the server."));
+ return;
+ }
- mConnected = false;
-}
+ kDebug(KIO_SFTP_DB) << "Trying to initialize the sftp session";
+ if (sftp_init(mSftp) < 0) {
+ closeConnection();
+ error(KIO::ERR_COULD_NOT_LOGIN, i18n("Could not initialize the SFTP session."));
+ return;
+ }
-void sftpProtocol::special(const QByteArray &) {
+ // Login succeeded!
+ infoMessage(i18n("Successfully connected to %1", mHost));
+ if (info.keepPassword) {
+ kDebug(KIO_SFTP_DB) << "Caching info.username = " << info.username
+ << ", info.url = " << info.url.prettyUrl();
+ cacheAuthentication(info);
+ }
+
+ // Update the original username in case it was changed!
+ if (!mUsername.isEmpty()) {
+ mUsername = info.username;
+ }
+
+ setTimeoutSpecialCommand(KIO_SFTP_SPECIAL_TIMEOUT);
+
+ mConnected = true;
+ connected();
+
+ info.password.fill('x');
+ info.password.clear();
+}
+
+void sftpProtocol::closeConnection()
+{
+ kDebug(KIO_SFTP_DB);
+
+ if (mSftp) {
+ sftp_free(mSftp);
+ mSftp = NULL;
+ }
+
+ if (mSession) {
+ ssh_disconnect(mSession);
+ mSession = NULL;
+ }
+
+ mConnected = false;
+}
+
+void sftpProtocol::special(const QByteArray &)
+{
int rc;
kDebug(KIO_SFTP_DB) << "special(): polling";
- if (!mSftp)
+ if (!mSftp) {
return;
+ }
/*
* channel_poll() returns the number of bytes that may be read on the
setTimeoutSpecialCommand(KIO_SFTP_SPECIAL_TIMEOUT);
}
-void sftpProtocol::open(const KUrl &url, QIODevice::OpenMode mode) {
- kDebug(KIO_SFTP_DB) << "open: " << url;
+void sftpProtocol::open(const KUrl &url, QIODevice::OpenMode mode)
+{
+ kDebug(KIO_SFTP_DB) << "open: " << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- const QString path = url.path();
- const QByteArray path_c = path.toUtf8();
+ const QString path = url.path();
+ const QByteArray path_c = path.toUtf8();
- sftp_attributes sb = sftp_lstat(mSftp, path_c.constData());
- if (sb == NULL) {
- reportError(url, sftp_get_error(mSftp));
- return;
- }
+ sftp_attributes sb = sftp_lstat(mSftp, path_c.constData());
+ if (sb == NULL) {
+ reportError(url, sftp_get_error(mSftp));
+ return;
+ }
- switch (sb->type) {
- case SSH_FILEXFER_TYPE_DIRECTORY:
- error(KIO::ERR_IS_DIRECTORY, url.prettyUrl());
- sftp_attributes_free(sb);
- return;
- case SSH_FILEXFER_TYPE_SPECIAL:
- case SSH_FILEXFER_TYPE_UNKNOWN:
- error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyUrl());
- sftp_attributes_free(sb);
- return;
- case SSH_FILEXFER_TYPE_SYMLINK:
- case SSH_FILEXFER_TYPE_REGULAR:
- break;
- }
+ switch (sb->type) {
+ case SSH_FILEXFER_TYPE_DIRECTORY: {
+ error(KIO::ERR_IS_DIRECTORY, url.prettyUrl());
+ sftp_attributes_free(sb);
+ return;
+ }
+ case SSH_FILEXFER_TYPE_SPECIAL:
+ case SSH_FILEXFER_TYPE_UNKNOWN: {
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, url.prettyUrl());
+ sftp_attributes_free(sb);
+ return;
+ }
+ case SSH_FILEXFER_TYPE_SYMLINK:
+ case SSH_FILEXFER_TYPE_REGULAR: {
+ break;
+ }
+ }
- KIO::filesize_t fileSize = sb->size;
- sftp_attributes_free(sb);
+ KIO::filesize_t fileSize = sb->size;
+ sftp_attributes_free(sb);
- int flags = 0;
+ int flags = 0;
- if (mode & QIODevice::ReadOnly) {
- if (mode & QIODevice::WriteOnly) {
- flags = O_RDWR | O_CREAT;
- } else {
- flags = O_RDONLY;
+ if (mode & QIODevice::ReadOnly) {
+ if (mode & QIODevice::WriteOnly) {
+ flags = O_RDWR | O_CREAT;
+ } else {
+ flags = O_RDONLY;
+ }
+ } else if (mode & QIODevice::WriteOnly) {
+ flags = O_WRONLY | O_CREAT;
}
- } else if (mode & QIODevice::WriteOnly) {
- flags = O_WRONLY | O_CREAT;
- }
- if (mode & QIODevice::Append) {
- flags |= O_APPEND;
- } else if (mode & QIODevice::Truncate) {
- flags |= O_TRUNC;
- }
-
- if (flags & O_CREAT) {
- mOpenFile = sftp_open(mSftp, path_c.constData(), flags, 0644);
- } else {
- mOpenFile = sftp_open(mSftp, path_c.constData(), flags, 0);
- }
+ if (mode & QIODevice::Append) {
+ flags |= O_APPEND;
+ } else if (mode & QIODevice::Truncate) {
+ flags |= O_TRUNC;
+ }
- if (mOpenFile == NULL) {
- error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
- return;
- }
+ if (flags & O_CREAT) {
+ mOpenFile = sftp_open(mSftp, path_c.constData(), flags, 0644);
+ } else {
+ mOpenFile = sftp_open(mSftp, path_c.constData(), flags, 0);
+ }
- // Determine the mimetype of the file to be retrieved, and emit it.
- // This is mandatory in all slaves (for KRun/BrowserRun to work).
- // If we're not opening the file ReadOnly or ReadWrite, don't attempt to
- // read the file and send the mimetype.
- if (mode & QIODevice::ReadOnly) {
- size_t bytesRequested = 1024;
- ssize_t bytesRead = 0;
- QVarLengthArray<char> buffer(bytesRequested);
+ if (mOpenFile == NULL) {
+ error(KIO::ERR_CANNOT_OPEN_FOR_READING, path);
+ return;
+ }
- bytesRead = sftp_read(mOpenFile, buffer.data(), bytesRequested);
- if (bytesRead < 0) {
- error(KIO::ERR_COULD_NOT_READ, mOpenUrl.prettyUrl());
- close();
- return;
- } else {
- QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead);
- KMimeType::Ptr p_mimeType = KMimeType::findByNameAndContent(mOpenUrl.fileName(), fileData);
- emit mimeType(p_mimeType->name());
+ // Determine the mimetype of the file to be retrieved, and emit it.
+ // This is mandatory in all slaves (for KRun/BrowserRun to work).
+ // If we're not opening the file ReadOnly or ReadWrite, don't attempt to
+ // read the file and send the mimetype.
+ if (mode & QIODevice::ReadOnly) {
+ size_t bytesRequested = 1024;
+ ssize_t bytesRead = 0;
+ QVarLengthArray<char> buffer(bytesRequested);
+
+ bytesRead = sftp_read(mOpenFile, buffer.data(), bytesRequested);
+ if (bytesRead < 0) {
+ error(KIO::ERR_COULD_NOT_READ, mOpenUrl.prettyUrl());
+ close();
+ return;
+ } else {
+ QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead);
+ KMimeType::Ptr p_mimeType = KMimeType::findByNameAndContent(mOpenUrl.fileName(), fileData);
+ emit mimeType(p_mimeType->name());
- // Go back to the beginning of the file.
- sftp_rewind(mOpenFile);
+ // Go back to the beginning of the file.
+ sftp_rewind(mOpenFile);
+ }
}
- }
- mOpenUrl = url;
+ mOpenUrl = url;
- openOffset = 0;
- totalSize(fileSize);
- position(0);
- opened();
+ openOffset = 0;
+ totalSize(fileSize);
+ position(0);
+ opened();
}
-void sftpProtocol::read(KIO::filesize_t bytes) {
- kDebug(KIO_SFTP_DB) << "read, offset = " << openOffset << ", bytes = " << bytes;
+void sftpProtocol::read(KIO::filesize_t bytes)
+{
+ kDebug(KIO_SFTP_DB) << "read, offset = " << openOffset << ", bytes = " << bytes;
- Q_ASSERT(mOpenFile != NULL);
+ Q_ASSERT(mOpenFile != NULL);
- QVarLengthArray<char> buffer(bytes);
+ QVarLengthArray<char> buffer(bytes);
- ssize_t bytesRead = sftp_read(mOpenFile, buffer.data(), bytes);
- Q_ASSERT(bytesRead <= static_cast<ssize_t>(bytes));
+ ssize_t bytesRead = sftp_read(mOpenFile, buffer.data(), bytes);
+ Q_ASSERT(bytesRead <= static_cast<ssize_t>(bytes));
- if (bytesRead < 0) {
- kDebug(KIO_SFTP_DB) << "Could not read " << mOpenUrl;
- error(KIO::ERR_COULD_NOT_READ, mOpenUrl.prettyUrl());
- close();
- return;
- }
+ if (bytesRead < 0) {
+ kDebug(KIO_SFTP_DB) << "Could not read " << mOpenUrl;
+ error(KIO::ERR_COULD_NOT_READ, mOpenUrl.prettyUrl());
+ close();
+ return;
+ }
- const QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead);
- data(fileData);
+ const QByteArray fileData = QByteArray::fromRawData(buffer.data(), bytesRead);
+ data(fileData);
}
-void sftpProtocol::write(const QByteArray &data) {
- kDebug(KIO_SFTP_DB) << "write, offset = " << openOffset << ", bytes = " << data.size();
+void sftpProtocol::write(const QByteArray &data)
+{
+ kDebug(KIO_SFTP_DB) << "write, offset = " << openOffset << ", bytes = " << data.size();
- Q_ASSERT(mOpenFile != NULL);
+ Q_ASSERT(mOpenFile != NULL);
- ssize_t bytesWritten = sftp_write(mOpenFile, data.data(), data.size());
- if (bytesWritten < 0) {
- kDebug(KIO_SFTP_DB) << "Could not write to " << mOpenUrl;
- error(KIO::ERR_COULD_NOT_WRITE, mOpenUrl.prettyUrl());
- close();
- return;
- }
+ ssize_t bytesWritten = sftp_write(mOpenFile, data.data(), data.size());
+ if (bytesWritten < 0) {
+ kDebug(KIO_SFTP_DB) << "Could not write to " << mOpenUrl;
+ error(KIO::ERR_COULD_NOT_WRITE, mOpenUrl.prettyUrl());
+ close();
+ return;
+ }
- written(bytesWritten);
+ written(bytesWritten);
}
-void sftpProtocol::seek(KIO::filesize_t offset) {
- kDebug(KIO_SFTP_DB) << "seek, offset = " << offset;
+void sftpProtocol::seek(KIO::filesize_t offset)
+{
+ kDebug(KIO_SFTP_DB) << "seek, offset = " << offset;
- Q_ASSERT(mOpenFile != NULL);
+ Q_ASSERT(mOpenFile != NULL);
- if (sftp_seek64(mOpenFile, static_cast<uint64_t>(offset)) < 0) {
- error(KIO::ERR_COULD_NOT_SEEK, mOpenUrl.path());
- close();
- }
+ if (sftp_seek64(mOpenFile, static_cast<uint64_t>(offset)) < 0) {
+ error(KIO::ERR_COULD_NOT_SEEK, mOpenUrl.path());
+ close();
+ }
- position(sftp_tell64(mOpenFile));
+ position(sftp_tell64(mOpenFile));
}
-void sftpProtocol::close() {
- sftp_close(mOpenFile);
+void sftpProtocol::close()
+{
+ sftp_close(mOpenFile);
- mOpenFile = NULL;
- finished();
+ mOpenFile = NULL;
+ finished();
}
-void sftpProtocol::get(const KUrl& url) {
- kDebug(KIO_SFTP_DB) << url;
+void sftpProtocol::get(const KUrl& url)
+{
+ kDebug(KIO_SFTP_DB) << url;
- int errorCode = 0;
- const sftpProtocol::StatusCode cs = sftpGet(url, errorCode);
+ int errorCode = 0;
+ const sftpProtocol::StatusCode cs = sftpGet(url, errorCode);
- if (cs == sftpProtocol::Success) {
- finished();
- return;
- }
+ if (cs == sftpProtocol::Success) {
+ finished();
+ return;
+ }
- // The call to sftpGet should only return server side errors since the file
- // descriptor parameter is set to -1.
- if (cs == sftpProtocol::ServerError && errorCode) {
- error(errorCode, url.prettyUrl());
- }
+ // The call to sftpGet should only return server side errors since the file
+ // descriptor parameter is set to -1.
+ if (cs == sftpProtocol::ServerError && errorCode) {
+ error(errorCode, url.prettyUrl());
+ }
}
-sftpProtocol::StatusCode sftpProtocol::sftpGet(const KUrl& url, int& errorCode, KIO::fileoffset_t offset, int fd) {
+sftpProtocol::StatusCode sftpProtocol::sftpGet(const KUrl& url, int& errorCode, KIO::fileoffset_t offset, int fd)
+{
+ kDebug(KIO_SFTP_DB) << url;
- kDebug(KIO_SFTP_DB) << url;
+ if (!sftpLogin()) {
+ return sftpProtocol::ServerError;
+ }
- if (!sftpLogin()) {
- return sftpProtocol::ServerError;
- }
+ QByteArray path = url.path().toUtf8();
- QByteArray path = url.path().toUtf8();
+ sftp_file file = NULL;
+ KIO::filesize_t totalbytesread = 0;
+ QByteArray filedata;
- sftp_file file = NULL;
- KIO::filesize_t totalbytesread = 0;
- QByteArray filedata;
+ sftp_attributes sb = sftp_lstat(mSftp, path.constData());
+ if (sb == NULL) {
+ errorCode = toKIOError(sftp_get_error(mSftp));
+ return sftpProtocol::ServerError;
+ }
- sftp_attributes sb = sftp_lstat(mSftp, path.constData());
- if (sb == NULL) {
- errorCode = toKIOError(sftp_get_error(mSftp));
- return sftpProtocol::ServerError;
- }
+ switch (sb->type) {
+ case SSH_FILEXFER_TYPE_DIRECTORY: {
+ errorCode = KIO::ERR_IS_DIRECTORY;
+ sftp_attributes_free(sb);
+ return sftpProtocol::ServerError;
+ }
+ case SSH_FILEXFER_TYPE_SPECIAL:
+ case SSH_FILEXFER_TYPE_UNKNOWN: {
+ errorCode = KIO::ERR_CANNOT_OPEN_FOR_READING;
+ sftp_attributes_free(sb);
+ return sftpProtocol::ServerError;
+ }
+ case SSH_FILEXFER_TYPE_SYMLINK:
+ case SSH_FILEXFER_TYPE_REGULAR: {
+ break;
+ }
+ }
- switch (sb->type) {
- case SSH_FILEXFER_TYPE_DIRECTORY:
- errorCode = KIO::ERR_IS_DIRECTORY;
- sftp_attributes_free(sb);
- return sftpProtocol::ServerError;
- case SSH_FILEXFER_TYPE_SPECIAL:
- case SSH_FILEXFER_TYPE_UNKNOWN:
- errorCode = KIO::ERR_CANNOT_OPEN_FOR_READING;
- sftp_attributes_free(sb);
- return sftpProtocol::ServerError;
- case SSH_FILEXFER_TYPE_SYMLINK:
- case SSH_FILEXFER_TYPE_REGULAR:
- break;
- }
+ // Open file
+ file = sftp_open(mSftp, path.constData(), O_RDONLY, 0);
+ if (file == NULL) {
+ errorCode = KIO::ERR_CANNOT_OPEN_FOR_READING;
+ sftp_attributes_free(sb);
+ return sftpProtocol::ServerError;
+ }
- // Open file
- file = sftp_open(mSftp, path.constData(), O_RDONLY, 0);
- if (file == NULL) {
- errorCode = KIO::ERR_CANNOT_OPEN_FOR_READING;
- sftp_attributes_free(sb);
- return sftpProtocol::ServerError;
- }
+ char mimeTypeBuf[1024];
+ ssize_t bytesread = sftp_read(file, mimeTypeBuf, sizeof(mimeTypeBuf));
- char mimeTypeBuf[1024];
- ssize_t bytesread = sftp_read(file, mimeTypeBuf, sizeof(mimeTypeBuf));
-
- if (bytesread < 0) {
- errorCode = KIO::ERR_COULD_NOT_READ;
- return sftpProtocol::ServerError;
- } else {
- int accuracy = 0;
- KMimeType::Ptr mime = KMimeType::findByNameAndContent(url.fileName(), QByteArray(mimeTypeBuf, bytesread), 0, &accuracy);
- if (!mime->isDefault() && accuracy == 100) {
- emit mimeType(mime->name());
- } else {
- accuracy = 0;
- mime = KMimeType::findByUrl(url.fileName(), 0, false, true, &accuracy);
- emit mimeType(mime->name());
+ if (bytesread < 0) {
+ errorCode = KIO::ERR_COULD_NOT_READ;
+ return sftpProtocol::ServerError;
+ } else {
+ int accuracy = 0;
+ KMimeType::Ptr mime = KMimeType::findByNameAndContent(url.fileName(), QByteArray(mimeTypeBuf, bytesread), 0, &accuracy);
+ if (!mime->isDefault() && accuracy == 100) {
+ emit mimeType(mime->name());
+ } else {
+ accuracy = 0;
+ mime = KMimeType::findByUrl(url.fileName(), 0, false, true, &accuracy);
+ emit mimeType(mime->name());
+ }
+ sftp_rewind(file);
}
- sftp_rewind(file);
- }
- // Set the total size
- totalSize(sb->size);
-
- // If offset is not specified, check the "resume" meta-data.
- if (offset < 0) {
- const QString resumeOffsetStr = metaData(QLatin1String("resume"));
- if (!resumeOffsetStr.isEmpty()) {
- bool ok;
- qlonglong resumeOffset = resumeOffsetStr.toLongLong(&ok);
- if (ok) {
- offset = resumeOffset;
- }
+ // Set the total size
+ totalSize(sb->size);
+
+ // If offset is not specified, check the "resume" meta-data.
+ if (offset < 0) {
+ const QString resumeOffsetStr = metaData(QLatin1String("resume"));
+ if (!resumeOffsetStr.isEmpty()) {
+ bool ok;
+ qlonglong resumeOffset = resumeOffsetStr.toLongLong(&ok);
+ if (ok) {
+ offset = resumeOffset;
+ }
+ }
}
- }
- // If we can resume, offset the buffer properly.
- if (offset > 0 && ((unsigned long long) offset < sb->size))
- {
- if (sftp_seek64(file, offset) == 0) {
- canResume();
- totalbytesread = offset;
- kDebug(KIO_SFTP_DB) << "Resume offset: " << QString::number(offset);
+ // If we can resume, offset the buffer properly.
+ if (offset > 0 && ((unsigned long long) offset < sb->size)) {
+ if (sftp_seek64(file, offset) == 0) {
+ canResume();
+ totalbytesread = offset;
+ kDebug(KIO_SFTP_DB) << "Resume offset: " << QString::number(offset);
+ }
}
- }
- bytesread = 0;
- sftpProtocol::GetRequest request(file, sb);
+ bytesread = 0;
+ sftpProtocol::GetRequest request(file, sb);
- for (;;) {
- // Enqueue get requests
- if (!request.enqueueChunks()) {
- errorCode = KIO::ERR_COULD_NOT_READ;
- return sftpProtocol::ServerError;
- }
+ for (;;) {
+ // Enqueue get requests
+ if (!request.enqueueChunks()) {
+ errorCode = KIO::ERR_COULD_NOT_READ;
+ return sftpProtocol::ServerError;
+ }
- filedata.clear();
- bytesread = request.readChunks(filedata);
- // Read pending get requests
- if (bytesread == -1) {
- errorCode = KIO::ERR_COULD_NOT_READ;
- return sftpProtocol::ServerError;
- } else if (bytesread == 0) {
- if (file->eof)
- break;
- else
- continue;
+ filedata.clear();
+ bytesread = request.readChunks(filedata);
+ // Read pending get requests
+ if (bytesread == -1) {
+ errorCode = KIO::ERR_COULD_NOT_READ;
+ return sftpProtocol::ServerError;
+ } else if (bytesread == 0) {
+ if (file->eof) {
+ break;
+ } else {
+ continue;
+ }
+ }
+
+ if (fd == -1) {
+ data(filedata);
+ } else if ((errorCode = writeToFile(fd, filedata.constData(), filedata.size()) != 0)) {
+ return sftpProtocol::ClientError;
+ }
+ // increment total bytes read
+ totalbytesread += filedata.length();
+
+ processedSize(totalbytesread);
}
if (fd == -1) {
- data(filedata);
- } else if ((errorCode = writeToFile(fd, filedata.constData(), filedata.size()) != 0)) {
- return sftpProtocol::ClientError;
+ data(QByteArray());
}
- // increment total bytes read
- totalbytesread += filedata.length();
-
- processedSize(totalbytesread);
- }
-
- if (fd == -1)
- data(QByteArray());
- processedSize(static_cast<KIO::filesize_t>(sb->size));
- return sftpProtocol::Success;
+ processedSize(static_cast<KIO::filesize_t>(sb->size));
+ return sftpProtocol::Success;
}
-void sftpProtocol::put(const KUrl& url, int permissions, KIO::JobFlags flags) {
- kDebug(KIO_SFTP_DB) << url << ", permissions =" << permissions
- << ", overwrite =" << (flags & KIO::Overwrite)
- << ", resume =" << (flags & KIO::Resume);
+void sftpProtocol::put(const KUrl& url, int permissions, KIO::JobFlags flags)
+{
+ kDebug(KIO_SFTP_DB) << url << ", permissions =" << permissions
+ << ", overwrite =" << (flags & KIO::Overwrite)
+ << ", resume =" << (flags & KIO::Resume);
- kDebug(KIO_SFTP_DB) << url;
+ kDebug(KIO_SFTP_DB) << url;
- int errorCode = 0;
- const sftpProtocol::StatusCode cs = sftpPut(url, permissions, flags, errorCode);
+ int errorCode = 0;
+ const sftpProtocol::StatusCode cs = sftpPut(url, permissions, flags, errorCode);
- if (cs == sftpProtocol::Success) {
- finished();
- return;
- }
+ if (cs == sftpProtocol::Success) {
+ finished();
+ return;
+ }
- // The call to sftpPut should only return server side errors since the file
- // descriptor parameter is set to -1.
- if (cs == sftpProtocol::ServerError && errorCode) {
- error(errorCode, url.prettyUrl());
- }
+ // The call to sftpPut should only return server side errors since the file
+ // descriptor parameter is set to -1.
+ if (cs == sftpProtocol::ServerError && errorCode) {
+ error(errorCode, url.prettyUrl());
+ }
}
-sftpProtocol::StatusCode sftpProtocol::sftpPut(const KUrl& url, int permissions, JobFlags flags, int& errorCode, int fd) {
- kDebug(KIO_SFTP_DB) << url << ", permissions =" << permissions
- << ", overwrite =" << (flags & KIO::Overwrite)
- << ", resume =" << (flags & KIO::Resume);
-
- if (!sftpLogin()) {
- return sftpProtocol::ServerError;
- }
-
- const QString dest_orig = url.path();
- const QByteArray dest_orig_c = dest_orig.toUtf8();
- const QString dest_part = dest_orig + ".part";
- const QByteArray dest_part_c = dest_part.toUtf8();
- uid_t owner = 0;
- gid_t group = 0;
-
- sftp_attributes sb = sftp_lstat(mSftp, dest_orig_c.constData());
- const bool bOrigExists = (sb != NULL);
- bool bPartExists = false;
- const bool bMarkPartial = config()->readEntry("MarkPartial", true);
-
- // Don't change permissions of the original file
- if (bOrigExists) {
- permissions = sb->permissions;
- owner = sb->uid;
- group = sb->gid;
- }
-
- if (bMarkPartial) {
- sftp_attributes sbPart = sftp_lstat(mSftp, dest_part_c.constData());
- bPartExists = (sbPart != NULL);
-
- if (bPartExists && !(flags & KIO::Resume) && !(flags & KIO::Overwrite) &&
- sbPart->size > 0 && sbPart->type == SSH_FILEXFER_TYPE_REGULAR) {
-
- if (fd == -1) {
- // Maybe we can use this partial file for resuming
- // Tell about the size we have, and the app will tell us
- // if it's ok to resume or not.
- kDebug(KIO_SFTP_DB) << "calling canResume with " << sbPart->size;
- flags |= canResume(sbPart->size) ? KIO::Resume : KIO::DefaultFlags;
- kDebug(KIO_SFTP_DB) << "put got answer " << (flags & KIO::Resume);
-
- } else {
- KIO::filesize_t pos = seekPos(fd, sbPart->size, SEEK_SET);
- if (pos != sbPart->size) {
- kDebug(KIO_SFTP_DB) << "Failed to seek to" << sbPart->size << "bytes in source file. Reason given" << strerror(errno);
- sftp_attributes_free(sb);
- sftp_attributes_free(sbPart);
- errorCode = ERR_COULD_NOT_SEEK;
- return sftpProtocol::ClientError;
- }
- flags |= KIO::Resume;
- }
- kDebug(KIO_SFTP_DB) << "Resuming at" << sbPart->size;
- sftp_attributes_free(sbPart);
+sftpProtocol::StatusCode sftpProtocol::sftpPut(const KUrl& url, int permissions, JobFlags flags, int& errorCode, int fd)
+{
+ kDebug(KIO_SFTP_DB) << url << ", permissions =" << permissions
+ << ", overwrite =" << (flags & KIO::Overwrite)
+ << ", resume =" << (flags & KIO::Resume);
+
+ if (!sftpLogin()) {
+ return sftpProtocol::ServerError;
+ }
+
+ const QString dest_orig = url.path();
+ const QByteArray dest_orig_c = dest_orig.toUtf8();
+ const QString dest_part = dest_orig + ".part";
+ const QByteArray dest_part_c = dest_part.toUtf8();
+ uid_t owner = 0;
+ gid_t group = 0;
+
+ sftp_attributes sb = sftp_lstat(mSftp, dest_orig_c.constData());
+ const bool bOrigExists = (sb != NULL);
+ bool bPartExists = false;
+ const bool bMarkPartial = config()->readEntry("MarkPartial", true);
+
+ // Don't change permissions of the original file
+ if (bOrigExists) {
+ permissions = sb->permissions;
+ owner = sb->uid;
+ group = sb->gid;
+ }
+
+ if (bMarkPartial) {
+ sftp_attributes sbPart = sftp_lstat(mSftp, dest_part_c.constData());
+ bPartExists = (sbPart != NULL);
+
+ if (bPartExists && !(flags & KIO::Resume) && !(flags & KIO::Overwrite) &&
+ sbPart->size > 0 && sbPart->type == SSH_FILEXFER_TYPE_REGULAR) {
+
+ if (fd == -1) {
+ // Maybe we can use this partial file for resuming
+ // Tell about the size we have, and the app will tell us
+ // if it's ok to resume or not.
+ kDebug(KIO_SFTP_DB) << "calling canResume with " << sbPart->size;
+ flags |= canResume(sbPart->size) ? KIO::Resume : KIO::DefaultFlags;
+ kDebug(KIO_SFTP_DB) << "put got answer " << (flags & KIO::Resume);
+
+ } else {
+ KIO::filesize_t pos = seekPos(fd, sbPart->size, SEEK_SET);
+ if (pos != sbPart->size) {
+ kDebug(KIO_SFTP_DB) << "Failed to seek to" << sbPart->size << "bytes in source file. Reason given" << strerror(errno);
+ sftp_attributes_free(sb);
+ sftp_attributes_free(sbPart);
+ errorCode = ERR_COULD_NOT_SEEK;
+ return sftpProtocol::ClientError;
+ }
+ flags |= KIO::Resume;
+ }
+ kDebug(KIO_SFTP_DB) << "Resuming at" << sbPart->size;
+ sftp_attributes_free(sbPart);
+ }
}
- }
- if (bOrigExists && !(flags & KIO::Overwrite) && !(flags & KIO::Resume)) {
- if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
- errorCode = KIO::ERR_DIR_ALREADY_EXIST;
- } else {
- errorCode = KIO::ERR_FILE_ALREADY_EXIST;
+ if (bOrigExists && !(flags & KIO::Overwrite) && !(flags & KIO::Resume)) {
+ if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
+ errorCode = KIO::ERR_DIR_ALREADY_EXIST;
+ } else {
+ errorCode = KIO::ERR_FILE_ALREADY_EXIST;
+ }
+ sftp_attributes_free(sb);
+ return sftpProtocol::ServerError;
}
- sftp_attributes_free(sb);
- return sftpProtocol::ServerError;
- }
- QByteArray dest;
- int result = -1;
- sftp_file file = NULL;
- StatusCode cs = sftpProtocol::Success;
- KIO::fileoffset_t totalBytesSent = 0;
+ QByteArray dest;
+ int result = -1;
+ sftp_file file = NULL;
+ StatusCode cs = sftpProtocol::Success;
+ KIO::fileoffset_t totalBytesSent = 0;
- // Loop until we got 0 (end of data)
- do {
- QByteArray buffer;
+ // Loop until we got 0 (end of data)
+ do {
+ QByteArray buffer;
- if (fd == -1) {
- dataReq(); // Request for data
- result = readData(buffer);
- } else {
- char buf[MAX_XFER_BUF_SIZE]; //
- result = ::read(fd, buf, sizeof(buf));
- if(result < 0) {
- errorCode = ERR_COULD_NOT_READ;
- cs = sftpProtocol::ClientError;
- break;
- }
- buffer = QByteArray(buf, result);
- }
-
- if (result >= 0) {
- if (dest.isEmpty()) {
- if (bMarkPartial) {
- kDebug(KIO_SFTP_DB) << "Appending .part extension to" << dest_orig;
- dest = dest_part_c;
- if (bPartExists && !(flags & KIO::Resume)) {
- kDebug(KIO_SFTP_DB) << "Deleting partial file" << dest_part;
- sftp_unlink(mSftp, dest_part_c.constData());
- // Catch errors when we try to open the file.
- }
+ if (fd == -1) {
+ dataReq(); // Request for data
+ result = readData(buffer);
} else {
- dest = dest_orig_c; // Will be automatically truncated below...
- } // bMarkPartial
-
- if ((flags & KIO::Resume)) {
- sftp_attributes fstat;
-
- kDebug(KIO_SFTP_DB) << "Trying to append: " << dest;
- file = sftp_open(mSftp, dest.constData(), O_RDWR, 0); // append if resuming
- if (file) {
- fstat = sftp_fstat(file);
- if (fstat) {
- sftp_seek64(file, fstat->size); // Seek to end TODO
- totalBytesSent += fstat->size;
- sftp_attributes_free(fstat);
+ char buf[MAX_XFER_BUF_SIZE]; //
+ result = ::read(fd, buf, sizeof(buf));
+ if (result < 0) {
+ errorCode = ERR_COULD_NOT_READ;
+ cs = sftpProtocol::ClientError;
+ break;
}
- }
- } else {
- mode_t initialMode;
-
- if (permissions != -1) {
- initialMode = permissions | S_IWUSR | S_IRUSR;
- } else {
- initialMode = 0644;
- }
-
- kDebug(KIO_SFTP_DB) << "Trying to open:" << QString(dest) << ", mode=" << QString::number(initialMode);
- file = sftp_open(mSftp, dest.constData(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
- } // flags & KIO::Resume
-
- if (file == NULL) {
- kDebug(KIO_SFTP_DB) << "COULD NOT WRITE " << QString(dest)
- << ", permissions=" << permissions
- << ", error=" << ssh_get_error(mSession);
- if (sftp_get_error(mSftp) == SSH_FX_PERMISSION_DENIED) {
- errorCode = KIO::ERR_WRITE_ACCESS_DENIED;
- } else {
- errorCode = KIO::ERR_CANNOT_OPEN_FOR_WRITING;
- }
- cs = sftpProtocol::ServerError;
- result = -1;
- continue;
- } // file
- } // dest.isEmpty
-
- ssize_t bytesWritten = sftp_write(file, buffer.data(), buffer.size());
- if (bytesWritten < 0) {
- errorCode = KIO::ERR_COULD_NOT_WRITE;
- result = -1;
- } else {
- totalBytesSent += bytesWritten;
- emit processedSize(totalBytesSent);
- }
- } // result
- } while (result > 0);
- sftp_attributes_free(sb);
+ buffer = QByteArray(buf, result);
+ }
- // An error occurred deal with it.
- if (result < 0) {
- kDebug(KIO_SFTP_DB) << "Error during 'put'. Aborting.";
+ if (result >= 0) {
+ if (dest.isEmpty()) {
+ if (bMarkPartial) {
+ kDebug(KIO_SFTP_DB) << "Appending .part extension to" << dest_orig;
+ dest = dest_part_c;
+ if (bPartExists && !(flags & KIO::Resume)) {
+ kDebug(KIO_SFTP_DB) << "Deleting partial file" << dest_part;
+ sftp_unlink(mSftp, dest_part_c.constData());
+ // Catch errors when we try to open the file.
+ }
+ } else {
+ dest = dest_orig_c; // Will be automatically truncated below...
+ } // bMarkPartial
+
+ if ((flags & KIO::Resume)) {
+ sftp_attributes fstat;
+
+ kDebug(KIO_SFTP_DB) << "Trying to append: " << dest;
+ file = sftp_open(mSftp, dest.constData(), O_RDWR, 0); // append if resuming
+ if (file) {
+ fstat = sftp_fstat(file);
+ if (fstat) {
+ sftp_seek64(file, fstat->size); // Seek to end TODO
+ totalBytesSent += fstat->size;
+ sftp_attributes_free(fstat);
+ }
+ }
+ } else {
+ mode_t initialMode;
+
+ if (permissions != -1) {
+ initialMode = permissions | S_IWUSR | S_IRUSR;
+ } else {
+ initialMode = 0644;
+ }
+
+ kDebug(KIO_SFTP_DB) << "Trying to open:" << QString(dest) << ", mode=" << QString::number(initialMode);
+ file = sftp_open(mSftp, dest.constData(), O_CREAT | O_TRUNC | O_WRONLY, initialMode);
+ } // flags & KIO::Resume
+
+ if (file == NULL) {
+ kDebug(KIO_SFTP_DB) << "COULD NOT WRITE " << QString(dest)
+ << ", permissions=" << permissions
+ << ", error=" << ssh_get_error(mSession);
+ if (sftp_get_error(mSftp) == SSH_FX_PERMISSION_DENIED) {
+ errorCode = KIO::ERR_WRITE_ACCESS_DENIED;
+ } else {
+ errorCode = KIO::ERR_CANNOT_OPEN_FOR_WRITING;
+ }
+ cs = sftpProtocol::ServerError;
+ result = -1;
+ continue;
+ } // file
+ } // dest.isEmpty
+
+ ssize_t bytesWritten = sftp_write(file, buffer.data(), buffer.size());
+ if (bytesWritten < 0) {
+ errorCode = KIO::ERR_COULD_NOT_WRITE;
+ result = -1;
+ } else {
+ totalBytesSent += bytesWritten;
+ emit processedSize(totalBytesSent);
+ }
+ } // result
+ } while (result > 0);
+ sftp_attributes_free(sb);
- if (file != NULL) {
- sftp_close(file);
+ // An error occurred deal with it.
+ if (result < 0) {
+ kDebug(KIO_SFTP_DB) << "Error during 'put'. Aborting.";
- sftp_attributes attr = sftp_stat(mSftp, dest.constData());
- if (bMarkPartial && attr != NULL) {
- size_t size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
- if (attr->size < size) {
- sftp_unlink(mSftp, dest.constData());
- }
- }
- delete attr;
- sftp_attributes_free(attr);
- }
+ if (file != NULL) {
+ sftp_close(file);
- //::exit(255);
- return cs;
- }
+ sftp_attributes attr = sftp_stat(mSftp, dest.constData());
+ if (bMarkPartial && attr != NULL) {
+ size_t size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
+ if (attr->size < size) {
+ sftp_unlink(mSftp, dest.constData());
+ }
+ }
+ delete attr;
+ sftp_attributes_free(attr);
+ }
- if (file == NULL) { // we got nothing to write out, so we never opened the file
- return sftpProtocol::Success;
- }
+ //::exit(255);
+ return cs;
+ }
- if (sftp_close(file) < 0) {
- kWarning(KIO_SFTP_DB) << "Error when closing file descriptor";
- error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
- return sftpProtocol::ServerError;
- }
+ if (file == NULL) { // we got nothing to write out, so we never opened the file
+ return sftpProtocol::Success;
+ }
- // after full download rename the file back to original name
- if (bMarkPartial) {
- // If the original URL is a symlink and we were asked to overwrite it,
- // remove the symlink first. This ensures that we do not overwrite the
- // current source if the symlink points to it.
- if ((flags & KIO::Overwrite)) {
- sftp_unlink(mSftp, dest_orig_c.constData());
+ if (sftp_close(file) < 0) {
+ kWarning(KIO_SFTP_DB) << "Error when closing file descriptor";
+ error(KIO::ERR_COULD_NOT_WRITE, dest_orig);
+ return sftpProtocol::ServerError;
}
- if (sftp_rename(mSftp, dest.constData(), dest_orig_c.constData()) < 0) {
- kWarning(KIO_SFTP_DB) << " Couldn't rename " << dest << " to " << dest_orig;
- errorCode = KIO::ERR_CANNOT_RENAME_PARTIAL;
- return sftpProtocol::ServerError;
+ // after full download rename the file back to original name
+ if (bMarkPartial) {
+ // If the original URL is a symlink and we were asked to overwrite it,
+ // remove the symlink first. This ensures that we do not overwrite the
+ // current source if the symlink points to it.
+ if ((flags & KIO::Overwrite)) {
+ sftp_unlink(mSftp, dest_orig_c.constData());
+ }
+
+ if (sftp_rename(mSftp, dest.constData(), dest_orig_c.constData()) < 0) {
+ kWarning(KIO_SFTP_DB) << " Couldn't rename " << dest << " to " << dest_orig;
+ errorCode = KIO::ERR_CANNOT_RENAME_PARTIAL;
+ return sftpProtocol::ServerError;
+ }
}
- }
- // set final permissions
- if (permissions != -1 && !(flags & KIO::Resume)) {
- kDebug(KIO_SFTP_DB) << "Trying to set final permissions of " << dest_orig << " to " << QString::number(permissions);
- if (sftp_chmod(mSftp, dest_orig_c.constData(), permissions) < 0) {
- errorCode = -1; // force copy to call sftpSendWarning...
- return sftpProtocol::ServerError;
+ // set final permissions
+ if (permissions != -1 && !(flags & KIO::Resume)) {
+ kDebug(KIO_SFTP_DB) << "Trying to set final permissions of " << dest_orig << " to " << QString::number(permissions);
+ if (sftp_chmod(mSftp, dest_orig_c.constData(), permissions) < 0) {
+ errorCode = -1; // force copy to call sftpSendWarning...
+ return sftpProtocol::ServerError;
+ }
}
- }
- // set original owner and group
- if (bOrigExists) {
- kDebug(KIO_SFTP_DB) << "Trying to restore original owner and group of " << dest_orig;
- if (sftp_chown(mSftp, dest_orig_c.constData(), owner, group) < 0) {
- kWarning(KIO_SFTP_DB) << "Could not change owner and group for" << dest_orig;
- // warning(i18n( "Could not change owner and group for\n%1", dest_orig));
+ // set original owner and group
+ if (bOrigExists) {
+ kDebug(KIO_SFTP_DB) << "Trying to restore original owner and group of " << dest_orig;
+ if (sftp_chown(mSftp, dest_orig_c.constData(), owner, group) < 0) {
+ kWarning(KIO_SFTP_DB) << "Could not change owner and group for" << dest_orig;
+ // warning(i18n( "Could not change owner and group for\n%1", dest_orig));
+ }
}
- }
- // set modification time
- const QString mtimeStr = metaData("modified");
- if (!mtimeStr.isEmpty()) {
- QDateTime dt = QDateTime::fromString(mtimeStr, Qt::ISODate);
- if (dt.isValid()) {
- struct timeval times[2];
-
- sftp_attributes attr = sftp_lstat(mSftp, dest_orig_c.constData());
- if (attr != NULL) {
- times[0].tv_sec = attr->atime; //// access time, unchanged
- times[1].tv_sec = dt.toTime_t(); // modification time
- times[0].tv_usec = times[1].tv_usec = 0;
-
- kDebug(KIO_SFTP_DB) << "Trying to restore mtime for " << dest_orig << " to: " << mtimeStr;
- result = sftp_utimes(mSftp, dest_orig_c.constData(), times);
- if (result < 0) {
- kWarning(KIO_SFTP_DB) << "Failed to set mtime for" << dest_orig;
- }
- sftp_attributes_free(attr);
- }
+ // set modification time
+ const QString mtimeStr = metaData("modified");
+ if (!mtimeStr.isEmpty()) {
+ QDateTime dt = QDateTime::fromString(mtimeStr, Qt::ISODate);
+ if (dt.isValid()) {
+ struct timeval times[2];
+
+ sftp_attributes attr = sftp_lstat(mSftp, dest_orig_c.constData());
+ if (attr != NULL) {
+ times[0].tv_sec = attr->atime; //// access time, unchanged
+ times[1].tv_sec = dt.toTime_t(); // modification time
+ times[0].tv_usec = times[1].tv_usec = 0;
+
+ kDebug(KIO_SFTP_DB) << "Trying to restore mtime for " << dest_orig << " to: " << mtimeStr;
+ result = sftp_utimes(mSftp, dest_orig_c.constData(), times);
+ if (result < 0) {
+ kWarning(KIO_SFTP_DB) << "Failed to set mtime for" << dest_orig;
+ }
+ sftp_attributes_free(attr);
+ }
+ }
}
- }
- return sftpProtocol::Success;
+ return sftpProtocol::Success;
}
void sftpProtocol::copy(const KUrl &src, const KUrl &dest, int permissions, KIO::JobFlags flags)
{
- kDebug(KIO_SFTP_DB) << src << " -> " << dest << " , permissions = " << QString::number(permissions)
- << ", overwrite = " << (flags & KIO::Overwrite)
- << ", resume = " << (flags & KIO::Resume);
-
- QString sCopyFile;
- int errorCode = 0;
- StatusCode cs = sftpProtocol::ClientError;
- const bool isSourceLocal = src.isLocalFile();
- const bool isDestinationLocal = dest.isLocalFile();
-
- if (!isSourceLocal && isDestinationLocal) { // sftp -> file
- sCopyFile = dest.toLocalFile();
- cs = sftpCopyGet(src, sCopyFile, permissions, flags, errorCode);
- if (cs == sftpProtocol::ServerError)
- sCopyFile = src.url();
- } else if (isSourceLocal && !isDestinationLocal) { // file -> sftp
- sCopyFile = src.toLocalFile();
- cs = sftpCopyPut(dest, sCopyFile, permissions, flags, errorCode);
- if (cs == sftpProtocol::ServerError)
- sCopyFile = dest.url();
- } else {
- errorCode = KIO::ERR_UNSUPPORTED_ACTION;
- sCopyFile.clear();
- }
+ kDebug(KIO_SFTP_DB) << src << " -> " << dest << " , permissions = " << QString::number(permissions)
+ << ", overwrite = " << (flags & KIO::Overwrite)
+ << ", resume = " << (flags & KIO::Resume);
+
+ QString sCopyFile;
+ int errorCode = 0;
+ StatusCode cs = sftpProtocol::ClientError;
+ const bool isSourceLocal = src.isLocalFile();
+ const bool isDestinationLocal = dest.isLocalFile();
+
+ if (!isSourceLocal && isDestinationLocal) { // sftp -> file
+ sCopyFile = dest.toLocalFile();
+ cs = sftpCopyGet(src, sCopyFile, permissions, flags, errorCode);
+ if (cs == sftpProtocol::ServerError) {
+ sCopyFile = src.url();
+ }
+ } else if (isSourceLocal && !isDestinationLocal) { // file -> sftp
+ sCopyFile = src.toLocalFile();
+ cs = sftpCopyPut(dest, sCopyFile, permissions, flags, errorCode);
+ if (cs == sftpProtocol::ServerError) {
+ sCopyFile = dest.url();
+ }
+ } else {
+ errorCode = KIO::ERR_UNSUPPORTED_ACTION;
+ sCopyFile.clear();
+ }
- // On success or errorcode < 0, emit the finished signal and
- // send a warning message to the client if errorCode < 0.
- if (cs == sftpProtocol::Success || errorCode < 0) {
- if (errorCode < 0)
- sftpSendWarning(errorCode, sCopyFile);
- finished();
- return;
- }
+ // On success or errorcode < 0, emit the finished signal and
+ // send a warning message to the client if errorCode < 0.
+ if (cs == sftpProtocol::Success || errorCode < 0) {
+ if (errorCode < 0) {
+ sftpSendWarning(errorCode, sCopyFile);
+ }
+ finished();
+ return;
+ }
- if (errorCode) {
- error(errorCode, sCopyFile);
- }
+ if (errorCode) {
+ error(errorCode, sCopyFile);
+ }
}
sftpProtocol::StatusCode sftpProtocol::sftpCopyGet(const KUrl& url, const QString& sCopyFile, int permissions, KIO::JobFlags flags, int& errorCode)
{
- kDebug(KIO_SFTP_DB) << url << "->" << sCopyFile << ", permissions=" << permissions;
+ kDebug(KIO_SFTP_DB) << url << "->" << sCopyFile << ", permissions=" << permissions;
- // check if destination is ok ...
- KDE_struct_stat buff;
- const bool bDestExists = (KDE::stat(sCopyFile, &buff) != -1);
+ // check if destination is ok ...
+ KDE_struct_stat buff;
+ const bool bDestExists = (KDE::stat(sCopyFile, &buff) != -1);
- if(bDestExists) {
- if(S_ISDIR(buff.st_mode)) {
- errorCode = ERR_IS_DIRECTORY;
- return sftpProtocol::ClientError;
- }
+ if (bDestExists) {
+ if (S_ISDIR(buff.st_mode)) {
+ errorCode = ERR_IS_DIRECTORY;
+ return sftpProtocol::ClientError;
+ }
- if(!(flags & KIO::Overwrite)) {
- errorCode = ERR_FILE_ALREADY_EXIST;
- return sftpProtocol::ClientError;
+ if (!(flags & KIO::Overwrite)) {
+ errorCode = ERR_FILE_ALREADY_EXIST;
+ return sftpProtocol::ClientError;
+ }
}
- }
- bool bResume = false;
- const QString sPart = sCopyFile + QLatin1String(".part"); // do we have a ".part" file?
- const bool bPartExists = (KDE::stat(sPart, &buff) != -1);
- const bool bMarkPartial = config()->readEntry("MarkPartial", true);
- const QString dest = (bMarkPartial ? sPart : sCopyFile);
+ bool bResume = false;
+ const QString sPart = sCopyFile + QLatin1String(".part"); // do we have a ".part" file?
+ const bool bPartExists = (KDE::stat(sPart, &buff) != -1);
+ const bool bMarkPartial = config()->readEntry("MarkPartial", true);
+ const QString dest = (bMarkPartial ? sPart : sCopyFile);
- if (bMarkPartial && bPartExists && buff.st_size > 0) {
- if (S_ISDIR(buff.st_mode)) {
- errorCode = ERR_DIR_ALREADY_EXIST;
- return sftpProtocol::ClientError; // client side error
+ if (bMarkPartial && bPartExists && buff.st_size > 0) {
+ if (S_ISDIR(buff.st_mode)) {
+ errorCode = ERR_DIR_ALREADY_EXIST;
+ return sftpProtocol::ClientError; // client side error
+ }
+ bResume = canResume( buff.st_size );
}
- bResume = canResume( buff.st_size );
- }
- if (bPartExists && !bResume) // get rid of an unwanted ".part" file
- QFile::remove(sPart);
+ if (bPartExists && !bResume) { // get rid of an unwanted ".part" file
+ QFile::remove(sPart);
+ }
// WABA: Make sure that we keep writing permissions ourselves,
// otherwise we can be in for a surprise on NFS.
- mode_t initialMode;
- if (permissions != -1)
- initialMode = permissions | S_IWUSR;
- else
- initialMode = 0666;
-
- // open the output file ...
- int fd = -1;
- KIO::fileoffset_t offset = 0;
- if (bResume) {
- fd = KDE::open( sPart, O_RDWR ); // append if resuming
- offset = seekPos(fd, 0, SEEK_END);
- if(offset < 0) {
- errorCode = ERR_CANNOT_RESUME;
- ::close(fd);
- return sftpProtocol::ClientError; // client side error
- }
- kDebug(KIO_SFTP_DB) << "resuming at" << offset;
- }
- else {
- fd = KDE::open(dest, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
- }
+ mode_t initialMode;
+ if (permissions != -1) {
+ initialMode = permissions | S_IWUSR;
+ } else {
+ initialMode = 0666;
+ }
+
+ // open the output file ...
+ int fd = -1;
+ KIO::fileoffset_t offset = 0;
+ if (bResume) {
+ fd = KDE::open( sPart, O_RDWR ); // append if resuming
+ offset = seekPos(fd, 0, SEEK_END);
+ if (offset < 0) {
+ errorCode = ERR_CANNOT_RESUME;
+ ::close(fd);
+ return sftpProtocol::ClientError; // client side error
+ }
+ kDebug(KIO_SFTP_DB) << "resuming at" << offset;
+ } else {
+ fd = KDE::open(dest, O_CREAT | O_TRUNC | O_WRONLY, initialMode);
+ }
- if (fd == -1) {
- kDebug(KIO_SFTP_DB) << "could not write to" << sCopyFile;
- errorCode = (errno == EACCES) ? ERR_WRITE_ACCESS_DENIED : ERR_CANNOT_OPEN_FOR_WRITING;
- return sftpProtocol::ClientError;
- }
+ if (fd == -1) {
+ kDebug(KIO_SFTP_DB) << "could not write to" << sCopyFile;
+ errorCode = (errno == EACCES) ? ERR_WRITE_ACCESS_DENIED : ERR_CANNOT_OPEN_FOR_WRITING;
+ return sftpProtocol::ClientError;
+ }
- StatusCode result = sftpGet(url, errorCode, offset, fd);
+ StatusCode result = sftpGet(url, errorCode, offset, fd);
- if( ::close(fd) && result == sftpProtocol::Success ) {
- errorCode = ERR_COULD_NOT_WRITE;
- result = sftpProtocol::ClientError;
- }
+ if( ::close(fd) && result == sftpProtocol::Success ) {
+ errorCode = ERR_COULD_NOT_WRITE;
+ result = sftpProtocol::ClientError;
+ }
- // handle renaming or deletion of a partial file ...
- if (bMarkPartial) {
- if (result == sftpProtocol::Success) { // rename ".part" on success
- if ( KDE::rename( sPart, sCopyFile ) ) {
- // If rename fails, try removing the destination first if it exists.
- if (!bDestExists || !(QFile::remove(sCopyFile) && KDE::rename(sPart, sCopyFile) == 0)) {
- kDebug(KIO_SFTP_DB) << "cannot rename " << sPart << " to " << sCopyFile;
- errorCode = ERR_CANNOT_RENAME_PARTIAL;
- result = sftpProtocol::ClientError;
+ // handle renaming or deletion of a partial file ...
+ if (bMarkPartial) {
+ if (result == sftpProtocol::Success) { // rename ".part" on success
+ if ( KDE::rename( sPart, sCopyFile ) ) {
+ // If rename fails, try removing the destination first if it exists.
+ if (!bDestExists || !(QFile::remove(sCopyFile) && KDE::rename(sPart, sCopyFile) == 0)) {
+ kDebug(KIO_SFTP_DB) << "cannot rename " << sPart << " to " << sCopyFile;
+ errorCode = ERR_CANNOT_RENAME_PARTIAL;
+ result = sftpProtocol::ClientError;
+ }
+ }
+ } else if (KDE::stat( sPart, &buff ) == 0) { // should a very small ".part" be deleted?
+ const int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
+ if (buff.st_size < size) {
+ QFile::remove(sPart);
+ }
}
- }
}
- else if (KDE::stat( sPart, &buff ) == 0) { // should a very small ".part" be deleted?
- const int size = config()->readEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
- if (buff.st_size < size)
- QFile::remove(sPart);
- }
- }
- const QString mtimeStr = metaData("modified");
- if (!mtimeStr.isEmpty()) {
- QDateTime dt = QDateTime::fromString(mtimeStr, Qt::ISODate);
- if (dt.isValid()) {
- struct utimbuf utbuf;
- utbuf.actime = buff.st_atime; // access time, unchanged
- utbuf.modtime = dt.toTime_t(); // modification time
- KDE::utime(sCopyFile, &utbuf);
+ const QString mtimeStr = metaData("modified");
+ if (!mtimeStr.isEmpty()) {
+ QDateTime dt = QDateTime::fromString(mtimeStr, Qt::ISODate);
+ if (dt.isValid()) {
+ struct utimbuf utbuf;
+ utbuf.actime = buff.st_atime; // access time, unchanged
+ utbuf.modtime = dt.toTime_t(); // modification time
+ KDE::utime(sCopyFile, &utbuf);
+ }
}
- }
- return result;
+ return result;
}
sftpProtocol::StatusCode sftpProtocol::sftpCopyPut(const KUrl& url, const QString& sCopyFile, int permissions, JobFlags flags, int& errorCode)
{
- kDebug(KIO_SFTP_DB) << sCopyFile << "->" << url << ", permissions=" << permissions << ", flags" << flags;
+ kDebug(KIO_SFTP_DB) << sCopyFile << "->" << url << ", permissions=" << permissions << ", flags" << flags;
- // check if source is ok ...
- KDE_struct_stat buff;
- bool bSrcExists = (KDE::stat(sCopyFile, &buff) != -1);
+ // check if source is ok ...
+ KDE_struct_stat buff;
+ bool bSrcExists = (KDE::stat(sCopyFile, &buff) != -1);
- if (bSrcExists) {
- if (S_ISDIR(buff.st_mode)) {
- errorCode = ERR_IS_DIRECTORY;
- return sftpProtocol::ClientError;
+ if (bSrcExists) {
+ if (S_ISDIR(buff.st_mode)) {
+ errorCode = ERR_IS_DIRECTORY;
+ return sftpProtocol::ClientError;
+ }
+ } else {
+ errorCode = ERR_DOES_NOT_EXIST;
+ return sftpProtocol::ClientError;
}
- } else {
- errorCode = ERR_DOES_NOT_EXIST;
- return sftpProtocol::ClientError;
- }
- const int fd = KDE::open(sCopyFile, O_RDONLY);
- if(fd == -1)
- {
- errorCode = ERR_CANNOT_OPEN_FOR_READING;
- return sftpProtocol::ClientError;
- }
+ const int fd = KDE::open(sCopyFile, O_RDONLY);
+ if (fd == -1) {
+ errorCode = ERR_CANNOT_OPEN_FOR_READING;
+ return sftpProtocol::ClientError;
+ }
- totalSize(buff.st_size);
+ totalSize(buff.st_size);
- // delegate the real work (errorCode gets status) ...
- StatusCode ret = sftpPut(url, permissions, flags, errorCode, fd);
- ::close(fd);
- return ret;
+ // delegate the real work (errorCode gets status) ...
+ StatusCode ret = sftpPut(url, permissions, flags, errorCode, fd);
+ ::close(fd);
+ return ret;
}
-void sftpProtocol::stat(const KUrl& url) {
- kDebug(KIO_SFTP_DB) << url;
+void sftpProtocol::stat(const KUrl& url)
+{
+ kDebug(KIO_SFTP_DB) << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- if (! url.hasPath() || QDir::isRelativePath(url.path()) ||
- url.path().contains("/./") || url.path().contains("/../")) {
- QString cPath;
+ if (! url.hasPath() || QDir::isRelativePath(url.path()) ||
+ url.path().contains("/./") || url.path().contains("/../")) {
+ QString cPath;
- if (url.hasPath()) {
- cPath = canonicalizePath(url.path());
- } else {
- cPath = canonicalizePath(QLatin1String("."));
- }
+ if (url.hasPath()) {
+ cPath = canonicalizePath(url.path());
+ } else {
+ cPath = canonicalizePath(QLatin1String("."));
+ }
- if (cPath.isEmpty()) {
- error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
- return;
- }
- KUrl redir(url);
- redir.setPath(cPath);
- redirection(redir);
+ if (cPath.isEmpty()) {
+ error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
+ return;
+ }
+ KUrl redir(url);
+ redir.setPath(cPath);
+ redirection(redir);
- kDebug(KIO_SFTP_DB) << "redirecting to " << redir.url();
+ kDebug(KIO_SFTP_DB) << "redirecting to " << redir.url();
- finished();
- return;
- }
+ finished();
+ return;
+ }
- QByteArray path = url.path().toUtf8();
+ QByteArray path = url.path().toUtf8();
- const QString sDetails = metaData(QLatin1String("details"));
- const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
+ const QString sDetails = metaData(QLatin1String("details"));
+ const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
- UDSEntry entry;
- entry.clear();
- if (!createUDSEntry(url.fileName(), path, entry, details)) {
- error(KIO::ERR_DOES_NOT_EXIST, url.prettyUrl());
- return;
- }
+ UDSEntry entry;
+ entry.clear();
+ if (!createUDSEntry(url.fileName(), path, entry, details)) {
+ error(KIO::ERR_DOES_NOT_EXIST, url.prettyUrl());
+ return;
+ }
- statEntry(entry);
+ statEntry(entry);
- finished();
+ finished();
}
-void sftpProtocol::mimetype(const KUrl& url){
- kDebug(KIO_SFTP_DB) << url;
+void sftpProtocol::mimetype(const KUrl& url)
+{
+ kDebug(KIO_SFTP_DB) << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- // open() feeds the mimetype
- open(url, QIODevice::ReadOnly);
- close();
+ // open() feeds the mimetype
+ open(url, QIODevice::ReadOnly);
+ close();
- finished();
+ finished();
}
-void sftpProtocol::listDir(const KUrl& url) {
- kDebug(KIO_SFTP_DB) << "list directory: " << url;
+void sftpProtocol::listDir(const KUrl& url)
+{
+ kDebug(KIO_SFTP_DB) << "list directory: " << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- if (! url.hasPath() || QDir::isRelativePath(url.path()) ||
- url.path().contains("/./") || url.path().contains("/../")) {
- QString cPath;
+ if (! url.hasPath() || QDir::isRelativePath(url.path()) ||
+ url.path().contains("/./") || url.path().contains("/../")) {
+ QString cPath;
- if (url.hasPath()) {
- cPath = canonicalizePath(url.path());
- } else {
- cPath = canonicalizePath(QString("."));
- }
+ if (url.hasPath()) {
+ cPath = canonicalizePath(url.path());
+ } else {
+ cPath = canonicalizePath(QString("."));
+ }
- if (cPath.isEmpty()) {
- error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
- return;
- }
- KUrl redir(url);
- redir.setPath(cPath);
- redirection(redir);
+ if (cPath.isEmpty()) {
+ error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
+ return;
+ }
+ KUrl redir(url);
+ redir.setPath(cPath);
+ redirection(redir);
- kDebug(KIO_SFTP_DB) << "redirecting to " << redir.url();
+ kDebug(KIO_SFTP_DB) << "redirecting to " << redir.url();
- finished();
- return;
- }
+ finished();
+ return;
+ }
- QByteArray path = url.path().toUtf8();
+ QByteArray path = url.path().toUtf8();
- sftp_dir dp = sftp_opendir(mSftp, path.constData());
- if (dp == NULL) {
- reportError(url, sftp_get_error(mSftp));
- return;
- }
+ sftp_dir dp = sftp_opendir(mSftp, path.constData());
+ if (dp == NULL) {
+ reportError(url, sftp_get_error(mSftp));
+ return;
+ }
- sftp_attributes dirent = NULL;
- const QString sDetails = metaData(QLatin1String("details"));
- const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
- UDSEntry entry;
+ sftp_attributes dirent = NULL;
+ const QString sDetails = metaData(QLatin1String("details"));
+ const int details = sDetails.isEmpty() ? 2 : sDetails.toInt();
+ UDSEntry entry;
- kDebug(KIO_SFTP_DB) << "readdir: " << path << ", details: " << QString::number(details);
+ kDebug(KIO_SFTP_DB) << "readdir: " << path << ", details: " << QString::number(details);
- for (;;) {
- mode_t access;
- mode_t type;
- char *link;
+ for (;;) {
+ mode_t access;
+ mode_t type;
+ char *link;
- dirent = sftp_readdir(mSftp, dp);
- if (dirent == NULL) {
- break;
- }
+ dirent = sftp_readdir(mSftp, dp);
+ if (dirent == NULL) {
+ break;
+ }
- entry.clear();
- entry.insert(KIO::UDSEntry::UDS_NAME, QFile::decodeName(dirent->name));
+ entry.clear();
+ entry.insert(KIO::UDSEntry::UDS_NAME, QFile::decodeName(dirent->name));
- if (dirent->type == SSH_FILEXFER_TYPE_SYMLINK) {
- QByteArray file = path + '/' + QFile::decodeName(dirent->name).toUtf8();
+ if (dirent->type == SSH_FILEXFER_TYPE_SYMLINK) {
+ QByteArray file = path + '/' + QFile::decodeName(dirent->name).toUtf8();
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
- link = sftp_readlink(mSftp, file.constData());
- if (link == NULL) {
- sftp_attributes_free(dirent);
- error(KIO::ERR_INTERNAL, i18n("Could not read link: %1", QString::fromUtf8(file)));
- return;
- }
- entry.insert(KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName(link));
- delete link;
- // A symlink -> follow it only if details > 1
- if (details > 1) {
- sftp_attributes sb = sftp_stat(mSftp, file.constData());
- if (sb == NULL) {
- // It is a link pointing to nowhere
- type = S_IFMT - 1;
- access = S_IRWXU | S_IRWXG | S_IRWXO;
- entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type);
- entry.insert( KIO::UDSEntry::UDS_ACCESS, access);
- entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
-
- goto notype;
+ link = sftp_readlink(mSftp, file.constData());
+ if (link == NULL) {
+ sftp_attributes_free(dirent);
+ error(KIO::ERR_INTERNAL, i18n("Could not read link: %1", QString::fromUtf8(file)));
+ return;
+ }
+ entry.insert(KIO::UDSEntry::UDS_LINK_DEST, QFile::decodeName(link));
+ delete link;
+ // A symlink -> follow it only if details > 1
+ if (details > 1) {
+ sftp_attributes sb = sftp_stat(mSftp, file.constData());
+ if (sb == NULL) {
+ // It is a link pointing to nowhere
+ type = S_IFMT - 1;
+ access = S_IRWXU | S_IRWXG | S_IRWXO;
+ entry.insert( KIO::UDSEntry::UDS_FILE_TYPE, type);
+ entry.insert( KIO::UDSEntry::UDS_ACCESS, access);
+ entry.insert( KIO::UDSEntry::UDS_SIZE, 0LL );
+
+ goto notype;
+ }
+ sftp_attributes_free(dirent);
+ dirent = sb;
+ }
}
- sftp_attributes_free(dirent);
- dirent = sb;
- }
- }
- switch (dirent->type) {
- case SSH_FILEXFER_TYPE_REGULAR:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
- break;
- case SSH_FILEXFER_TYPE_DIRECTORY:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
- break;
- case SSH_FILEXFER_TYPE_SYMLINK:
- entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFLNK);
- break;
- case SSH_FILEXFER_TYPE_SPECIAL:
- case SSH_FILEXFER_TYPE_UNKNOWN:
- break;
- }
-
- access = dirent->permissions & 07777;
- entry.insert(KIO::UDSEntry::UDS_ACCESS, access);
+ switch (dirent->type) {
+ case SSH_FILEXFER_TYPE_REGULAR: {
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFREG);
+ break;
+ }
+ case SSH_FILEXFER_TYPE_DIRECTORY: {
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFDIR);
+ break;
+ }
+ case SSH_FILEXFER_TYPE_SYMLINK: {
+ entry.insert(KIO::UDSEntry::UDS_FILE_TYPE, S_IFLNK);
+ break;
+ }
+ case SSH_FILEXFER_TYPE_SPECIAL:
+ case SSH_FILEXFER_TYPE_UNKNOWN: {
+ break;
+ }
+ }
- entry.insert(KIO::UDSEntry::UDS_SIZE, dirent->size);
+ access = dirent->permissions & 07777;
+ entry.insert(KIO::UDSEntry::UDS_ACCESS, access);
+
+ entry.insert(KIO::UDSEntry::UDS_SIZE, dirent->size);
notype:
- if (details > 0) {
- if (dirent->owner) {
- entry.insert(KIO::UDSEntry::UDS_USER, QString::fromUtf8(dirent->owner));
- } else {
- entry.insert(KIO::UDSEntry::UDS_USER, QString::number(dirent->uid));
- }
+ if (details > 0) {
+ if (dirent->owner) {
+ entry.insert(KIO::UDSEntry::UDS_USER, QString::fromUtf8(dirent->owner));
+ } else {
+ entry.insert(KIO::UDSEntry::UDS_USER, QString::number(dirent->uid));
+ }
- if (dirent->group) {
- entry.insert(KIO::UDSEntry::UDS_GROUP, QString::fromUtf8(dirent->group));
- } else {
- entry.insert(KIO::UDSEntry::UDS_GROUP, QString::number(dirent->gid));
- }
+ if (dirent->group) {
+ entry.insert(KIO::UDSEntry::UDS_GROUP, QString::fromUtf8(dirent->group));
+ } else {
+ entry.insert(KIO::UDSEntry::UDS_GROUP, QString::number(dirent->gid));
+ }
- entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, dirent->atime);
- entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, dirent->mtime);
- entry.insert(KIO::UDSEntry::UDS_CREATION_TIME, dirent->createtime);
- }
+ entry.insert(KIO::UDSEntry::UDS_ACCESS_TIME, dirent->atime);
+ entry.insert(KIO::UDSEntry::UDS_MODIFICATION_TIME, dirent->mtime);
+ entry.insert(KIO::UDSEntry::UDS_CREATION_TIME, dirent->createtime);
+ }
- sftp_attributes_free(dirent);
- listEntry(entry, false);
- } // for ever
- sftp_closedir(dp);
- listEntry(entry, true); // ready
+ sftp_attributes_free(dirent);
+ listEntry(entry, false);
+ } // for ever
+ sftp_closedir(dp);
+ listEntry(entry, true); // ready
- finished();
+ finished();
}
-void sftpProtocol::mkdir(const KUrl &url, int permissions) {
- kDebug(KIO_SFTP_DB) << "create directory: " << url;
+void sftpProtocol::mkdir(const KUrl &url, int permissions)
+{
+ kDebug(KIO_SFTP_DB) << "create directory: " << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- if (url.path().isEmpty()) {
- error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
- return;
- }
- const QString path = url.path();
- const QByteArray path_c = path.toUtf8();
+ if (url.path().isEmpty()) {
+ error(KIO::ERR_MALFORMED_URL, url.prettyUrl());
+ return;
+ }
+ const QString path = url.path();
+ const QByteArray path_c = path.toUtf8();
- // Remove existing file or symlink, if requested.
- if (metaData(QLatin1String("overwrite")) == QLatin1String("true")) {
- kDebug(KIO_SFTP_DB) << "overwrite set, remove existing file or symlink: " << url;
- sftp_unlink(mSftp, path_c.constData());
- }
+ // Remove existing file or symlink, if requested.
+ if (metaData(QLatin1String("overwrite")) == QLatin1String("true")) {
+ kDebug(KIO_SFTP_DB) << "overwrite set, remove existing file or symlink: " << url;
+ sftp_unlink(mSftp, path_c.constData());
+ }
- kDebug(KIO_SFTP_DB) << "Trying to create directory: " << path;
- sftp_attributes sb = sftp_lstat(mSftp, path_c.constData());
- if (sb == NULL) {
- if (sftp_mkdir(mSftp, path_c.constData(), 0777) < 0) {
- reportError(url, sftp_get_error(mSftp));
- sftp_attributes_free(sb);
- return;
- } else {
- kDebug(KIO_SFTP_DB) << "Successfully created directory: " << url;
- if (permissions != -1) {
- chmod(url, permissions);
- } else {
- finished();
- }
- sftp_attributes_free(sb);
- return;
+ kDebug(KIO_SFTP_DB) << "Trying to create directory: " << path;
+ sftp_attributes sb = sftp_lstat(mSftp, path_c.constData());
+ if (sb == NULL) {
+ if (sftp_mkdir(mSftp, path_c.constData(), 0777) < 0) {
+ reportError(url, sftp_get_error(mSftp));
+ sftp_attributes_free(sb);
+ return;
+ } else {
+ kDebug(KIO_SFTP_DB) << "Successfully created directory: " << url;
+ if (permissions != -1) {
+ chmod(url, permissions);
+ } else {
+ finished();
+ }
+ sftp_attributes_free(sb);
+ return;
+ }
}
- }
- if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
- error(KIO::ERR_DIR_ALREADY_EXIST, path);
- } else {
- error(KIO::ERR_FILE_ALREADY_EXIST, path);
- }
+ if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
+ error(KIO::ERR_DIR_ALREADY_EXIST, path);
+ } else {
+ error(KIO::ERR_FILE_ALREADY_EXIST, path);
+ }
- sftp_attributes_free(sb);
- return;
+ sftp_attributes_free(sb);
+ return;
}
-void sftpProtocol::rename(const KUrl& src, const KUrl& dest, KIO::JobFlags flags) {
- kDebug(KIO_SFTP_DB) << "rename " << src << " to " << dest << flags;
+void sftpProtocol::rename(const KUrl& src, const KUrl& dest, KIO::JobFlags flags)
+{
+ kDebug(KIO_SFTP_DB) << "rename " << src << " to " << dest << flags;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- QByteArray qsrc = src.path().toUtf8();
- QByteArray qdest = dest.path().toUtf8();
+ QByteArray qsrc = src.path().toUtf8();
+ QByteArray qdest = dest.path().toUtf8();
- sftp_attributes sb = sftp_lstat(mSftp, qdest.constData());
- if (sb != NULL) {
- if (!(flags & KIO::Overwrite)) {
- if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
- error(KIO::ERR_DIR_ALREADY_EXIST, dest.url());
- } else {
- error(KIO::ERR_FILE_ALREADY_EXIST, dest.url());
- }
- sftp_attributes_free(sb);
- return;
+ sftp_attributes sb = sftp_lstat(mSftp, qdest.constData());
+ if (sb != NULL) {
+ if (!(flags & KIO::Overwrite)) {
+ if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
+ error(KIO::ERR_DIR_ALREADY_EXIST, dest.url());
+ } else {
+ error(KIO::ERR_FILE_ALREADY_EXIST, dest.url());
+ }
+ sftp_attributes_free(sb);
+ return;
+ }
+
+ // Delete the existing destination file/dir...
+ if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
+ if (sftp_rmdir(mSftp, qdest.constData()) < 0) {
+ reportError(dest, sftp_get_error(mSftp));
+ return;
+ }
+ } else {
+ if (sftp_unlink(mSftp, qdest.constData()) < 0) {
+ reportError(dest, sftp_get_error(mSftp));
+ return;
+ }
+ }
}
+ sftp_attributes_free(sb);
- // Delete the existing destination file/dir...
- if (sb->type == SSH_FILEXFER_TYPE_DIRECTORY) {
- if (sftp_rmdir(mSftp, qdest.constData()) < 0) {
- reportError(dest, sftp_get_error(mSftp));
- return;
- }
- } else {
- if (sftp_unlink(mSftp, qdest.constData()) < 0) {
+ if (sftp_rename(mSftp, qsrc.constData(), qdest.constData()) < 0) {
reportError(dest, sftp_get_error(mSftp));
return;
- }
}
- }
- sftp_attributes_free(sb);
-
- if (sftp_rename(mSftp, qsrc.constData(), qdest.constData()) < 0) {
- reportError(dest, sftp_get_error(mSftp));
- return;
- }
- finished();
+ finished();
}
-void sftpProtocol::symlink(const QString &target, const KUrl &dest, KIO::JobFlags flags) {
- kDebug(KIO_SFTP_DB) << "link " << target << "->" << dest
- << ", overwrite = " << (flags & KIO::Overwrite)
- << ", resume = " << (flags & KIO::Resume);
+void sftpProtocol::symlink(const QString &target, const KUrl &dest, KIO::JobFlags flags)
+{
+ kDebug(KIO_SFTP_DB) << "link " << target << "->" << dest
+ << ", overwrite = " << (flags & KIO::Overwrite)
+ << ", resume = " << (flags & KIO::Resume);
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- QByteArray t = target.toUtf8();
- QByteArray d = dest.path().toUtf8();
-
- bool failed = false;
- if (sftp_symlink(mSftp, t.constData(), d.constData()) < 0) {
- if (flags == KIO::Overwrite) {
- sftp_attributes sb = sftp_lstat(mSftp, d.constData());
- if (sb == NULL) {
- failed = true;
- } else {
- if (sftp_unlink(mSftp, d.constData()) < 0) {
- failed = true;
- } else {
- if (sftp_symlink(mSftp, t.constData(), d.constData()) < 0) {
- failed = true;
- }
+ QByteArray t = target.toUtf8();
+ QByteArray d = dest.path().toUtf8();
+
+ bool failed = false;
+ if (sftp_symlink(mSftp, t.constData(), d.constData()) < 0) {
+ if (flags == KIO::Overwrite) {
+ sftp_attributes sb = sftp_lstat(mSftp, d.constData());
+ if (sb == NULL) {
+ failed = true;
+ } else {
+ if (sftp_unlink(mSftp, d.constData()) < 0) {
+ failed = true;
+ } else {
+ if (sftp_symlink(mSftp, t.constData(), d.constData()) < 0) {
+ failed = true;
+ }
+ }
+ }
+ sftp_attributes_free(sb);
}
- }
- sftp_attributes_free(sb);
}
- }
- if (failed) {
- reportError(dest, sftp_get_error(mSftp));
- return;
- }
+ if (failed) {
+ reportError(dest, sftp_get_error(mSftp));
+ return;
+ }
- finished();
+ finished();
}
-void sftpProtocol::chmod(const KUrl& url, int permissions) {
- kDebug(KIO_SFTP_DB) << "change permission of " << url << " to " << QString::number(permissions);
+void sftpProtocol::chmod(const KUrl& url, int permissions)
+{
+ kDebug(KIO_SFTP_DB) << "change permission of " << url << " to " << QString::number(permissions);
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- QByteArray path = url.path().toUtf8();
+ QByteArray path = url.path().toUtf8();
- if (sftp_chmod(mSftp, path.constData(), permissions) < 0) {
- reportError(url, sftp_get_error(mSftp));
- return;
- }
+ if (sftp_chmod(mSftp, path.constData(), permissions) < 0) {
+ reportError(url, sftp_get_error(mSftp));
+ return;
+ }
- finished();
+ finished();
}
-void sftpProtocol::del(const KUrl &url, bool isfile){
- kDebug(KIO_SFTP_DB) << "deleting " << (isfile ? "file: " : "directory: ") << url;
+void sftpProtocol::del(const KUrl &url, bool isfile)
+{
+ kDebug(KIO_SFTP_DB) << "deleting " << (isfile ? "file: " : "directory: ") << url;
- if (!sftpLogin()) {
- return;
- }
+ if (!sftpLogin()) {
+ return;
+ }
- QByteArray path = url.path().toUtf8();
+ QByteArray path = url.path().toUtf8();
- if (isfile) {
- if (sftp_unlink(mSftp, path.constData()) < 0) {
- reportError(url, sftp_get_error(mSftp));
- return;
- }
- } else {
- if (sftp_rmdir(mSftp, path.constData()) < 0) {
- reportError(url, sftp_get_error(mSftp));
- return;
+ if (isfile) {
+ if (sftp_unlink(mSftp, path.constData()) < 0) {
+ reportError(url, sftp_get_error(mSftp));
+ return;
+ }
+ } else {
+ if (sftp_rmdir(mSftp, path.constData()) < 0) {
+ reportError(url, sftp_get_error(mSftp));
+ return;
+ }
}
- }
- finished();
+ finished();
}
-void sftpProtocol::slave_status() {
- kDebug(KIO_SFTP_DB) << "connected to " << mHost << "?: " << mConnected;
- slaveStatus((mConnected ? mHost : QString()), mConnected);
+void sftpProtocol::slave_status()
+{
+ kDebug(KIO_SFTP_DB) << "connected to " << mHost << "?: " << mConnected;
+ slaveStatus((mConnected ? mHost : QString()), mConnected);
}
sftpProtocol::GetRequest::GetRequest(sftp_file file, sftp_attributes sb, ushort maxPendingRequests)
- :mFile(file), mSb(sb), mMaxPendingRequests(maxPendingRequests) {
-
+ : mFile(file), mSb(sb), mMaxPendingRequests(maxPendingRequests)
+{
}
-bool sftpProtocol::GetRequest::enqueueChunks() {
- sftpProtocol::GetRequest::Request request;
-
- kDebug(KIO_SFTP_DB) << "enqueueChunks";
-
- while (pendingRequests.count() < mMaxPendingRequests) {
- request.expectedLength = MAX_XFER_BUF_SIZE;
- request.startOffset = mFile->offset;
- request.id = sftp_async_read_begin(mFile, request.expectedLength);
- if (request.id < 0) {
- if (pendingRequests.isEmpty()) {
- return false;
- } else {
- break;
- }
- }
+bool sftpProtocol::GetRequest::enqueueChunks()
+{
+ sftpProtocol::GetRequest::Request request;
+
+ kDebug(KIO_SFTP_DB) << "enqueueChunks";
+
+ while (pendingRequests.count() < mMaxPendingRequests) {
+ request.expectedLength = MAX_XFER_BUF_SIZE;
+ request.startOffset = mFile->offset;
+ request.id = sftp_async_read_begin(mFile, request.expectedLength);
+ if (request.id < 0) {
+ if (pendingRequests.isEmpty()) {
+ return false;
+ } else {
+ break;
+ }
+ }
- pendingRequests.enqueue(request);
+ pendingRequests.enqueue(request);
- if (mFile->offset >= mSb->size) {
- // Do not add any more chunks if the offset is larger than the given file size.
- // However this is done after adding a request as the remote file size may
- // have changed in the meantime.
- break;
+ if (mFile->offset >= mSb->size) {
+ // Do not add any more chunks if the offset is larger than the given file size.
+ // However this is done after adding a request as the remote file size may
+ // have changed in the meantime.
+ break;
+ }
}
- }
- kDebug(KIO_SFTP_DB) << "enqueueChunks done" << QString::number(pendingRequests.size());
+ kDebug(KIO_SFTP_DB) << "enqueueChunks done" << QString::number(pendingRequests.size());
- return true;
+ return true;
}
-int sftpProtocol::GetRequest::readChunks(QByteArray &data) {
-
- int totalRead = 0;
- ssize_t bytesread = 0;
+int sftpProtocol::GetRequest::readChunks(QByteArray &data)
+{
+ int totalRead = 0;
+ ssize_t bytesread = 0;
+
+ while (!pendingRequests.isEmpty()) {
+ sftpProtocol::GetRequest::Request &request = pendingRequests.head();
+ int dataSize = data.size() + request.expectedLength;
+
+ data.resize(dataSize);
+ if (data.size() < dataSize) {
+ // Could not allocate enough memory - skip current chunk
+ data.resize(dataSize - request.expectedLength);
+ break;
+ }
- while (!pendingRequests.isEmpty()) {
- sftpProtocol::GetRequest::Request &request = pendingRequests.head();
- int dataSize = data.size() + request.expectedLength;
+ bytesread = sftp_async_read(mFile, data.data() + totalRead, request.expectedLength, request.id);
- data.resize(dataSize);
- if (data.size() < dataSize) {
- // Could not allocate enough memory - skip current chunk
- data.resize(dataSize - request.expectedLength);
- break;
- }
+ // kDebug(KIO_SFTP_DB) << "bytesread=" << QString::number(bytesread);
- bytesread = sftp_async_read(mFile, data.data() + totalRead, request.expectedLength, request.id);
+ if (bytesread == 0 || bytesread == SSH_AGAIN) {
+ // Done reading or timeout
+ data.resize(data.size() - request.expectedLength);
- // kDebug(KIO_SFTP_DB) << "bytesread=" << QString::number(bytesread);
-
- if (bytesread == 0 || bytesread == SSH_AGAIN) {
- // Done reading or timeout
- data.resize(data.size() - request.expectedLength);
+ if (bytesread == 0) {
+ pendingRequests.dequeue(); // This frees QByteArray &data!
+ }
- if (bytesread == 0) {
- pendingRequests.dequeue(); // This frees QByteArray &data!
- }
+ break;
+ } else if (bytesread == SSH_ERROR) {
+ return -1;
+ }
- break;
- } else if (bytesread == SSH_ERROR) {
- return -1;
- }
+ totalRead += bytesread;
- totalRead += bytesread;
+ if (bytesread < request.expectedLength) {
+ int rc;
- if (bytesread < request.expectedLength) {
- int rc;
+ // If less data is read than expected - requeue the request
+ data.resize(data.size() - (request.expectedLength - bytesread));
- // If less data is read than expected - requeue the request
- data.resize(data.size() - (request.expectedLength - bytesread));
+ // Modify current request
+ request.expectedLength -= bytesread;
+ request.startOffset += bytesread;
- // Modify current request
- request.expectedLength -= bytesread;
- request.startOffset += bytesread;
+ rc = sftp_seek64(mFile, request.startOffset);
+ if (rc < 0) {
+ // Failed to continue reading
+ return -1;
+ }
- rc = sftp_seek64(mFile, request.startOffset);
- if (rc < 0) {
- // Failed to continue reading
- return -1;
- }
+ request.id = sftp_async_read_begin(mFile, request.expectedLength);
- request.id = sftp_async_read_begin(mFile, request.expectedLength);
+ if (request.id < 0) {
+ // Failed to dispatch rerequest
+ return -1;
+ }
- if (request.id < 0) {
- // Failed to dispatch rerequest
- return -1;
- }
+ return totalRead;
+ }
- return totalRead;
+ pendingRequests.dequeue();
}
- pendingRequests.dequeue();
- }
-
- return totalRead;
+ return totalRead;
}
-sftpProtocol::GetRequest::~GetRequest() {
- sftpProtocol::GetRequest::Request request;
- char buf[MAX_XFER_BUF_SIZE];
+sftpProtocol::GetRequest::~GetRequest()
+{
+ sftpProtocol::GetRequest::Request request;
+ char buf[MAX_XFER_BUF_SIZE];
- // Remove pending reads to avoid memory leaks
- while (!pendingRequests.isEmpty()) {
- request = pendingRequests.dequeue();
- sftp_async_read(mFile, buf, request.expectedLength, request.id);
- }
+ // Remove pending reads to avoid memory leaks
+ while (!pendingRequests.isEmpty()) {
+ request = pendingRequests.dequeue();
+ sftp_async_read(mFile, buf, request.expectedLength, request.id);
+ }
- // Close channel & free attributes
- sftp_close(mFile);
- sftp_attributes_free(mSb);
+ // Close channel & free attributes
+ sftp_close(mFile);
+ sftp_attributes_free(mSb);
}
void sftpProtocol::requiresUserNameRedirection()
void sftpProtocol::sftpSendWarning(int errorCode, const QString& url)
{
- switch (errorCode) {
- case -1:
- warning(i18n( "Could not change permissions for\n%1", url));
- break;
- default:
- break;
- }
+ switch (errorCode) {
+ case -1: {
+ warning(i18n( "Could not change permissions for\n%1", url));
+ break;
+ }
+ default: {
+ break;
+ }
+ }
}
void sftpProtocol::clearPubKeyAuthInfo()
{
- if (mPublicKeyAuthInfo) {
- delete mPublicKeyAuthInfo;
- mPublicKeyAuthInfo = 0;
- }
+ if (mPublicKeyAuthInfo) {
+ delete mPublicKeyAuthInfo;
+ mPublicKeyAuthInfo = 0;
+ }
}