summaryrefslogtreecommitdiffstats
path: root/kioslave/sftp/kio_sftp.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kioslave/sftp/kio_sftp.cpp')
-rw-r--r--kioslave/sftp/kio_sftp.cpp2282
1 files changed, 0 insertions, 2282 deletions
diff --git a/kioslave/sftp/kio_sftp.cpp b/kioslave/sftp/kio_sftp.cpp
deleted file mode 100644
index 73f5bfc6d..000000000
--- a/kioslave/sftp/kio_sftp.cpp
+++ /dev/null
@@ -1,2282 +0,0 @@
-/***************************************************************************
- sftp.cpp - description
- -------------------
- begin : Fri Jun 29 23:45:40 CDT 2001
- copyright : (C) 2001 by Lucas Fisher
- email : ljfisher@purdue.edu
- ***************************************************************************/
-
-/***************************************************************************
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- ***************************************************************************/
-
-/*
-DEBUGGING
-We are pretty much left with kdDebug messages for debugging. We can't use a gdb
-as described in the ioslave DEBUG.howto because tdeinit has to run in a terminal.
-Ssh will detect this terminal and ask for a password there, but will just get garbage.
-So we can't connect.
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <fcntl.h>
-
-#include <tqcstring.h>
-#include <tqstring.h>
-#include <tqobject.h>
-#include <tqstrlist.h>
-#include <tqfile.h>
-#include <tqbuffer.h>
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <errno.h>
-#include <ctype.h>
-#include <time.h>
-#include <netdb.h>
-#include <string.h>
-
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/time.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-
-#include <kapplication.h>
-#include <kuser.h>
-#include <kdebug.h>
-#include <kmessagebox.h>
-#include <kinstance.h>
-#include <kglobal.h>
-#include <kstandarddirs.h>
-#include <klocale.h>
-#include <kurl.h>
-#include <kio/ioslave_defaults.h>
-#include <kmimetype.h>
-#include <kmimemagic.h>
-#include <klargefile.h>
-#include <kremoteencoding.h>
-
-#include "sftp.h"
-#include "kio_sftp.h"
-#include "atomicio.h"
-#include "sftpfileattr.h"
-#include "ksshprocess.h"
-
-
-using namespace TDEIO;
-extern "C"
-{
- int KDE_EXPORT kdemain( int argc, char **argv )
- {
- TDEInstance instance( "kio_sftp" );
-
- kdDebug(KIO_SFTP_DB) << "*** Starting kio_sftp " << endl;
-
- if (argc != 4) {
- kdDebug(KIO_SFTP_DB) << "Usage: kio_sftp protocol domain-socket1 domain-socket2" << endl;
- exit(-1);
- }
-
- sftpProtocol slave(argv[2], argv[3]);
- slave.dispatchLoop();
-
- kdDebug(KIO_SFTP_DB) << "*** kio_sftp Done" << endl;
- return 0;
- }
-}
-
-
-/*
- * This helper handles some special issues (blocking and interrupted
- * system call) when writing to a file handle.
- *
- * @return 0 on success or an error code on failure (ERR_COULD_NOT_WRITE,
- * ERR_DISK_FULL, ERR_CONNECTION_BROKEN).
- */
-static int writeToFile (int fd, const char *buf, size_t len)
-{
- while (len > 0)
- {
- ssize_t written = ::write(fd, buf, len);
- if (written >= 0)
- {
- buf += written;
- len -= written;
- continue;
- }
-
- switch(errno)
- {
- case EINTR:
- continue;
- case EPIPE:
- return ERR_CONNECTION_BROKEN;
- case ENOSPC:
- return ERR_DISK_FULL;
- default:
- return ERR_COULD_NOT_WRITE;
- }
- }
- return 0;
-}
-
-sftpProtocol::sftpProtocol(const TQCString &pool_socket, const TQCString &app_socket)
- : SlaveBase("kio_sftp", pool_socket, app_socket),
- mConnected(false), mPort(-1), mMsgId(0) {
- kdDebug(KIO_SFTP_DB) << "sftpProtocol(): pid = " << getpid() << endl;
-}
-
-
-sftpProtocol::~sftpProtocol() {
- kdDebug(KIO_SFTP_DB) << "~sftpProtocol(): pid = " << getpid() << endl;
- closeConnection();
-}
-
-/**
- * Type is a sftp packet type found in .sftp.h'.
- * Example: SSH2_FXP_READLINK, SSH2_FXP_RENAME, etc.
- *
- * Returns true if the type is supported by the sftp protocol
- * version negotiated by the client and server (sftpVersion).
- */
-bool sftpProtocol::isSupportedOperation(int type) {
- switch (type) {
- case SSH2_FXP_VERSION:
- case SSH2_FXP_STATUS:
- case SSH2_FXP_HANDLE:
- case SSH2_FXP_DATA:
- case SSH2_FXP_NAME:
- case SSH2_FXP_ATTRS:
- case SSH2_FXP_INIT:
- case SSH2_FXP_OPEN:
- case SSH2_FXP_CLOSE:
- case SSH2_FXP_READ:
- case SSH2_FXP_WRITE:
- case SSH2_FXP_LSTAT:
- case SSH2_FXP_FSTAT:
- case SSH2_FXP_SETSTAT:
- case SSH2_FXP_FSETSTAT:
- case SSH2_FXP_OPENDIR:
- case SSH2_FXP_READDIR:
- case SSH2_FXP_REMOVE:
- case SSH2_FXP_MKDIR:
- case SSH2_FXP_RMDIR:
- case SSH2_FXP_REALPATH:
- case SSH2_FXP_STAT:
- return true;
- case SSH2_FXP_RENAME:
- return sftpVersion >= 2 ? true : false;
- case SSH2_FXP_EXTENDED:
- case SSH2_FXP_EXTENDED_REPLY:
- case SSH2_FXP_READLINK:
- case SSH2_FXP_SYMLINK:
- return sftpVersion >= 3 ? true : false;
- default:
- kdDebug(KIO_SFTP_DB) << "isSupportedOperation(type:"
- << type << "): unrecognized operation type" << endl;
- break;
- }
-
- return false;
-}
-
-void sftpProtocol::copy(const KURL &src, const KURL &dest, int permissions, bool overwrite)
-{
- kdDebug(KIO_SFTP_DB) << "copy(): " << src << " -> " << dest << endl;
-
- bool srcLocal = src.isLocalFile();
- bool destLocal = dest.isLocalFile();
-
- if ( srcLocal && !destLocal ) // Copy file -> sftp
- sftpCopyPut(src, dest, permissions, overwrite);
- else if ( destLocal && !srcLocal ) // Copy sftp -> file
- sftpCopyGet(dest, src, permissions, overwrite);
- else
- error(ERR_UNSUPPORTED_ACTION, TQString::null);
-}
-
-void sftpProtocol::sftpCopyGet(const KURL& dest, const KURL& src, int mode, bool overwrite)
-{
- kdDebug(KIO_SFTP_DB) << "sftpCopyGet(): " << src << " -> " << dest << endl;
-
- // Attempt to establish a connection...
- openConnection();
- if( !mConnected )
- return;
-
- KDE_struct_stat buff_orig;
- TQCString dest_orig ( TQFile::encodeName(dest.path()) );
- bool origExists = (KDE_lstat( dest_orig.data(), &buff_orig ) != -1);
-
- if (origExists)
- {
- if (S_ISDIR(buff_orig.st_mode))
- {
- error(ERR_IS_DIRECTORY, dest.prettyURL());
- return;
- }
-
- if (!overwrite)
- {
- error(ERR_FILE_ALREADY_EXIST, dest.prettyURL());
- return;
- }
- }
-
- TDEIO::filesize_t offset = 0;
- TQCString dest_part ( dest_orig + ".part" );
-
- int fd = -1;
- bool partExists = false;
- bool markPartial = config()->readBoolEntry("MarkPartial", true);
-
- if (markPartial)
- {
- KDE_struct_stat buff_part;
- partExists = (KDE_stat( dest_part.data(), &buff_part ) != -1);
-
- if (partExists && buff_part.st_size > 0 && S_ISREG(buff_part.st_mode))
- {
- if (canResume( buff_part.st_size ))
- {
- offset = buff_part.st_size;
- kdDebug(KIO_SFTP_DB) << "sftpCopyGet: Resuming @ " << offset << endl;
- }
- }
-
- if (offset > 0)
- {
- fd = KDE_open(dest_part.data(), O_RDWR);
- offset = KDE_lseek(fd, 0, SEEK_END);
- if (offset == 0)
- {
- error(ERR_CANNOT_RESUME, dest.prettyURL());
- return;
- }
- }
- else
- {
- // Set up permissions properly, based on what is done in file io-slave
- int openFlags = (O_CREAT | O_TRUNC | O_WRONLY);
- int initialMode = (mode == -1) ? 0666 : (mode | S_IWUSR);
- fd = KDE_open(dest_part.data(), openFlags, initialMode);
- }
- }
- else
- {
- // Set up permissions properly, based on what is done in file io-slave
- int openFlags = (O_CREAT | O_TRUNC | O_WRONLY);
- int initialMode = (mode == -1) ? 0666 : (mode | S_IWUSR);
- fd = KDE_open(dest_orig.data(), openFlags, initialMode);
- }
-
- if(fd == -1)
- {
- kdDebug(KIO_SFTP_DB) << "sftpCopyGet: Unable to open (" << fd << ") for writting." << endl;
- if (errno == EACCES)
- error (ERR_WRITE_ACCESS_DENIED, dest.prettyURL());
- else
- error (ERR_CANNOT_OPEN_FOR_WRITING, dest.prettyURL());
- return;
- }
-
- Status info = sftpGet(src, offset, fd);
- if ( info.code != 0 )
- {
- // Should we keep the partially downloaded file ??
- TDEIO::filesize_t size = config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
- if (info.size < size)
- ::remove(dest_part.data());
-
- error(info.code, info.text);
- return;
- }
-
- if (::close(fd) != 0)
- {
- error(ERR_COULD_NOT_WRITE, dest.prettyURL());
- return;
- }
-
- //
- if (markPartial)
- {
- if (::rename(dest_part.data(), dest_orig.data()) != 0)
- {
- error (ERR_CANNOT_RENAME_PARTIAL, dest_part);
- return;
- }
- }
-
- data(TQByteArray());
- kdDebug(KIO_SFTP_DB) << "sftpCopyGet(): emit finished()" << endl;
- finished();
-}
-
-sftpProtocol::Status sftpProtocol::sftpGet( const KURL& src, TDEIO::filesize_t offset, int fd )
-{
- int code;
- sftpFileAttr attr(remoteEncoding());
-
- Status res;
- res.code = 0;
- res.size = 0;
-
- kdDebug(KIO_SFTP_DB) << "sftpGet(): " << src << endl;
-
- // stat the file first to get its size
- if( (code = sftpStat(src, attr)) != SSH2_FX_OK ) {
- return doProcessStatus(code, src.prettyURL());
- }
-
- // We cannot get file if it is a directory
- if( attr.fileType() == S_IFDIR ) {
- res.text = src.prettyURL();
- res.code = ERR_IS_DIRECTORY;
- return res;
- }
-
- TDEIO::filesize_t fileSize = attr.fileSize();
- TQ_UINT32 pflags = SSH2_FXF_READ;
- attr.clear();
-
- TQByteArray handle;
- if( (code = sftpOpen(src, pflags, attr, handle)) != SSH2_FX_OK ) {
- res.text = src.prettyURL();
- res.code = ERR_CANNOT_OPEN_FOR_READING;
- return res;
- }
-
- // needed for determining mimetype
- // note: have to emit mimetype before emitting totalsize.
- TQByteArray buff;
- TQByteArray mimeBuffer;
-
- unsigned int oldSize;
- bool foundMimetype = false;
-
- // How big should each data packet be? Definitely not bigger than 64kb or
- // you will overflow the 2 byte size variable in a sftp packet.
- TQ_UINT32 len = 60*1024;
- code = SSH2_FX_OK;
-
- kdDebug(KIO_SFTP_DB) << "sftpGet(): offset = " << offset << endl;
- while( code == SSH2_FX_OK ) {
- if( (code = sftpRead(handle, offset, len, buff)) == SSH2_FX_OK ) {
- offset += buff.size();
-
- // save data for mimetype. Pretty much follows what is in the ftp ioslave
- if( !foundMimetype ) {
- oldSize = mimeBuffer.size();
- mimeBuffer.resize(oldSize + buff.size());
- memcpy(mimeBuffer.data()+oldSize, buff.data(), buff.size());
-
- if( mimeBuffer.size() > 1024 || offset == fileSize ) {
- // determine mimetype
- KMimeMagicResult* result =
- KMimeMagic::self()->findBufferFileType(mimeBuffer, src.fileName());
- kdDebug(KIO_SFTP_DB) << "sftpGet(): mimetype is " <<
- result->mimeType() << endl;
- mimeType(result->mimeType());
-
- // Always send the total size after emitting mime-type...
- totalSize(fileSize);
-
- if (fd == -1)
- data(mimeBuffer);
- else
- {
- if ( (res.code=writeToFile(fd, mimeBuffer.data(), mimeBuffer.size())) != 0 )
- return res;
- }
-
- processedSize(mimeBuffer.size());
- mimeBuffer.resize(0);
- foundMimetype = true;
- }
- }
- else {
- if (fd == -1)
- data(buff);
- else
- {
- if ( (res.code= writeToFile(fd, buff.data(), buff.size())) != 0 )
- return res;
- }
- processedSize(offset);
- }
- }
-
- /*
- Check if slave was killed. According to slavebase.h we need to leave
- the slave methods as soon as possible if the slave is killed. This
- allows the slave to be cleaned up properly.
- */
- if( wasKilled() ) {
- res.text = i18n("An internal error occurred. Please retry the request again.");
- res.code = ERR_UNKNOWN;
- return res;
- }
- }
-
- if( code != SSH2_FX_EOF ) {
- res.text = src.prettyURL();
- res.code = ERR_COULD_NOT_READ; // return here or still send empty array to indicate end of read?
- }
-
- res.size = offset;
- sftpClose(handle);
- processedSize (offset);
- return res;
-}
-
-void sftpProtocol::get(const KURL& url) {
- kdDebug(KIO_SFTP_DB) << "get(): " << url << endl ;
-
- openConnection();
- if( !mConnected )
- return;
-
- // Get resume offset
- TQ_UINT64 offset = config()->readUnsignedLongNumEntry("resume");
- if( offset > 0 ) {
- canResume();
- kdDebug(KIO_SFTP_DB) << "get(): canResume(), offset = " << offset << endl;
- }
-
- Status info = sftpGet(url, offset);
-
- if (info.code != 0)
- {
- error(info.code, info.text);
- return;
- }
-
- data(TQByteArray());
- kdDebug(KIO_SFTP_DB) << "get(): emit finished()" << endl;
- finished();
-}
-
-
-void sftpProtocol::setHost (const TQString& h, int port, const TQString& user, const TQString& pass)
-{
- kdDebug(KIO_SFTP_DB) << "setHost(): " << user << "@" << h << ":" << port << endl;
-
- if( mHost != h || mPort != port || user != mUsername || mPassword != pass )
- closeConnection();
-
- mHost = h;
-
- if( port > 0 )
- mPort = port;
- else {
- mPort = -1;
- }
-
- mUsername = user;
- mPassword = pass;
-
- if (user.isEmpty())
- {
- KUser u;
- mUsername = u.loginName();
- }
-}
-
-
-void sftpProtocol::openConnection() {
-
- if(mConnected)
- return;
-
- kdDebug(KIO_SFTP_DB) << "openConnection(): " << mUsername << "@"
- << mHost << ":" << mPort << endl;
-
- infoMessage( i18n("Opening SFTP connection to host <b>%1:%2</b>").arg(mHost).arg(mPort));
-
- if( mHost.isEmpty() ) {
- kdDebug(KIO_SFTP_DB) << "openConnection(): Need hostname..." << endl;
- error(ERR_UNKNOWN_HOST, i18n("No hostname specified"));
- return;
- }
-
- ////////////////////////////////////////////////////////////////////////////
- // Setup AuthInfo for use with password caching and the
- // password dialog box.
- AuthInfo info;
- info.url.setProtocol("sftp");
- info.url.setHost(mHost);
- info.url.setPort(mPort);
- info.url.setUser(mUsername);
- info.caption = i18n("SFTP Login");
- info.comment = "sftp://" + mHost + ":" + TQString::number(mPort);
- info.commentLabel = i18n("site:");
- info.username = mUsername;
- info.keepPassword = true;
-
- ///////////////////////////////////////////////////////////////////////////
- // Check for cached authentication info if a username AND password were
- // not specified in setHost().
- if( mUsername.isEmpty() && mPassword.isEmpty() ) {
- kdDebug(KIO_SFTP_DB) << "openConnection(): checking cache "
- << "info.username = " << info.username
- << ", info.url = " << info.url.prettyURL() << endl;
-
- if( checkCachedAuthentication(info) ) {
- mUsername = info.username;
- mPassword = info.password;
- }
- }
-
- ///////////////////////////////////////////////////////////////////////////
- // Now setup our ssh options. If we found a cached username
- // and password we set the SSH_PASSWORD and SSH_USERNAME
- // options right away. Otherwise we wait. The other options are
- // necessary for running sftp over ssh.
- KSshProcess::SshOpt opt; // a ssh option, this can be reused
- KSshProcess::SshOptList opts; // list of SshOpts
- KSshProcess::SshOptListIterator passwdIt; // points to the opt in opts that specifies the password
- KSshProcess::SshOptListIterator usernameIt;
-
-// opt.opt = KSshProcess::SSH_VERBOSE;
-// opts.append(opt);
-// opts.append(opt);
-
- if( mPort != -1 ) {
- opt.opt = KSshProcess::SSH_PORT;
- opt.num = mPort;
- opts.append(opt);
- }
-
- opt.opt = KSshProcess::SSH_SUBSYSTEM;
- opt.str = "sftp";
- opts.append(opt);
-
- opt.opt = KSshProcess::SSH_FORWARDX11;
- opt.boolean = false;
- opts.append(opt);
-
- opt.opt = KSshProcess::SSH_FORWARDAGENT;
- opt.boolean = false;
- opts.append(opt);
-
- opt.opt = KSshProcess::SSH_PROTOCOL;
- opt.num = 2;
- opts.append(opt);
-
- opt.opt = KSshProcess::SSH_HOST;
- opt.str = mHost;
- opts.append(opt);
-
- opt.opt = KSshProcess::SSH_ESCAPE_CHAR;
- opt.num = -1; // don't use any escape character
- opts.append(opt);
-
- // set the username and password if we have them
- if( !mUsername.isEmpty() ) {
- opt.opt = KSshProcess::SSH_USERNAME;
- opt.str = mUsername;
- usernameIt = opts.append(opt);
- }
-
- if( !mPassword.isEmpty() ) {
- opt.opt = KSshProcess::SSH_PASSWD;
- opt.str = mPassword;
- passwdIt = opts.append(opt);
- }
-
- ssh.setOptions(opts);
- ssh.printArgs();
-
- ///////////////////////////////////////////////////////////////////////////
- // Start the ssh connection process.
- //
-
- int err; // error code from KSshProcess
- TQString msg; // msg for dialog box
- TQString caption; // dialog box caption
- bool firstTime = true;
- bool dlgResult;
-
- while( !(mConnected = ssh.connect()) ) {
- err = ssh.error();
- kdDebug(KIO_SFTP_DB) << "openConnection(): "
- "Got " << err << " from KSshProcess::connect()" << endl;
-
- switch(err) {
- case KSshProcess::ERR_NEED_PASSWD:
- case KSshProcess::ERR_NEED_PASSPHRASE:
- // At this point we know that either we didn't set
- // an username or password in the ssh options list,
- // or what we did pass did not work. Therefore we
- // must prompt the user.
- if( err == KSshProcess::ERR_NEED_PASSPHRASE )
- info.prompt = i18n("Please enter your username and key passphrase.");
- else
- info.prompt = i18n("Please enter your username and password.");
-
- kdDebug(KIO_SFTP_DB) << "openConnection(): info.username = " << info.username
- << ", info.url = " << info.url.prettyURL() << endl;
-
- if( firstTime )
- dlgResult = openPassDlg(info);
- else
- dlgResult = openPassDlg(info, i18n("Incorrect username or password"));
-
- if( dlgResult ) {
- if( info.username.isEmpty() || info.password.isEmpty() ) {
- error(ERR_COULD_NOT_AUTHENTICATE,
- i18n("Please enter a username and password"));
- continue;
- }
- }
- else {
- // user canceled or dialog failed to open
- error(ERR_USER_CANCELED, TQString::null);
- kdDebug(KIO_SFTP_DB) << "openConnection(): user canceled, dlgResult = " << dlgResult << endl;
- closeConnection();
- return;
- }
-
- firstTime = false;
-
- // Check if the username has changed. SSH only accepts
- // the username at startup. If the username has changed
- // we must disconnect ssh, change the SSH_USERNAME
- // option, and reset the option list. We will also set
- // the password option so the user is not prompted for
- // it again.
- if( mUsername != info.username ) {
- kdDebug(KIO_SFTP_DB) << "openConnection(): Username changed from "
- << mUsername << " to " << info.username << endl;
-
- ssh.disconnect();
-
- // if we haven't yet added the username
- // or password option to the ssh options list then
- // the iterators will be equal to the empty iterator.
- // Create the opts now and add them to the opt list.
- if( usernameIt == KSshProcess::SshOptListIterator() ) {
- kdDebug(KIO_SFTP_DB) << "openConnection(): "
- "Adding username to options list" << endl;
- opt.opt = KSshProcess::SSH_USERNAME;
- usernameIt = opts.append(opt);
- }
-
- if( passwdIt == KSshProcess::SshOptListIterator() ) {
- kdDebug(KIO_SFTP_DB) << "openConnection(): "
- "Adding password to options list" << endl;
- opt.opt = KSshProcess::SSH_PASSWD;
- passwdIt = opts.append(opt);
- }
-
- (*usernameIt).str = info.username;
- (*passwdIt).str = info.password;
- ssh.setOptions(opts);
- ssh.printArgs();
- }
- else { // just set the password
- ssh.setPassword(info.password);
- }
-
- mUsername = info.username;
- mPassword = info.password;
-
- break;
-
- case KSshProcess::ERR_NEW_HOST_KEY:
- caption = i18n("Warning: Cannot verify host's identity.");
- msg = ssh.errorMsg();
- if( KMessageBox::Yes != messageBox(WarningYesNo, msg, caption) ) {
- closeConnection();
- error(ERR_USER_CANCELED, TQString::null);
- return;
- }
- ssh.acceptHostKey(true);
- break;
-
- case KSshProcess::ERR_DIFF_HOST_KEY:
- caption = i18n("Warning: Host's identity changed.");
- msg = ssh.errorMsg();
- if( KMessageBox::Yes != messageBox(WarningYesNo, msg, caption) ) {
- closeConnection();
- error(ERR_USER_CANCELED, TQString::null);
- return;
- }
- ssh.acceptHostKey(true);
- break;
-
- case KSshProcess::ERR_AUTH_FAILED:
- infoMessage(i18n("Authentication failed."));
- error(ERR_COULD_NOT_LOGIN, i18n("Authentication failed."));
- return;
-
- case KSshProcess::ERR_AUTH_FAILED_NEW_KEY:
- msg = ssh.errorMsg();
- error(ERR_COULD_NOT_LOGIN, msg);
- return;
-
- case KSshProcess::ERR_AUTH_FAILED_DIFF_KEY:
- msg = ssh.errorMsg();
- error(ERR_COULD_NOT_LOGIN, msg);
- return;
-
- case KSshProcess::ERR_CLOSED_BY_REMOTE_HOST:
- infoMessage(i18n("Connection failed."));
- caption = i18n("Connection closed by remote host.");
- msg = ssh.errorMsg();
- messageBox(Information, msg, caption);
- closeConnection();
- error(ERR_COULD_NOT_LOGIN, msg);
- return;
-
- case KSshProcess::ERR_INTERACT:
- case KSshProcess::ERR_INTERNAL:
- case KSshProcess::ERR_UNKNOWN:
- case KSshProcess::ERR_INVALID_STATE:
- case KSshProcess::ERR_CANNOT_LAUNCH:
- case KSshProcess::ERR_HOST_KEY_REJECTED:
- default:
- infoMessage(i18n("Connection failed."));
- caption = i18n("Unexpected SFTP error: %1").arg(err);
- msg = ssh.errorMsg();
- messageBox(Information, msg, caption);
- closeConnection();
- error(ERR_UNKNOWN, msg);
- return;
- }
- }
-
- // catch all in case we did something wrong above
- if( !mConnected ) {
- error(ERR_INTERNAL, TQString::null);
- return;
- }
-
- // Now send init packet.
- kdDebug(KIO_SFTP_DB) << "openConnection(): Sending SSH2_FXP_INIT packet." << endl;
- TQByteArray p;
- TQDataStream packet(p, IO_WriteOnly);
- packet << (TQ_UINT32)5; // packet length
- packet << (TQ_UINT8) SSH2_FXP_INIT; // packet type
- packet << (TQ_UINT32)SSH2_FILEXFER_VERSION; // client version
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream s(p, IO_ReadOnly);
- TQ_UINT32 version;
- TQ_UINT8 type;
- s >> type;
- kdDebug(KIO_SFTP_DB) << "openConnection(): Got type " << type << endl;
-
- if( type == SSH2_FXP_VERSION ) {
- s >> version;
- kdDebug(KIO_SFTP_DB) << "openConnection(): Got server version " << version << endl;
-
- // XXX Get extensions here
- sftpVersion = version;
-
- /* Server should return lowest common version supported by
- * client and server, but double check just in case.
- */
- if( sftpVersion > SSH2_FILEXFER_VERSION ) {
- error(ERR_UNSUPPORTED_PROTOCOL,
- i18n("SFTP version %1").arg(version));
- closeConnection();
- return;
- }
- }
- else {
- error(ERR_UNKNOWN, i18n("Protocol error."));
- closeConnection();
- return;
- }
-
- // Login succeeded!
- infoMessage(i18n("Successfully connected to %1").arg(mHost));
- info.url.setProtocol("sftp");
- info.url.setHost(mHost);
- info.url.setPort(mPort);
- info.url.setUser(mUsername);
- info.username = mUsername;
- info.password = mPassword;
- kdDebug(KIO_SFTP_DB) << "sftpProtocol(): caching info.username = " << info.username <<
- ", info.url = " << info.url.prettyURL() << endl;
- cacheAuthentication(info);
- mConnected = true;
- connected();
-
- mPassword.fill('x');
- info.password.fill('x');
-
- return;
-}
-
-void sftpProtocol::closeConnection() {
- kdDebug(KIO_SFTP_DB) << "closeConnection()" << endl;
- ssh.disconnect();
- mConnected = false;
-}
-
-void sftpProtocol::sftpCopyPut(const KURL& src, const KURL& dest, int permissions, bool overwrite) {
-
- KDE_struct_stat buff;
- TQCString file (TQFile::encodeName(src.path()));
-
- if (KDE_lstat(file.data(), &buff) == -1) {
- error (ERR_DOES_NOT_EXIST, src.prettyURL());
- return;
- }
-
- if (S_ISDIR (buff.st_mode)) {
- error (ERR_IS_DIRECTORY, src.prettyURL());
- return;
- }
-
- int fd = KDE_open (file.data(), O_RDONLY);
- if (fd == -1) {
- error (ERR_CANNOT_OPEN_FOR_READING, src.prettyURL());
- return;
- }
-
- totalSize (buff.st_size);
-
- sftpPut (dest, permissions, false, overwrite, fd);
-
- // Close the file descriptor...
- ::close( fd );
-}
-
-void sftpProtocol::sftpPut( const KURL& dest, int permissions, bool resume, bool overwrite, int fd ) {
-
- openConnection();
- if( !mConnected )
- return;
-
- kdDebug(KIO_SFTP_DB) << "sftpPut(): " << dest
- << ", resume=" << resume
- << ", overwrite=" << overwrite << endl;
-
- KURL origUrl( dest );
- sftpFileAttr origAttr(remoteEncoding());
- bool origExists = false;
-
- // Stat original (without part ext) to see if it already exists
- int code = sftpStat(origUrl, origAttr);
-
- if( code == SSH2_FX_OK ) {
- kdDebug(KIO_SFTP_DB) << "sftpPut(): <file> already exists" << endl;
-
- // Delete remote file if its size is zero
- if( origAttr.fileSize() == 0 ) {
- if( sftpRemove(origUrl, true) != SSH2_FX_OK ) {
- error(ERR_CANNOT_DELETE_ORIGINAL, origUrl.prettyURL());
- return;
- }
- }
- else {
- origExists = true;
- }
- }
- else if( code != SSH2_FX_NO_SUCH_FILE ) {
- processStatus(code, origUrl.prettyURL());
- return;
- }
-
- // Do not waste time/resources with more remote stat calls if the file exists
- // and we weren't instructed to overwrite it...
- if( origExists && !overwrite ) {
- error(ERR_FILE_ALREADY_EXIST, origUrl.prettyURL());
- return;
- }
-
- // Stat file with part ext to see if it already exists...
- KURL partUrl( origUrl );
- partUrl.setFileName( partUrl.fileName() + ".part" );
-
- TQ_UINT64 offset = 0;
- bool partExists = false;
- bool markPartial = config()->readBoolEntry("MarkPartial", true);
-
- if( markPartial ) {
-
- sftpFileAttr partAttr(remoteEncoding());
- code = sftpStat(partUrl, partAttr);
-
- if( code == SSH2_FX_OK ) {
- kdDebug(KIO_SFTP_DB) << "sftpPut(): .part file already exists" << endl;
- partExists = true;
- offset = partAttr.fileSize();
-
- // If for some reason, both the original and partial files exist,
- // skip resumption just like we would if the size of the partial
- // file is zero...
- if( origExists || offset == 0 )
- {
- if( sftpRemove(partUrl, true) != SSH2_FX_OK ) {
- error(ERR_CANNOT_DELETE_PARTIAL, partUrl.prettyURL());
- return;
- }
-
- if( sftpRename(origUrl, partUrl) != SSH2_FX_OK ) {
- error(ERR_CANNOT_RENAME_ORIGINAL, origUrl.prettyURL());
- return;
- }
-
- offset = 0;
- }
- else if( !overwrite && !resume ) {
- if (fd != -1)
- resume = (KDE_lseek(fd, offset, SEEK_SET) != -1);
- else
- resume = canResume( offset );
-
- kdDebug(KIO_SFTP_DB) << "sftpPut(): can resume = " << resume
- << ", offset = " << offset;
-
- if( !resume ) {
- error(ERR_FILE_ALREADY_EXIST, partUrl.prettyURL());
- return;
- }
- }
- else {
- offset = 0;
- }
- }
- else if( code == SSH2_FX_NO_SUCH_FILE ) {
- if( origExists && sftpRename(origUrl, partUrl) != SSH2_FX_OK ) {
- error(ERR_CANNOT_RENAME_ORIGINAL, origUrl.prettyURL());
- return;
- }
- }
- else {
- processStatus(code, partUrl.prettyURL());
- return;
- }
- }
-
- // Determine the url we will actually write to...
- KURL writeUrl (markPartial ? partUrl:origUrl);
-
- TQ_UINT32 pflags = 0;
- if( overwrite && !resume )
- pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_TRUNC;
- else if( !overwrite && !resume )
- pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_EXCL;
- else if( overwrite && resume )
- pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT;
- else if( !overwrite && resume )
- pflags = SSH2_FXF_WRITE | SSH2_FXF_CREAT | SSH2_FXF_APPEND;
-
- sftpFileAttr attr(remoteEncoding());
- TQByteArray handle;
-
- // Set the permissions of the file we write to if it didn't already exist
- // and the permission info is supplied, i.e it is not -1
- if( !partExists && !origExists && permissions != -1)
- attr.setPermissions(permissions);
-
- code = sftpOpen( writeUrl, pflags, attr, handle );
- if( code != SSH2_FX_OK ) {
-
- // Rename the file back to its original name if a
- // put fails due to permissions problems...
- if( markPartial && overwrite ) {
- (void) sftpRename(partUrl, origUrl);
- writeUrl = origUrl;
- }
-
- if( code == SSH2_FX_FAILURE ) { // assume failure means file exists
- error(ERR_FILE_ALREADY_EXIST, writeUrl.prettyURL());
- return;
- }
- else {
- processStatus(code, writeUrl.prettyURL());
- return;
- }
- }
-
- long nbytes;
- TQByteArray buff;
-
- do {
-
- if( fd != -1 ) {
- buff.resize( 16*1024 );
- if ( (nbytes = ::read(fd, buff.data(), buff.size())) > -1 )
- buff.resize( nbytes );
- }
- else {
- dataReq();
- nbytes = readData( buff );
- }
-
- if( nbytes >= 0 ) {
- if( (code = sftpWrite(handle, offset, buff)) != SSH2_FX_OK ) {
- error(ERR_COULD_NOT_WRITE, dest.prettyURL());
- return;
- }
-
- offset += nbytes;
- processedSize(offset);
-
- /* Check if slave was killed. According to slavebase.h we
- * need to leave the slave methods as soon as possible if
- * the slave is killed. This allows the slave to be cleaned
- * up properly.
- */
- if( wasKilled() ) {
- sftpClose(handle);
- closeConnection();
- error(ERR_UNKNOWN, i18n("An internal error occurred. Please try again."));
- return;
- }
- }
-
- } while( nbytes > 0 );
-
- if( nbytes < 0 ) {
- sftpClose(handle);
-
- if( markPartial ) {
- // Remove remote file if it smaller than our keep size
- uint minKeepSize = config()->readNumEntry("MinimumKeepSize", DEFAULT_MINIMUM_KEEP_SIZE);
-
- if( sftpStat(writeUrl, attr) == SSH2_FX_OK ) {
- if( attr.fileSize() < minKeepSize ) {
- sftpRemove(writeUrl, true);
- }
- }
- }
-
- error( ERR_UNKNOWN, i18n("Unknown error was encountered while copying the file "
- "to '%1'. Please try again.").arg(dest.host()) );
- return;
- }
-
- if( (code = sftpClose(handle)) != SSH2_FX_OK ) {
- error(ERR_COULD_NOT_WRITE, writeUrl.prettyURL());
- return;
- }
-
- // If wrote to a partial file, then remove the part ext
- if( markPartial ) {
- if( sftpRename(partUrl, origUrl) != SSH2_FX_OK ) {
- error(ERR_CANNOT_RENAME_PARTIAL, origUrl.prettyURL());
- return;
- }
- }
-
- finished();
-}
-
-void sftpProtocol::put ( const KURL& url, int permissions, bool overwrite, bool resume ){
- kdDebug(KIO_SFTP_DB) << "put(): " << url << ", overwrite = " << overwrite
- << ", resume = " << resume << endl;
-
- sftpPut( url, permissions, resume, overwrite );
-}
-
-void sftpProtocol::stat ( const KURL& url ){
- kdDebug(KIO_SFTP_DB) << "stat(): " << url << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- // If the stat URL has no path, do not attempt to determine the real
- // path and do a redirect. KRun will simply ignore such requests.
- // Instead, simply return the mime-type as a directory...
- if( !url.hasPath() ) {
- UDSEntry entry;
- UDSAtom atom;
-
- atom.m_uds = TDEIO::UDS_NAME;
- atom.m_str = TQString::null;
- entry.append( atom );
-
- atom.m_uds = TDEIO::UDS_FILE_TYPE;
- atom.m_long = S_IFDIR;
- entry.append( atom );
-
- atom.m_uds = TDEIO::UDS_ACCESS;
- atom.m_long = S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
- entry.append( atom );
-
- atom.m_uds = TDEIO::UDS_USER;
- atom.m_str = mUsername;
- entry.append( atom );
- atom.m_uds = TDEIO::UDS_GROUP;
- entry.append( atom );
-
- // no size
- statEntry( entry );
- finished();
- return;
- }
-
- int code;
- sftpFileAttr attr(remoteEncoding());
- if( (code = sftpStat(url, attr)) != SSH2_FX_OK ) {
- processStatus(code, url.prettyURL());
- return;
- }
- else {
- //kdDebug() << "We sent and received stat packet ok" << endl;
- attr.setFilename(url.fileName());
- statEntry(attr.entry());
- }
-
- finished();
-
- kdDebug(KIO_SFTP_DB) << "stat: END" << endl;
- return;
-}
-
-
-void sftpProtocol::mimetype ( const KURL& url ){
- kdDebug(KIO_SFTP_DB) << "mimetype(): " << url << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- TQ_UINT32 pflags = SSH2_FXF_READ;
- TQByteArray handle, mydata;
- sftpFileAttr attr(remoteEncoding());
- int code;
- if( (code = sftpOpen(url, pflags, attr, handle)) != SSH2_FX_OK ) {
- error(ERR_CANNOT_OPEN_FOR_READING, url.prettyURL());
- return;
- }
-
- TQ_UINT32 len = 1024; // Get first 1k for determining mimetype
- TQ_UINT64 offset = 0;
- code = SSH2_FX_OK;
- while( offset < len && code == SSH2_FX_OK ) {
- if( (code = sftpRead(handle, offset, len, mydata)) == SSH2_FX_OK ) {
- data(mydata);
- offset += mydata.size();
- processedSize(offset);
-
- kdDebug(KIO_SFTP_DB) << "mimetype(): offset = " << offset << endl;
- }
- }
-
-
- data(TQByteArray());
- processedSize(offset);
- sftpClose(handle);
- finished();
- kdDebug(KIO_SFTP_DB) << "mimetype(): END" << endl;
-}
-
-
-void sftpProtocol::listDir(const KURL& url) {
- kdDebug(KIO_SFTP_DB) << "listDir(): " << url << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- if( !url.hasPath() ) {
- KURL newUrl ( url );
- if( sftpRealPath(url, newUrl) == SSH2_FX_OK ) {
- kdDebug(KIO_SFTP_DB) << "listDir: Redirecting to " << newUrl << endl;
- redirection(newUrl);
- finished();
- return;
- }
- }
-
- int code;
- TQByteArray handle;
-
- if( (code = sftpOpenDirectory(url, handle)) != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "listDir(): open directory failed" << endl;
- processStatus(code, url.prettyURL());
- return;
- }
-
-
- code = SSH2_FX_OK;
- while( code == SSH2_FX_OK ) {
- code = sftpReadDir(handle, url);
- if( code != SSH2_FX_OK && code != SSH2_FX_EOF )
- processStatus(code, url.prettyURL());
- kdDebug(KIO_SFTP_DB) << "listDir(): return code = " << code << endl;
- }
-
- if( (code = sftpClose(handle)) != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "listdir(): closing of directory failed" << endl;
- processStatus(code, url.prettyURL());
- return;
- }
-
- finished();
- kdDebug(KIO_SFTP_DB) << "listDir(): END" << endl;
-}
-
-/** Make a directory.
- OpenSSH does not follow the internet draft for sftp in this case.
- The format of the mkdir request expected by OpenSSH sftp server is:
- uint32 id
- string path
- ATTR attr
- */
-void sftpProtocol::mkdir(const KURL&url, int permissions){
-
- kdDebug(KIO_SFTP_DB) << "mkdir() creating dir: " << url.path() << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- sftpFileAttr attr(remoteEncoding());
-
- if (permissions != -1)
- attr.setPermissions(permissions);
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << TQ_UINT32(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len + attr.size());
- s << (TQ_UINT8)SSH2_FXP_MKDIR;
- s << id;
- s.writeBytes(path.data(), len);
- s << attr;
-
- kdDebug(KIO_SFTP_DB) << "mkdir(): packet size is " << p.size() << endl;
-
- putPacket(p);
- getPacket(p);
-
- TQ_UINT8 type;
- TQDataStream r(p, IO_ReadOnly);
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "mkdir: sftp packet id mismatch" << endl;
- error(ERR_COULD_NOT_MKDIR, path);
- finished();
- return;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "mkdir(): unexpected packet type of " << type << endl;
- error(ERR_COULD_NOT_MKDIR, path);
- finished();
- return;
- }
-
- int code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "mkdir(): failed with code " << code << endl;
-
- // Check if mkdir failed because the directory already exists so that
- // we can return the appropriate message...
- sftpFileAttr dirAttr(remoteEncoding());
- if ( sftpStat(url, dirAttr) == SSH2_FX_OK )
- {
- error( ERR_DIR_ALREADY_EXIST, url.prettyURL() );
- return;
- }
-
- error(ERR_COULD_NOT_MKDIR, path);
- }
-
- finished();
-}
-
-void sftpProtocol::rename(const KURL& src, const KURL& dest, bool overwrite){
- kdDebug(KIO_SFTP_DB) << "rename(" << src << " -> " << dest << ")" << endl;
-
- if (!isSupportedOperation(SSH2_FXP_RENAME)) {
- error(ERR_UNSUPPORTED_ACTION,
- i18n("The remote host does not support renaming files."));
- return;
- }
-
- openConnection();
- if( !mConnected )
- return;
-
- // Always stat the destination before attempting to rename
- // a file or a directory...
- sftpFileAttr attr(remoteEncoding());
- int code = sftpStat(dest, attr);
-
- // If the destination directory, exists tell it to the job
- // so it the proper action can be presented to the user...
- if( code == SSH2_FX_OK )
- {
- if (!overwrite)
- {
- if ( S_ISDIR(attr.permissions()) )
- error( TDEIO::ERR_DIR_ALREADY_EXIST, dest.url() );
- else
- error( TDEIO::ERR_FILE_ALREADY_EXIST, dest.url() );
- return;
- }
-
- // If overwrite is specified, then simply remove the existing file/dir first...
- if( (code = sftpRemove( dest, !S_ISDIR(attr.permissions()) )) != SSH2_FX_OK )
- {
- processStatus(code);
- return;
- }
- }
-
- // Do the renaming...
- if( (code = sftpRename(src, dest)) != SSH2_FX_OK ) {
- processStatus(code);
- return;
- }
-
- finished();
- kdDebug(KIO_SFTP_DB) << "rename(): END" << endl;
-}
-
-void sftpProtocol::symlink(const TQString& target, const KURL& dest, bool overwrite){
- kdDebug(KIO_SFTP_DB) << "symlink()" << endl;
-
- if (!isSupportedOperation(SSH2_FXP_SYMLINK)) {
- error(ERR_UNSUPPORTED_ACTION,
- i18n("The remote host does not support creating symbolic links."));
- return;
- }
-
- openConnection();
- if( !mConnected )
- return;
-
- int code;
- bool failed = false;
- if( (code = sftpSymLink(target, dest)) != SSH2_FX_OK ) {
- if( overwrite ) { // try to delete the destination
- sftpFileAttr attr(remoteEncoding());
- if( (code = sftpStat(dest, attr)) != SSH2_FX_OK ) {
- failed = true;
- }
- else {
- if( (code = sftpRemove(dest, !S_ISDIR(attr.permissions())) ) != SSH2_FX_OK ) {
- failed = true;
- }
- else {
- // XXX what if rename fails again? We have lost the file.
- // Maybe rename dest to a temporary name first? If rename is
- // successful, then delete?
- if( (code = sftpSymLink(target, dest)) != SSH2_FX_OK )
- failed = true;
- }
- }
- }
- else if( code == SSH2_FX_FAILURE ) {
- error(ERR_FILE_ALREADY_EXIST, dest.prettyURL());
- return;
- }
- else
- failed = true;
- }
-
- // What error code do we return? Code for the original symlink command
- // or for the last command or for both? The second one is implemented here.
- if( failed )
- processStatus(code);
-
- finished();
-}
-
-void sftpProtocol::chmod(const KURL& url, int permissions){
- TQString perms;
- perms.setNum(permissions, 8);
- kdDebug(KIO_SFTP_DB) << "chmod(" << url << ", " << perms << ")" << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- sftpFileAttr attr(remoteEncoding());
-
- if (permissions != -1)
- attr.setPermissions(permissions);
-
- int code;
- if( (code = sftpSetStat(url, attr)) != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "chmod(): sftpSetStat failed with error " << code << endl;
- if( code == SSH2_FX_FAILURE )
- error(ERR_CANNOT_CHMOD, TQString::null);
- else
- processStatus(code, url.prettyURL());
- }
- finished();
-}
-
-
-void sftpProtocol::del(const KURL &url, bool isfile){
- kdDebug(KIO_SFTP_DB) << "del(" << url << ", " << (isfile?"file":"dir") << ")" << endl;
-
- openConnection();
- if( !mConnected )
- return;
-
- int code;
- if( (code = sftpRemove(url, isfile)) != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "del(): sftpRemove failed with error code " << code << endl;
- processStatus(code, url.prettyURL());
- }
- finished();
-}
-
-void sftpProtocol::slave_status() {
- kdDebug(KIO_SFTP_DB) << "slave_status(): connected to "
- << mHost << "? " << mConnected << endl;
-
- slaveStatus ((mConnected ? mHost : TQString::null), mConnected);
-}
-
-bool sftpProtocol::getPacket(TQByteArray& msg) {
- TQByteArray buf(4096);
-
- // Get the message length...
- ssize_t len = atomicio(ssh.stdioFd(), buf.data(), 4, true /*read*/);
-
- if( len == 0 || len == -1 ) {
- kdDebug(KIO_SFTP_DB) << "getPacket(): read of packet length failed, ret = "
- << len << ", error =" << strerror(errno) << endl;
- closeConnection();
- error( ERR_CONNECTION_BROKEN, mHost);
- msg.resize(0);
- return false;
- }
-
- uint msgLen;
- TQDataStream s(buf, IO_ReadOnly);
- s >> msgLen;
-
- //kdDebug(KIO_SFTP_DB) << "getPacket(): Message size = " << msgLen << endl;
-
- msg.resize(0);
-
- TQBuffer b( msg );
- b.open( IO_WriteOnly );
-
- while( msgLen ) {
- len = atomicio(ssh.stdioFd(), buf.data(), kMin((uint)buf.size(), msgLen), true /*read*/);
-
- if( len == 0 || len == -1) {
- TQString errmsg;
- if (len == 0)
- errmsg = i18n("Connection closed");
- else
- errmsg = i18n("Could not read SFTP packet");
- kdDebug(KIO_SFTP_DB) << "getPacket(): nothing to read, ret = " <<
- len << ", error =" << strerror(errno) << endl;
- closeConnection();
- error(ERR_CONNECTION_BROKEN, errmsg);
- b.close();
- return false;
- }
-
- b.writeBlock(buf.data(), len);
-
- //kdDebug(KIO_SFTP_DB) << "getPacket(): Read Message size = " << len << endl;
- //kdDebug(KIO_SFTP_DB) << "getPacket(): Copy Message size = " << msg.size() << endl;
-
- msgLen -= len;
- }
-
- b.close();
-
- return true;
-}
-
-/** Send an sftp packet to stdin of the ssh process. */
-bool sftpProtocol::putPacket(TQByteArray& p){
-// kdDebug(KIO_SFTP_DB) << "putPacket(): size == " << p.size() << endl;
- int ret;
- ret = atomicio(ssh.stdioFd(), p.data(), p.size(), false /*write*/);
- if( ret <= 0 ) {
- kdDebug(KIO_SFTP_DB) << "putPacket(): write failed, ret =" << ret <<
- ", error = " << strerror(errno) << endl;
- return false;
- }
-
- return true;
-}
-
-/** Used to have the server canonicalize any given path name to an absolute path.
-This is useful for converting path names containing ".." components or relative
-pathnames without a leading slash into absolute paths.
-Returns the canonicalized url. */
-int sftpProtocol::sftpRealPath(const KURL& url, KURL& newUrl){
-
- kdDebug(KIO_SFTP_DB) << "sftpRealPath(" << url << ", newUrl)" << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << TQ_UINT32(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len);
- s << (TQ_UINT8)SSH2_FXP_REALPATH;
- s << id;
- s.writeBytes(path.data(), len);
-
- putPacket(p);
- getPacket(p);
-
- TQ_UINT8 type;
- TQDataStream r(p, IO_ReadOnly);
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpRealPath: sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 code;
- r >> code;
- return code;
- }
-
- if( type != SSH2_FXP_NAME ) {
- kdError(KIO_SFTP_DB) << "sftpRealPath(): unexpected packet type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 count;
- r >> count;
- if( count != 1 ) {
- kdError(KIO_SFTP_DB) << "sftpRealPath(): Bad number of file attributes for realpath command" << endl;
- return -1;
- }
-
- TQCString newPath;
- r >> newPath;
-
- newPath.truncate(newPath.size());
- if (newPath.isEmpty())
- newPath = "/";
- newUrl.setPath(newPath);
-
- return SSH2_FX_OK;
-}
-
-sftpProtocol::Status sftpProtocol::doProcessStatus(TQ_UINT8 code, const TQString& message)
-{
- Status res;
- res.code = 0;
- res.size = 0;
- res.text = message;
-
- switch(code)
- {
- case SSH2_FX_OK:
- case SSH2_FX_EOF:
- break;
- case SSH2_FX_NO_SUCH_FILE:
- res.code = ERR_DOES_NOT_EXIST;
- break;
- case SSH2_FX_PERMISSION_DENIED:
- res.code = ERR_ACCESS_DENIED;
- break;
- case SSH2_FX_FAILURE:
- res.text = i18n("SFTP command failed for an unknown reason.");
- res.code = ERR_UNKNOWN;
- break;
- case SSH2_FX_BAD_MESSAGE:
- res.text = i18n("The SFTP server received a bad message.");
- res.code = ERR_UNKNOWN;
- break;
- case SSH2_FX_OP_UNSUPPORTED:
- res.text = i18n("You attempted an operation unsupported by the SFTP server.");
- res.code = ERR_UNKNOWN;
- break;
- default:
- res.text = i18n("Error code: %1").arg(code);
- res.code = ERR_UNKNOWN;
- }
-
- return res;
-}
-
-/** Process SSH_FXP_STATUS packets. */
-void sftpProtocol::processStatus(TQ_UINT8 code, const TQString& message){
- Status st = doProcessStatus( code, message );
- if( st.code != 0 )
- error( st.code, st.text );
-}
-
-/** Opens a directory handle for url.path. Returns true if succeeds. */
-int sftpProtocol::sftpOpenDirectory(const KURL& url, TQByteArray& handle){
-
- kdDebug(KIO_SFTP_DB) << "sftpOpenDirectory(" << url << ", handle)" << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len);
- s << (TQ_UINT8)SSH2_FXP_OPENDIR;
- s << (TQ_UINT32)id;
- s.writeBytes(path.data(), len);
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpOpenDirectory: sftp packet id mismatch: " <<
- "expected " << expectedId << ", got " << id << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 errCode;
- r >> errCode;
- return errCode;
- }
-
- if( type != SSH2_FXP_HANDLE ) {
- kdError(KIO_SFTP_DB) << "sftpOpenDirectory: unexpected message type of " << type << endl;
- return -1;
- }
-
- r >> handle;
- if( handle.size() > 256 ) {
- kdError(KIO_SFTP_DB) << "sftpOpenDirectory: handle exceeds max length" << endl;
- return -1;
- }
-
- kdDebug(KIO_SFTP_DB) << "sftpOpenDirectory: handle (" << handle.size() << "): [" << handle << "]" << endl;
- return SSH2_FX_OK;
-}
-
-/** Closes a directory or file handle. */
-int sftpProtocol::sftpClose(const TQByteArray& handle){
-
- kdDebug(KIO_SFTP_DB) << "sftpClose()" << endl;
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + handle.size());
- s << (TQ_UINT8)SSH2_FXP_CLOSE;
- s << (TQ_UINT32)id;
- s << handle;
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpClose: sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "sftpClose: unexpected message type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "sftpClose: close failed with err code " << code << endl;
- }
-
- return code;
-}
-
-/** Set a files attributes. */
-int sftpProtocol::sftpSetStat(const KURL& url, const sftpFileAttr& attr){
-
- kdDebug(KIO_SFTP_DB) << "sftpSetStat(" << url << ", attr)" << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len + attr.size());
- s << (TQ_UINT8)SSH2_FXP_SETSTAT;
- s << (TQ_UINT32)id;
- s.writeBytes(path.data(), len);
- s << attr;
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpSetStat(): sftp packet id mismatch" << endl;
- return -1;
- // XXX How do we do a fatal error?
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "sftpSetStat(): unexpected message type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "sftpSetStat(): set stat failed with err code " << code << endl;
- }
-
- return code;
-}
-
-/** Sends a sftp command to remove a file or directory. */
-int sftpProtocol::sftpRemove(const KURL& url, bool isfile){
-
- kdDebug(KIO_SFTP_DB) << "sftpRemove(): " << url << ", isFile ? " << isfile << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len);
- s << (TQ_UINT8)(isfile ? SSH2_FXP_REMOVE : SSH2_FXP_RMDIR);
- s << (TQ_UINT32)id;
- s.writeBytes(path.data(), len);
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "del(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "del(): unexpected message type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "del(): del failed with err code " << code << endl;
- }
-
- return code;
-}
-
-/** Send a sftp command to rename a file or directoy. */
-int sftpProtocol::sftpRename(const KURL& src, const KURL& dest){
-
- kdDebug(KIO_SFTP_DB) << "sftpRename(" << src << " -> " << dest << ")" << endl;
-
- TQCString srcPath = remoteEncoding()->encode(src.path());
- TQCString destPath = remoteEncoding()->encode(dest.path());
-
- uint slen = srcPath.length();
- uint dlen = destPath.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ +
- 4 /*str length*/ + slen +
- 4 /*str length*/ + dlen);
- s << (TQ_UINT8)SSH2_FXP_RENAME;
- s << (TQ_UINT32)id;
- s.writeBytes(srcPath.data(), slen);
- s.writeBytes(destPath.data(), dlen);
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpRename(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "sftpRename(): unexpected message type of " << type << endl;
- return -1;
- }
-
- int code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "sftpRename(): rename failed with err code " << code << endl;
- }
-
- return code;
-}
-/** Get directory listings. */
-int sftpProtocol::sftpReadDir(const TQByteArray& handle, const KURL& url){
- // url is needed so we can lookup the link destination
- kdDebug(KIO_SFTP_DB) << "sftpReadDir(): " << url << endl;
-
- TQ_UINT32 id, expectedId, count;
- TQ_UINT8 type;
-
- sftpFileAttr attr (remoteEncoding());
- attr.setDirAttrsFlag(true);
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- id = expectedId = mMsgId++;
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + handle.size());
- s << (TQ_UINT8)SSH2_FXP_READDIR;
- s << (TQ_UINT32)id;
- s << handle;
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- r >> type >> id;
-
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpReadDir(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- int code;
- if( type == SSH2_FXP_STATUS ) {
- r >> code;
- return code;
- }
-
- if( type != SSH2_FXP_NAME ) {
- kdError(KIO_SFTP_DB) << "kio_sftpProtocl::sftpReadDir(): Unexpected message" << endl;
- return -1;
- }
-
- r >> count;
- kdDebug(KIO_SFTP_DB) << "sftpReadDir(): got " << count << " entries" << endl;
-
- while(count--) {
- r >> attr;
-
- if( S_ISLNK(attr.permissions()) ) {
- KURL myurl ( url );
- myurl.addPath(attr.filename());
-
- // Stat the symlink to find out its type...
- sftpFileAttr attr2 (remoteEncoding());
- (void) sftpStat(myurl, attr2);
-
- attr.setLinkType(attr2.linkType());
- attr.setLinkDestination(attr2.linkDestination());
- }
-
- listEntry(attr.entry(), false);
- }
-
- listEntry(attr.entry(), true);
-
- return SSH2_FX_OK;
-}
-
-int sftpProtocol::sftpReadLink(const KURL& url, TQString& target){
-
- kdDebug(KIO_SFTP_DB) << "sftpReadLink(): " << url << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- //kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Encoded Path: " << path << endl;
- //kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Encoded Size: " << len << endl;
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len);
- s << (TQ_UINT8)SSH2_FXP_READLINK;
- s << id;
- s.writeBytes(path.data(), len);
-
-
- putPacket(p);
- getPacket(p);
-
- TQ_UINT8 type;
- TQDataStream r(p, IO_ReadOnly);
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpReadLink(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 code;
- r >> code;
- kdDebug(KIO_SFTP_DB) << "sftpReadLink(): read link failed with code " << code << endl;
- return code;
- }
-
- if( type != SSH2_FXP_NAME ) {
- kdError(KIO_SFTP_DB) << "sftpReadLink(): unexpected packet type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 count;
- r >> count;
- if( count != 1 ) {
- kdError(KIO_SFTP_DB) << "sftpReadLink(): Bad number of file attributes for realpath command" << endl;
- return -1;
- }
-
- TQCString linkAddress;
- r >> linkAddress;
-
- linkAddress.truncate(linkAddress.size());
- kdDebug(KIO_SFTP_DB) << "sftpReadLink(): Link address: " << linkAddress << endl;
-
- target = remoteEncoding()->decode(linkAddress);
-
- return SSH2_FX_OK;
-}
-
-int sftpProtocol::sftpSymLink(const TQString& _target, const KURL& dest){
-
- TQCString destPath = remoteEncoding()->encode(dest.path());
- TQCString target = remoteEncoding()->encode(_target);
- uint dlen = destPath.length();
- uint tlen = target.length();
-
- kdDebug(KIO_SFTP_DB) << "sftpSymLink(" << target << " -> " << destPath << ")" << endl;
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ +
- 4 /*str length*/ + tlen +
- 4 /*str length*/ + dlen);
- s << (TQ_UINT8)SSH2_FXP_SYMLINK;
- s << (TQ_UINT32)id;
- s.writeBytes(target.data(), tlen);
- s.writeBytes(destPath.data(), dlen);
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpSymLink(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "sftpSymLink(): unexpected message type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 code;
- r >> code;
- if( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "sftpSymLink(): rename failed with err code " << code << endl;
- }
-
- return code;
-}
-
-/** Stats a file. */
-int sftpProtocol::sftpStat(const KURL& url, sftpFileAttr& attr) {
-
- kdDebug(KIO_SFTP_DB) << "sftpStat(): " << url << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ + 4 /*str length*/ + len);
- s << (TQ_UINT8)SSH2_FXP_LSTAT;
- s << (TQ_UINT32)id;
- s.writeBytes(path.data(), len);
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpStat(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 errCode;
- r >> errCode;
- kdError(KIO_SFTP_DB) << "sftpStat(): stat failed with code " << errCode << endl;
- return errCode;
- }
-
- if( type != SSH2_FXP_ATTRS ) {
- kdError(KIO_SFTP_DB) << "sftpStat(): unexpected message type of " << type << endl;
- return -1;
- }
-
- r >> attr;
- attr.setFilename(url.fileName());
- kdDebug(KIO_SFTP_DB) << "sftpStat(): " << attr << endl;
-
- // If the stat'ed resource is a symlink, perform a recursive stat
- // to determine the actual destination's type (file/dir).
- if( S_ISLNK(attr.permissions()) && isSupportedOperation(SSH2_FXP_READLINK) ) {
-
- TQString target;
- int code = sftpReadLink( url, target );
-
- if ( code != SSH2_FX_OK ) {
- kdError(KIO_SFTP_DB) << "sftpStat(): Unable to stat symlink destination" << endl;
- return -1;
- }
-
- kdDebug(KIO_SFTP_DB) << "sftpStat(): Resource is a symlink to -> " << target << endl;
-
- KURL dest( url );
- if( target[0] == '/' )
- dest.setPath(target);
- else
- dest.setFileName(target);
-
- dest.cleanPath();
-
- // Ignore symlinks that point to themselves...
- if ( dest != url ) {
-
- sftpFileAttr attr2 (remoteEncoding());
- (void) sftpStat(dest, attr2);
-
- if (attr2.linkType() == 0)
- attr.setLinkType(attr2.fileType());
- else
- attr.setLinkType(attr2.linkType());
-
- attr.setLinkDestination(target);
-
- kdDebug(KIO_SFTP_DB) << "sftpStat(): File type: " << attr.fileType() << endl;
- }
- }
-
- return SSH2_FX_OK;
-}
-
-
-int sftpProtocol::sftpOpen(const KURL& url, const TQ_UINT32 pflags,
- const sftpFileAttr& attr, TQByteArray& handle) {
- kdDebug(KIO_SFTP_DB) << "sftpOpen(" << url << ", handle" << endl;
-
- TQCString path = remoteEncoding()->encode(url.path());
- uint len = path.length();
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
-
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ +
- 4 /*str length*/ + len +
- 4 /*pflags*/ + attr.size());
- s << (TQ_UINT8)SSH2_FXP_OPEN;
- s << (TQ_UINT32)id;
- s.writeBytes(path.data(), len);
- s << pflags;
- s << attr;
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpOpen(): sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 errCode;
- r >> errCode;
- return errCode;
- }
-
- if( type != SSH2_FXP_HANDLE ) {
- kdError(KIO_SFTP_DB) << "sftpOpen(): unexpected message type of " << type << endl;
- return -1;
- }
-
- r >> handle;
- if( handle.size() > 256 ) {
- kdError(KIO_SFTP_DB) << "sftpOpen(): handle exceeds max length" << endl;
- return -1;
- }
-
- kdDebug(KIO_SFTP_DB) << "sftpOpen(): handle (" << handle.size() << "): [" << handle << "]" << endl;
- return SSH2_FX_OK;
-}
-
-
-int sftpProtocol::sftpRead(const TQByteArray& handle, TDEIO::filesize_t offset, TQ_UINT32 len, TQByteArray& data)
-{
- // kdDebug(KIO_SFTP_DB) << "sftpRead( offset = " << offset << ", len = " << len << ")" << endl;
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ +
- 4 /*str length*/ + handle.size() +
- 8 /*offset*/ + 4 /*length*/);
- s << (TQ_UINT8)SSH2_FXP_READ;
- s << (TQ_UINT32)id;
- s << handle;
- s << offset; // we don't have a convienient 64 bit int so set upper int to zero
- s << len;
-
- putPacket(p);
- getPacket(p);
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpRead: sftp packet id mismatch" << endl;
- return -1;
- }
-
- if( type == SSH2_FXP_STATUS ) {
- TQ_UINT32 errCode;
- r >> errCode;
- kdError(KIO_SFTP_DB) << "sftpRead: read failed with code " << errCode << endl;
- return errCode;
- }
-
- if( type != SSH2_FXP_DATA ) {
- kdError(KIO_SFTP_DB) << "sftpRead: unexpected message type of " << type << endl;
- return -1;
- }
-
- r >> data;
-
- return SSH2_FX_OK;
-}
-
-
-int sftpProtocol::sftpWrite(const TQByteArray& handle, TDEIO::filesize_t offset, const TQByteArray& data){
-// kdDebug(KIO_SFTP_DB) << "sftpWrite( offset = " << offset <<
-// ", data sz = " << data.size() << ")" << endl;
- TQByteArray p;
- TQDataStream s(p, IO_WriteOnly);
-
- TQ_UINT32 id, expectedId;
- id = expectedId = mMsgId++;
- s << (TQ_UINT32)(1 /*type*/ + 4 /*id*/ +
- 4 /*str length*/ + handle.size() +
- 8 /*offset*/ +
- 4 /* data size */ + data.size());
- s << (TQ_UINT8)SSH2_FXP_WRITE;
- s << (TQ_UINT32)id;
- s << handle;
- s << offset; // we don't have a convienient 64 bit int so set upper int to zero
- s << data;
-
-// kdDebug(KIO_SFTP_DB) << "sftpWrite(): SSH2_FXP_WRITE, id:"
-// << id << ", handle:" << handle << ", offset:" << offset << ", some data" << endl;
-
-// kdDebug(KIO_SFTP_DB) << "sftpWrite(): send packet [" << p << "]" << endl;
-
- putPacket(p);
- getPacket(p);
-
-// kdDebug(KIO_SFTP_DB) << "sftpWrite(): received packet [" << p << "]" << endl;
-
- TQDataStream r(p, IO_ReadOnly);
- TQ_UINT8 type;
-
- r >> type >> id;
- if( id != expectedId ) {
- kdError(KIO_SFTP_DB) << "sftpWrite(): sftp packet id mismatch, got "
- << id << ", expected " << expectedId << endl;
- return -1;
- }
-
- if( type != SSH2_FXP_STATUS ) {
- kdError(KIO_SFTP_DB) << "sftpWrite(): unexpected message type of " << type << endl;
- return -1;
- }
-
- TQ_UINT32 code;
- r >> code;
- return code;
-}
-
-