Changeset View
Changeset View
Standalone View
Standalone View
sftp/kio_sftp.h
1 | /* | 1 | /* | ||
---|---|---|---|---|---|
2 | * Copyright (c) 2001 Lucas Fisher <ljfisher@purdue.edu> | 2 | * Copyright (c) 2001 Lucas Fisher <ljfisher@purdue.edu> | ||
3 | * Copyright (c) 2009 Andreas Schneider <mail@cynapses.org> | 3 | * Copyright (c) 2009 Andreas Schneider <mail@cynapses.org> | ||
4 | * Copyright (c) 2020 Harald Sitter <sitter@kde.org> | ||||
4 | * | 5 | * | ||
5 | * This library is free software; you can redistribute it and/or | 6 | * This library is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU Library General Public | 7 | * modify it under the terms of the GNU Library General Public | ||
7 | * License (LGPL) as published by the Free Software Foundation; | 8 | * License (LGPL) as published by the Free Software Foundation; | ||
8 | * either version 2 of the License, or (at your option) any later | 9 | * either version 2 of the License, or (at your option) any later | ||
9 | * version. | 10 | * version. | ||
10 | * | 11 | * | ||
11 | * This library is distributed in the hope that it will be useful, | 12 | * This library is distributed in the hope that it will be useful, | ||
Show All 18 Lines | |||||
30 | #include <libssh/callbacks.h> | 31 | #include <libssh/callbacks.h> | ||
31 | 32 | | |||
32 | #include <QQueue> | 33 | #include <QQueue> | ||
33 | 34 | | |||
34 | namespace KIO { | 35 | namespace KIO { | ||
35 | class AuthInfo; | 36 | class AuthInfo; | ||
36 | } | 37 | } | ||
37 | 38 | | |||
38 | class sftpProtocol : public KIO::SlaveBase | 39 | /** | ||
40 | * Result type for returning error context. | ||||
41 | * | ||||
42 | * This is meant to be returned by functions that do not have a simple | ||||
43 | * error conditions that could be represented by returning a bool, or | ||||
44 | * when the contextual error string can only be correctly constructed | ||||
45 | * inside the function. When using the Result type always mark the | ||||
46 | * function Q_REQUIRED_RESULT to enforce handling of the Result. | ||||
47 | * | ||||
48 | * The Result is forwared all the way to the frontend API where it is | ||||
dfaure: typo: forwar*d*ed | |||||
49 | * turned into an error() or finished() call. | ||||
50 | */ | ||||
51 | struct Result | ||||
52 | { | ||||
53 | bool success; | ||||
54 | int error; | ||||
55 | QString errorString; | ||||
56 | | ||||
57 | inline static Result fail(int _error = KIO::ERR_UNKNOWN, | ||||
58 | const QString &_errorString = QString()) | ||||
59 | { | ||||
60 | return Result { false, _error, _errorString }; | ||||
61 | } | ||||
62 | | ||||
63 | inline static Result pass() | ||||
64 | { | ||||
65 | return Result { true, 0, QString() }; | ||||
66 | } | ||||
67 | }; | ||||
68 | | ||||
69 | class SFTPSlave; | ||||
70 | | ||||
71 | class SFTPInternal | ||||
39 | { | 72 | { | ||
40 | public: | 73 | public: | ||
41 | sftpProtocol(const QByteArray &pool_socket, const QByteArray &app_socket); | 74 | explicit SFTPInternal(SFTPSlave *qptr); | ||
42 | ~sftpProtocol() override; | 75 | ~SFTPInternal(); | ||
43 | void setHost(const QString &h, quint16 port, const QString& user, const QString& pass) override; | 76 | void setHost(const QString &h, quint16 port, const QString& user, const QString& pass); | ||
44 | void get(const QUrl &url) override; | 77 | Q_REQUIRED_RESULT Result get(const QUrl &url); | ||
feverfew: TODO KF6 https://en.cppreference.com/w/cpp/language/attributes/nodiscard ? | |||||
I guess, that applies to all slaves though. ftp already has it and smb is also going to get it at some point. If we want a todo comment I'd put it in the ftp code. Though TBH I think that should just be a clazy check or deprecation inside Qt when built with c++17. sitter: I guess, that applies to all slaves though. ftp already has it and smb is also going to get it… | |||||
45 | void listDir(const QUrl &url) override ; | 78 | Q_REQUIRED_RESULT Result listDir(const QUrl &url); | ||
46 | void mimetype(const QUrl &url) override; | 79 | Q_REQUIRED_RESULT Result mimetype(const QUrl &url); | ||
47 | void stat(const QUrl &url) override; | 80 | Q_REQUIRED_RESULT Result stat(const QUrl &url); | ||
48 | void copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags) override; | 81 | Q_REQUIRED_RESULT Result copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags); | ||
49 | void put(const QUrl &url, int permissions, KIO::JobFlags flags) override; | 82 | Q_REQUIRED_RESULT Result put(const QUrl &url, int permissions, KIO::JobFlags flags); | ||
50 | void closeConnection() override; | 83 | void closeConnection(); | ||
51 | void slave_status() override; | 84 | void slave_status(); | ||
52 | void del(const QUrl &url, bool isfile) override; | 85 | Q_REQUIRED_RESULT Result del(const QUrl &url, bool isfile); | ||
53 | void chmod(const QUrl &url, int permissions) override; | 86 | Q_REQUIRED_RESULT Result chmod(const QUrl &url, int permissions); | ||
54 | void symlink(const QString &target, const QUrl &dest, KIO::JobFlags flags) override; | 87 | Q_REQUIRED_RESULT Result symlink(const QString &target, const QUrl &dest, KIO::JobFlags flags); | ||
55 | void rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) override; | 88 | Q_REQUIRED_RESULT Result rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags); | ||
56 | void mkdir(const QUrl &url, int permissions) override; | 89 | Q_REQUIRED_RESULT Result mkdir(const QUrl &url, int permissions); | ||
57 | void openConnection() override; | 90 | Q_REQUIRED_RESULT Result openConnection(); | ||
58 | 91 | | |||
59 | // KIO::FileJob interface | 92 | // KIO::FileJob interface | ||
60 | void open(const QUrl &url, QIODevice::OpenMode mode) override; | 93 | Q_REQUIRED_RESULT Result open(const QUrl &url, QIODevice::OpenMode mode); | ||
61 | void read(KIO::filesize_t size) override; | 94 | Q_REQUIRED_RESULT Result read(KIO::filesize_t size); | ||
62 | void write(const QByteArray &data) override; | 95 | Q_REQUIRED_RESULT Result write(const QByteArray &data); | ||
63 | void seek(KIO::filesize_t offset) override; | 96 | Q_REQUIRED_RESULT Result seek(KIO::filesize_t offset); | ||
64 | void truncate(KIO::filesize_t length); | 97 | Q_REQUIRED_RESULT Result truncate(KIO::filesize_t length); | ||
65 | void close() override; | 98 | void close(); | ||
66 | void special(const QByteArray &data) override; | 99 | Q_REQUIRED_RESULT Result special(const QByteArray &data); | ||
67 | 100 | | |||
68 | // libssh authentication callback (note that this is called by the | 101 | // libssh authentication callback (note that this is called by the | ||
69 | // global ::auth_callback() call. | 102 | // global ::auth_callback() call. | ||
70 | int auth_callback(const char *prompt, char *buf, size_t len, | 103 | int auth_callback(const char *prompt, char *buf, size_t len, | ||
71 | int echo, int verify, void *userdata); | 104 | int echo, int verify, void *userdata); | ||
72 | 105 | | |||
73 | // libssh logging callback (note that this is called by the | 106 | // libssh logging callback (note that this is called by the | ||
74 | // global ::log_callback() call. | 107 | // global ::log_callback() call. | ||
75 | void log_callback(int priority, const char *function, const char *buffer, | 108 | void log_callback(int priority, const char *function, const char *buffer, | ||
76 | void *userdata); | 109 | void *userdata); | ||
77 | 110 | | |||
78 | protected: | | |||
79 | void virtual_hook(int id, void *data) override; | | |||
80 | 111 | | |||
112 | // Must call after construction! | ||||
113 | // Bit rubbish, but we need to return something on init. | ||||
114 | Q_REQUIRED_RESULT Result init(); | ||||
115 | | ||||
116 | Q_REQUIRED_RESULT Result fileSystemFreeSpace(const QUrl &url); // KF6 TODO: Once a virtual fileSystemFreeSpace method in SlaveBase exists, override it | ||||
81 | private: // Private variables | 117 | private: // Private variables | ||
118 | /** Fronting SlaveBase instance */ | ||||
119 | SFTPSlave *q = nullptr; | ||||
120 | | ||||
82 | /** True if ioslave is connected to sftp server. */ | 121 | /** True if ioslave is connected to sftp server. */ | ||
83 | bool mConnected; | 122 | bool mConnected = false; | ||
84 | 123 | | |||
85 | /** Host we are connected to. */ | 124 | /** Host we are connected to. */ | ||
86 | QString mHost; | 125 | QString mHost; | ||
87 | 126 | | |||
88 | /** Port we are connected to. */ | 127 | /** Port we are connected to. */ | ||
89 | int mPort; | 128 | int mPort = -1; | ||
90 | 129 | | |||
91 | /** The ssh session for the connection */ | 130 | /** The ssh session for the connection */ | ||
92 | ssh_session mSession; | 131 | ssh_session mSession = nullptr; | ||
93 | 132 | | |||
94 | /** The sftp session for the connection */ | 133 | /** The sftp session for the connection */ | ||
95 | sftp_session mSftp; | 134 | sftp_session mSftp = nullptr; | ||
96 | 135 | | |||
97 | /** Username to use when connecting */ | 136 | /** Username to use when connecting */ | ||
98 | QString mUsername; | 137 | QString mUsername; | ||
99 | 138 | | |||
100 | /** User's password */ | 139 | /** User's password */ | ||
101 | QString mPassword; | 140 | QString mPassword; | ||
102 | 141 | | |||
103 | /** The open file */ | 142 | /** The open file */ | ||
104 | sftp_file mOpenFile; | 143 | sftp_file mOpenFile = nullptr; | ||
105 | 144 | | |||
106 | /** The open URL */ | 145 | /** The open URL */ | ||
107 | QUrl mOpenUrl; | 146 | QUrl mOpenUrl; | ||
108 | 147 | | |||
109 | ssh_callbacks mCallbacks; | 148 | ssh_callbacks mCallbacks = nullptr; | ||
110 | | ||||
111 | /** Version of the sftp protocol we are using. */ | | |||
112 | int sftpVersion; | | |||
113 | | ||||
114 | struct Status | | |||
115 | { | | |||
116 | int code; | | |||
117 | KIO::filesize_t size; | | |||
118 | QString text; | | |||
119 | }; | | |||
120 | 149 | | |||
121 | // KIO::FileJob interface | 150 | // KIO::FileJob interface | ||
122 | /** The opened handle */ | 151 | KIO::filesize_t openOffset = 0; | ||
123 | QByteArray openHandle; | | |||
124 | QUrl openUrl; | | |||
125 | KIO::filesize_t openOffset; | | |||
126 | 152 | | |||
127 | /** | 153 | /** | ||
128 | * Holds public key authentication info for proper retry handling. | 154 | * Holds public key authentication info for proper retry handling. | ||
129 | */ | 155 | */ | ||
130 | KIO::AuthInfo* mPublicKeyAuthInfo; | 156 | KIO::AuthInfo *mPublicKeyAuthInfo = nullptr; | ||
131 | 157 | | |||
132 | /** | 158 | /** | ||
133 | * GetRequest encapsulates several SFTP get requests into a single object. | 159 | * GetRequest encapsulates several SFTP get requests into a single object. | ||
134 | * As SFTP messages are limited to MAX_XFER_BUF_SIZE several requests | 160 | * As SFTP messages are limited to MAX_XFER_BUF_SIZE several requests | ||
135 | * should be sent simultaneously in order to increase transfer speeds. | 161 | * should be sent simultaneously in order to increase transfer speeds. | ||
136 | */ | 162 | */ | ||
137 | class GetRequest { | 163 | class GetRequest { | ||
138 | public: | 164 | public: | ||
Show All 39 Lines | 193 | private: | |||
178 | sftp_attributes mSb; | 204 | sftp_attributes mSb; | ||
179 | ushort mMaxPendingRequests; | 205 | ushort mMaxPendingRequests; | ||
180 | QQueue<Request> pendingRequests; | 206 | QQueue<Request> pendingRequests; | ||
181 | }; | 207 | }; | ||
182 | 208 | | |||
183 | private: // private methods | 209 | private: // private methods | ||
184 | int authenticateKeyboardInteractive(KIO::AuthInfo &info); | 210 | int authenticateKeyboardInteractive(KIO::AuthInfo &info); | ||
185 | 211 | | |||
186 | void reportError(const QUrl &url, const int err); | 212 | Q_REQUIRED_RESULT Result reportError(const QUrl &url, const int err); | ||
187 | 213 | | |||
188 | bool createUDSEntry(const QString &filename, const QByteArray &path, | 214 | bool createUDSEntry(const QString &filename, const QByteArray &path, | ||
189 | KIO::UDSEntry &entry, short int details); | 215 | KIO::UDSEntry &entry, short int details); | ||
190 | 216 | | |||
191 | QString canonicalizePath(const QString &path); | 217 | QString canonicalizePath(const QString &path); | ||
192 | void requiresUserNameRedirection(); | 218 | void requiresUserNameRedirection(); | ||
193 | void clearPubKeyAuthInfo(); | 219 | void clearPubKeyAuthInfo(); | ||
194 | bool sftpLogin(); | 220 | Q_REQUIRED_RESULT Result sftpLogin(); | ||
195 | bool sftpOpenConnection(const KIO::AuthInfo&); | 221 | Q_REQUIRED_RESULT Result sftpOpenConnection(const KIO::AuthInfo &); | ||
196 | void sftpSendWarning(int errorCode, const QString& url); | 222 | | ||
223 | Q_REQUIRED_RESULT Result sftpGet(const QUrl &url, KIO::fileoffset_t offset = -1, int fd = -1); | ||||
224 | Q_REQUIRED_RESULT Result sftpPut(const QUrl &url, int permissions, KIO::JobFlags flags, int fd = -1); | ||||
225 | | ||||
226 | Q_REQUIRED_RESULT Result sftpCopyGet(const QUrl &url, const QString &src, int permissions, KIO::JobFlags flags); | ||||
227 | Q_REQUIRED_RESULT Result sftpCopyPut(const QUrl &url, const QString &dest, int permissions, KIO::JobFlags flags); | ||||
228 | }; | ||||
229 | | ||||
230 | /** | ||||
231 | * Fronting class. | ||||
232 | * The purpose of this is to separate the slave interface from the slave logic and force state | ||||
233 | * convergence. | ||||
234 | * Specifically logic code must not call finalization API error()/finished() but instead move | ||||
235 | * a single Result object up the call chain. This is to prevent overwriting errors and/or finished | ||||
236 | * finality states and broken-state situations those can cause. | ||||
237 | */ | ||||
238 | class SFTPSlave : public KIO::SlaveBase | ||||
239 | { | ||||
240 | public: | ||||
241 | SFTPSlave(const QByteArray &pool_socket, const QByteArray &app_socket); | ||||
242 | ~SFTPSlave() override = default; | ||||
243 | void setHost(const QString &host, quint16 port, const QString &user, const QString &pass) override; | ||||
244 | void get(const QUrl &url) override; | ||||
245 | void listDir(const QUrl &url) override ; | ||||
246 | void mimetype(const QUrl &url) override; | ||||
247 | void stat(const QUrl &url) override; | ||||
248 | void copy(const QUrl &src, const QUrl &dest, int permissions, KIO::JobFlags flags) override; | ||||
249 | void put(const QUrl &url, int permissions, KIO::JobFlags flags) override; | ||||
250 | void slave_status() override; | ||||
251 | void del(const QUrl &url, bool isfile) override; | ||||
252 | void chmod(const QUrl &url, int permissions) override; | ||||
253 | void symlink(const QString &target, const QUrl &dest, KIO::JobFlags flags) override; | ||||
254 | void rename(const QUrl &src, const QUrl &dest, KIO::JobFlags flags) override; | ||||
255 | void mkdir(const QUrl &url, int permissions) override; | ||||
256 | void openConnection() override; | ||||
257 | void closeConnection() override; | ||||
258 | | ||||
259 | // KIO::FileJob interface | ||||
260 | void open(const QUrl &url, QIODevice::OpenMode mode) override; | ||||
261 | void read(KIO::filesize_t size) override; | ||||
262 | void write(const QByteArray &data) override; | ||||
263 | void seek(KIO::filesize_t offset) override; | ||||
264 | void truncate(KIO::filesize_t length); | ||||
265 | void close() override; | ||||
266 | void special(const QByteArray &data) override; | ||||
267 | void virtual_hook(int id, void *data) override; | ||||
197 | 268 | | |||
198 | // Close without error() or finish() call (in case of errors for example) | 269 | private: | ||
199 | void closeWithoutFinish(); | 270 | // WARNING: All members and all logic not confined to one of the public functions | ||
271 | // must go into SftpInternal! | ||||
200 | 272 | | |||
201 | /** | 273 | /** | ||
202 | * Status Code returned from ftpPut() and ftpGet(), used to select | 274 | * Overridden to prevent SftpInternal from easily calling | ||
203 | * source or destination url for error messages | 275 | * q->opened(). Use a Result return type on error conditions | ||
276 | * instead. When there was no error Result the | ||||
277 | * connection is considered opened. | ||||
278 | * | ||||
279 | * SftpInternal must not call any state-changing signals! | ||||
204 | */ | 280 | */ | ||
205 | typedef enum { | 281 | void opened() | ||
206 | Success, | 282 | { | ||
207 | ClientError, | 283 | SlaveBase::opened(); | ||
208 | ServerError | 284 | } | ||
209 | } StatusCode; | | |||
210 | 285 | | |||
211 | StatusCode sftpGet(const QUrl& url, int& errorCode, KIO::fileoffset_t offset = -1, int fd = -1); | 286 | /** | ||
212 | StatusCode sftpPut(const QUrl& url, int permissions, KIO::JobFlags flags, int& errorCode, int fd = -1); | 287 | * @see opened() | ||
288 | */ | ||||
289 | void error(int _errid, const QString &_text) | ||||
290 | { | ||||
291 | SlaveBase::error(_errid, _text); | ||||
292 | } | ||||
293 | | ||||
294 | /** | ||||
295 | * @see opened() | ||||
296 | */ | ||||
297 | void finished() | ||||
298 | { | ||||
299 | SlaveBase::finished(); | ||||
300 | } | ||||
213 | 301 | | |||
214 | StatusCode sftpCopyGet(const QUrl& url, const QString& src, int permissions, KIO::JobFlags flags, int& errorCode); | 302 | /** | ||
215 | StatusCode sftpCopyPut(const QUrl& url, const QString& dest, int permissions, KIO::JobFlags flags, int& errorCode); | 303 | * Calls finished() or error() as appropriate | ||
304 | */ | ||||
305 | void finalize(const Result &result); | ||||
306 | | ||||
307 | /** | ||||
308 | * Calls error() if and only if the result is an error | ||||
309 | */ | ||||
310 | void maybeError(const Result &result); | ||||
216 | 311 | | |||
217 | void fileSystemFreeSpace(const QUrl& url); // KF6 TODO: Once a virtual fileSystemFreeSpace method in SlaveBase exists, override it | 312 | QScopedPointer<SFTPInternal> d { new SFTPInternal(this) }; | ||
218 | }; | 313 | }; | ||
219 | 314 | | |||
220 | #endif | 315 | #endif |
typo: forwar*d*ed