sftp_client.c
Go to the documentation of this file.
1 /**
2  * @file sftp_client.c
3  * @brief SFTP client
4  *
5  * @section License
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  *
9  * Copyright (C) 2019-2026 Oryx Embedded SARL. All rights reserved.
10  *
11  * This file is part of CycloneSSH Open.
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software Foundation,
25  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
26  *
27  * @author Oryx Embedded SARL (www.oryx-embedded.com)
28  * @version 2.6.0
29  **/
30 
31 //Switch to the appropriate trace level
32 #define TRACE_LEVEL SFTP_TRACE_LEVEL
33 
34 //Dependencies
35 #include "ssh/ssh.h"
36 #include "ssh/ssh_transport.h"
37 #include "sftp/sftp_client.h"
39 #include "sftp/sftp_client_misc.h"
40 #include "debug.h"
41 
42 //Check SSH stack configuration
43 #if (SFTP_CLIENT_SUPPORT == ENABLED)
44 
45 
46 /**
47  * @brief Initialize SFTP client context
48  * @param[in] context Pointer to the SFTP client context
49  * @return Error code
50  **/
51 
53 {
54  //Make sure the SFTP client context is valid
55  if(context == NULL)
57 
58  //Clear SFTP client context
59  osMemset(context, 0, sizeof(SftpClientContext));
60 
61  //Attach TCP/IP stack context
62  context->netContext = netGetDefaultContext();
63 
64  //Initialize SFTP client state
65  context->state = SFTP_CLIENT_STATE_DISCONNECTED;
66  //Default timeout
67  context->timeout = SFTP_CLIENT_DEFAULT_TIMEOUT;
68 
69  //Successful processing
70  return NO_ERROR;
71 }
72 
73 
74 /**
75  * @brief Register SSH initialization callback function
76  * @param[in] context Pointer to the SFTP client context
77  * @param[in] callback SSH initialization callback function
78  * @return Error code
79  **/
80 
83 {
84  //Check parameters
85  if(context == NULL || callback == NULL)
87 
88  //Save callback function
89  context->sshInitCallback = callback;
90 
91  //Successful processing
92  return NO_ERROR;
93 }
94 
95 
96 /**
97  * @brief Set communication timeout
98  * @param[in] context Pointer to the SFTP client context
99  * @param[in] timeout Timeout value, in milliseconds
100  * @return Error code
101  **/
102 
104 {
105  //Make sure the SFTP client context is valid
106  if(context == NULL)
108 
109  //Save timeout value
110  context->timeout = timeout;
111 
112  //Successful processing
113  return NO_ERROR;
114 }
115 
116 
117 /**
118  * @brief Bind the SFTP client to a particular network interface
119  * @param[in] context Pointer to the SFTP client context
120  * @param[in] interface Network interface to be used
121  * @return Error code
122  **/
123 
125  NetInterface *interface)
126 {
127  //Make sure the SFTP client context is valid
128  if(context == NULL)
130 
131  //Explicitly associate the SFTP client with the specified interface
132  context->interface = interface;
133 
134  //Successful processing
135  return NO_ERROR;
136 }
137 
138 
139 /**
140  * @brief Establish a connection with the specified SFTP server
141  * @param[in] context Pointer to the SFTP client context
142  * @param[in] serverIpAddr IP address of the SFTP server to connect to
143  * @param[in] serverPort Port number
144  * @return Error code
145  **/
146 
148  const IpAddr *serverIpAddr, uint16_t serverPort)
149 {
150  error_t error;
151  size_t n;
152  SftpName name;
153 
154  //Make sure the SFTP client context is valid
155  if(context == NULL)
157 
158  //Initialize status code
159  error = NO_ERROR;
160 
161  //Establish connection with the SFTP server
162  while(!error)
163  {
164  //Check current state
165  if(context->state == SFTP_CLIENT_STATE_DISCONNECTED)
166  {
167  //Open network connection
168  error = sftpClientOpenConnection(context);
169 
170  //Check status code
171  if(!error)
172  {
173  //Update SFTP client state
175  }
176  }
177  else if(context->state == SFTP_CLIENT_STATE_CONNECTING)
178  {
179  //Establish network connection
180  error = socketConnect(context->sshConnection.socket, serverIpAddr,
181  serverPort);
182 
183  //Check status code
184  if(error == NO_ERROR)
185  {
186  //Force the socket to operate in non-blocking mode
187  socketSetTimeout(context->sshConnection.socket, 0);
188 
189  //Update SFTP client state
191  }
192  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
193  {
194  //Check whether the timeout has elapsed
195  error = sftpClientCheckTimeout(context);
196  }
197  else
198  {
199  //Communication error
200  }
201  }
202  else if(context->state == SFTP_CLIENT_STATE_CHANNEL_OPEN ||
203  context->state == SFTP_CLIENT_STATE_CHANNEL_OPEN_REPLY ||
204  context->state == SFTP_CLIENT_STATE_CHANNEL_REQUEST ||
205  context->state == SFTP_CLIENT_STATE_CHANNEL_REPLY)
206  {
207  //Establish SSH connection
208  error = sftpClientEstablishConnection(context);
209  }
210  else if(context->state == SFTP_CLIENT_STATE_CHANNEL_DATA)
211  {
212  //Format SSH_FXP_INIT packet
214 
215  //Check status code
216  if(!error)
217  {
218  //Send the SSH_FXP_INIT request and wait for the server's response
220  }
221  }
222  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
223  {
224  //Send the SSH_FXP_INIT request and wait for the server's response
225  error = sftpClientSendCommand(context);
226 
227  //Check status code
228  if(!error)
229  {
230  //Format SSH_FXP_REALPATH packet
231  error = sftpClientFormatFxpRealPath(context, ".");
232  }
233 
234  //Check status code
235  if(!error)
236  {
237  //Update SFTP client state
239  }
240  }
241  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_2)
242  {
243  //Send the SSH_FXP_REALPATH request and wait for the server's response
244  error = sftpClientSendCommand(context);
245 
246  //Check status code
247  if(!error)
248  {
249  //Update SFTP client state
251  }
252  }
253  else if(context->state == SFTP_CLIENT_STATE_RECEIVING_NAME)
254  {
255  //The server will respond to an SSH_FXP_REALPATH request with an
256  //SSH_FXP_NAME packet containing only one name and dummy attributes
257  error = sftpParseName(context->version, &name, context->buffer,
258  context->responseLen, &n);
259 
260  //Check status code
261  if(!error)
262  {
263  //Retrieve the length of the home directory
264  n = name.filename.length;
265 
266  //Check the length of the pathname
268  {
269  //Save the home directory
270  osStrncpy(context->currentDir, name.filename.value, n);
271  //Properly terminate the string with a NULL character
272  context->currentDir[n] = '\0';
273  }
274  else
275  {
276  //Use default home directory
277  osStrcpy(context->currentDir, "");
278  }
279 
280  //Update SFTP client state
282  }
283  }
284  else if(context->state == SFTP_CLIENT_STATE_CONNECTED)
285  {
286  //The SFTP client is connected
287  break;
288  }
289  else
290  {
291  //Invalid state
292  error = ERROR_WRONG_STATE;
293  }
294  }
295 
296  //Failed to establish connection with the SFTP server?
297  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
298  {
299  //Clean up side effects
300  sftpClientCloseConnection(context);
301  //Update SFTP client state
303  }
304 
305  //Return status code
306  return error;
307 }
308 
309 
310 /**
311  * @brief Get current working directory
312  * @param[in] context Pointer to the SFTP client context
313  * @return Path of the current directory
314  **/
315 
317 {
318  char_t *path;
319  static char_t *defaultPath = "/";
320 
321  //Retrieve the path of the current directory
322  if(context != NULL)
323  {
324  path = context->currentDir;
325  }
326  else
327  {
328  path = defaultPath;
329  }
330 
331  //Return the pathname
332  return path;
333 }
334 
335 
336 /**
337  * @brief Change working directory
338  * @param[in] context Pointer to the SFTP client context
339  * @param[in] path New current working directory
340  * @return Error code
341  **/
342 
344  const char_t *path)
345 {
346  error_t error;
347 
348  //Make sure the SFTP client context is valid
349  if(context == NULL)
351 
352  //Initialize status code
353  error = NO_ERROR;
354 
355  //Execute SFTP command
356  while(!error)
357  {
358  //Check current state
359  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
360  {
361  //Format SSH_FXP_OPENDIR packet
362  error = sftpClientFormatFxpOpenDir(context, path);
363 
364  //Check status code
365  if(!error)
366  {
367  //Send the SSH_FXP_OPENDIR request and wait for the server's response
369  }
370  }
371  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
372  {
373  //Send the SSH_FXP_OPENDIR request and wait for the server's response
374  error = sftpClientSendCommand(context);
375 
376  //Check status code
377  if(error == NO_ERROR)
378  {
379  //Format SSH_FXP_CLOSE packet
380  error = sftpClientFormatFxpClose(context, context->handle,
381  context->handleLen);
382 
383  //Check status code
384  if(!error)
385  {
386  //Send the SSH_FXP_CLOSE request and wait for the server's response
388  }
389  }
390  }
391  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_2)
392  {
393  //Send the SSH_FXP_CLOSE request and wait for the server's response
394  error = sftpClientSendCommand(context);
395 
396  //Check status code
397  if(error == NO_ERROR)
398  {
399  //Get the path of the new working directory
400  sftpGetAbsolutePath(context, path, (char_t *) context->buffer);
401  //Save the resulting pathname
402  osStrcpy(context->currentDir, (char_t *) context->buffer);
403 
404  //Update SFTP client state
406  //We are done
407  break;
408  }
409  }
410  else
411  {
412  //Invalid state
413  error = ERROR_WRONG_STATE;
414  }
415  }
416 
417  //Check status code
418  if(error == ERROR_UNEXPECTED_RESPONSE)
419  {
420  //Update SFTP client state
422  //The specified directory does not exist
423  error = ERROR_INVALID_DIRECTORY;
424  }
425 
426  //Return status code
427  return error;
428 }
429 
430 
431 /**
432  * @brief Change to parent directory
433  * @param[in] context Pointer to the SFTP client context
434  * @return Error code
435  **/
436 
438 {
439  //Change to the parent directory
440  return sftpClientChangeWorkingDir(context, "..");
441 }
442 
443 
444 /**
445  * @brief Open a directory
446  * @param[in] context Pointer to the SFTP client context
447  * @param[in] path Path to the directory to be be opened
448  * @return Directory handle
449  **/
450 
452 {
453  error_t error;
454 
455  //Check parameters
456  if(context == NULL || path == NULL)
458 
459  //Initialize status code
460  error = NO_ERROR;
461 
462  //Execute SFTP command
463  while(!error)
464  {
465  //Check current state
466  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
467  {
468  //Format SSH_FXP_OPENDIR packet
469  error = sftpClientFormatFxpOpenDir(context, path);
470 
471  //Check status code
472  if(!error)
473  {
474  //Send the SSH_FXP_OPENDIR request and wait for the server's response
476  }
477  }
478  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
479  {
480  //Send the SSH_FXP_OPENDIR request and wait for the server's response
481  error = sftpClientSendCommand(context);
482 
483  //Check status code
484  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
485  {
486  //Update SFTP client state
488  //We are done
489  break;
490  }
491  }
492  else
493  {
494  //Invalid state
495  error = ERROR_WRONG_STATE;
496  }
497  }
498 
499  //Return status code
500  return error;
501 }
502 
503 
504 /**
505  * @brief Read an entry from the directory
506  * @param[in] context Pointer to the SFTP client context
507  * @param[out] dirEntry Pointer to a directory entry
508  * @return Error code
509  **/
510 
512 {
513  error_t error;
514  size_t n;
515  SftpName name;
516 
517  //Check parameters
518  if(context == NULL || dirEntry == NULL)
520 
521  //Initialize status code
522  error = NO_ERROR;
523 
524  //Execute SFTP command
525  while(!error)
526  {
527  //Check current state
528  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
529  {
530  //Format SSH_FXP_READDIR packet
531  error = sftpClientFormatFxpReadDir(context, context->handle,
532  context->handleLen);
533 
534  //Check status code
535  if(!error)
536  {
537  //Send the SSH_FXP_READDIR request and wait for the server's response
539  }
540  }
541  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
542  {
543  //Send the SSH_FXP_READDIR request and wait for the server's response
544  error = sftpClientSendCommand(context);
545 
546  //Check status code
547  if(error == NO_ERROR)
548  {
549  //Update SFTP client state
551  }
552  else if(error == ERROR_UNEXPECTED_RESPONSE)
553  {
554  //If there are no more names available to be read, the server
555  //responds with an SSH_FX_EOF error code
556  if(context->statusCode == SSH_FX_EOF)
557  {
558  //No more directory entries to return
559  error = ERROR_END_OF_STREAM;
560  }
561 
562  //Update SFTP client state
564  }
565  else
566  {
567  //Just for sanity
568  }
569  }
570  else if(context->state == SFTP_CLIENT_STATE_RECEIVING_NAME)
571  {
572  //Any data residue?
573  if(context->responsePos > 0)
574  {
575  //Move the remaining data bytes to the start of the buffer
576  osMemmove(context->buffer, context->buffer + context->responsePos,
577  context->responseLen - context->responsePos);
578 
579  //Rewind to the beginning of the buffer
580  context->dataLen -= context->responsePos;
581  context->responseLen -= context->responsePos;
582  context->responsePos = 0;
583  }
584 
585  //Limit the number of bytes to read at a time
586  n = MIN(context->dataLen, SFTP_CLIENT_BUFFER_SIZE);
587 
588  //Check whether there is any data left to read
589  if(n == 0)
590  {
591  //Update SFTP client state
593  }
594  else if(context->responseLen < n)
595  {
596  //Receive more data
597  error = sshReadChannel(&context->sshChannel, context->buffer +
598  context->responseLen, n - context->responseLen, &n, 0);
599 
600  //Check status code
601  if(!error)
602  {
603  //Advance data pointer
604  context->responseLen += n;
605  //Save current time
606  context->timestamp = osGetSystemTime();
607  }
608 
609  //Check status code
610  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
611  {
612  //Process SSH connection events
613  error = sftpClientProcessEvents(context);
614  }
615  }
616  else
617  {
618  //One or more names may be returned at a time
619  error = sftpParseName(context->version, &name,
620  context->buffer + context->responsePos,
621  context->responseLen - context->responsePos, &n);
622 
623  //Check status code
624  if(!error)
625  {
626  //Advance data pointer
627  context->responsePos += n;
628 
629  //Retrieve the length of the filename
630  n = MIN(name.filename.length, SFTP_CLIENT_MAX_FILENAME_LEN);
631 
632  //Copy the filename
633  osStrncpy(dirEntry->name, name.filename.value, n);
634  //Properly terminate the string with a NULL character
635  dirEntry->name[n] = '\0';
636 
637  //Save file attributes
638  dirEntry->type = name.attributes.type;
639  dirEntry->size = name.attributes.size;
640  dirEntry->permissions = name.attributes.permissions;
641  dirEntry->modified = name.attributes.mtime;
642  }
643 
644  //We are done
645  break;
646  }
647  }
648  else
649  {
650  //Invalid state
651  error = ERROR_WRONG_STATE;
652  }
653  }
654 
655  //Return status code
656  return error;
657 }
658 
659 
660 /**
661  * @brief Close directory
662  * @param[in] context Pointer to the SFTP client context
663  * @return Error code
664  **/
665 
667 {
668  error_t error;
669 
670  //Make sure the SFTP client context is valid
671  if(context == NULL)
673 
674  //Initialize status code
675  error = NO_ERROR;
676 
677  //Execute SFTP command
678  while(!error)
679  {
680  //Check current state
681  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
682  {
683  //Format SSH_FXP_CLOSE packet
684  error = sftpClientFormatFxpClose(context, context->handle,
685  context->handleLen);
686 
687  //Check status code
688  if(!error)
689  {
690  //Send the SSH_FXP_CLOSE request and wait for the server's response
692  }
693  }
694  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
695  {
696  //Send the SSH_FXP_CLOSE request and wait for the server's response
697  error = sftpClientSendCommand(context);
698 
699  //Check status code
700  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
701  {
702  //Update SFTP client state
704  //We are done
705  break;
706  }
707  }
708  else
709  {
710  //Invalid state
711  error = ERROR_WRONG_STATE;
712  }
713  }
714 
715  //Return status code
716  return error;
717 }
718 
719 
720 /**
721  * @brief Create a new directory
722  * @param[in] context Pointer to the SFTP client context
723  * @param[in] path Name of the new directory
724  * @return Error code
725  **/
726 
728 {
729  error_t error;
730 
731  //Check parameters
732  if(context == NULL || path == NULL)
734 
735  //Initialize status code
736  error = NO_ERROR;
737 
738  //Execute SFTP command
739  while(!error)
740  {
741  //Check current state
742  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
743  {
744  //Format SSH_FXP_MKDIR packet
745  error = sftpClientFormatFxpMkDir(context, path);
746 
747  //Check status code
748  if(!error)
749  {
750  //Send the SSH_FXP_MKDIR request and wait for the server's response
752  }
753  }
754  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
755  {
756  //Send the SSH_FXP_MKDIR request and wait for the server's response
757  error = sftpClientSendCommand(context);
758 
759  //Check status code
760  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
761  {
762  //Update SFTP client state
764  //We are done
765  break;
766  }
767  }
768  else
769  {
770  //Invalid state
771  error = ERROR_WRONG_STATE;
772  }
773  }
774 
775  //Return status code
776  return error;
777 }
778 
779 
780 /**
781  * @brief Remove a directory
782  * @param[in] context Pointer to the SFTP client context
783  * @param[in] path Path to the directory to be removed
784  * @return Error code
785  **/
786 
788 {
789  error_t error;
790 
791  //Check parameters
792  if(context == NULL || path == NULL)
794 
795  //Initialize status code
796  error = NO_ERROR;
797 
798  //Execute SFTP command
799  while(!error)
800  {
801  //Check current state
802  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
803  {
804  //Format SSH_FXP_RMDIR packet
805  error = sftpClientFormatFxpRmDir(context, path);
806 
807  //Check status code
808  if(!error)
809  {
810  //Send the SSH_FXP_RMDIR request and wait for the server's response
812  }
813  }
814  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
815  {
816  //Send the SSH_FXP_RMDIR request and wait for the server's response
817  error = sftpClientSendCommand(context);
818 
819  //Check status code
820  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
821  {
822  //Update SFTP client state
824  //We are done
825  break;
826  }
827  }
828  else
829  {
830  //Invalid state
831  error = ERROR_WRONG_STATE;
832  }
833  }
834 
835  //Return status code
836  return error;
837 }
838 
839 
840 /**
841  * @brief Open a file for reading, writing, or appending
842  * @param[in] context Pointer to the SFTP client context
843  * @param[in] path Path to the file to be be opened
844  * @param[in] mode File access mode
845  * @return Error code
846  **/
847 
849  uint_t mode)
850 {
851  error_t error;
852 
853  //Check parameters
854  if(context == NULL || path == NULL)
856 
857  //Initialize status code
858  error = NO_ERROR;
859 
860  //Execute SFTP command
861  while(!error)
862  {
863  //Check current state
864  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
865  {
866  //Rewind to the beginning of the file
867  context->fileOffset = 0;
868 
869  //Format SSH_FXP_OPEN packet
870  error = sftpClientFormatFxpOpen(context, path, mode);
871 
872  //Check status code
873  if(!error)
874  {
875  //Send the SSH_FXP_OPEN request and wait for the server's response
877  }
878  }
879  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
880  {
881  //Send the SSH_FXP_OPEN request and wait for the server's response
882  error = sftpClientSendCommand(context);
883 
884  //Check status code
885  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
886  {
887  //Update SFTP client state
889  //We are done
890  break;
891  }
892  }
893  else
894  {
895  //Invalid state
896  error = ERROR_WRONG_STATE;
897  }
898  }
899 
900  //Return status code
901  return error;
902 }
903 
904 
905 /**
906  * @brief Write to a remote file
907  * @param[in] context Pointer to the SFTP client context
908  * @param[in] data Pointer to a buffer containing the data to be written
909  * @param[in] length Number of data bytes to write
910  * @param[in] written Number of bytes that have been written (optional parameter)
911  * @param[in] flags Set of flags that influences the behavior of this function
912  * @return Error code
913  **/
914 
916  size_t length, size_t *written, uint_t flags)
917 {
918  error_t error;
919  size_t n;
920  size_t totalLength;
921 
922  //Make sure the SFTP client context is valid
923  if(context == NULL)
925 
926  //Check parameters
927  if(data == NULL && length != 0)
929 
930  //Initialize status code
931  error = NO_ERROR;
932  //Actual number of bytes written
933  totalLength = 0;
934 
935  //Execute SFTP command
936  while(!error)
937  {
938  //Check current state
939  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
940  {
941  //Send as much data as possible
942  if(totalLength < length)
943  {
944  //The maximum size of packets is determined by the client
946 
947  //Format SSH_FXP_WRITE packet
948  error = sftpClientFormatFxpWrite(context, context->handle,
949  context->handleLen, context->fileOffset, n);
950 
951  //Check status code
952  if(!error)
953  {
954  //Send the SSH_FXP_WRITE request
956  }
957  }
958  else
959  {
960  //We are done
961  break;
962  }
963  }
964  else if(context->state == SFTP_CLIENT_STATE_SENDING_DATA)
965  {
966  //Send the SSH_FXP_WRITE request
967  if(context->requestPos < context->requestLen)
968  {
969  //Send more data
970  error = sshWriteChannel(&context->sshChannel,
971  context->buffer + context->requestPos,
972  context->requestLen - context->requestPos, &n, flags);
973 
974  //Check status code
975  if(error == NO_ERROR || error == ERROR_TIMEOUT)
976  {
977  //Any data transmitted?
978  if(n > 0)
979  {
980  //Advance data pointer
981  context->requestPos += n;
982  //Save current time
983  context->timestamp = osGetSystemTime();
984  }
985  }
986  }
987  else
988  {
989  //The length of the payload shall not exceed the length of the
990  //'data' field specified in the SSH_FXP_WRITE packet
991  n = MIN(length - totalLength, context->dataLen);
992 
993  //Check whether there is any data left to write
994  if(n > 0)
995  {
996  //Send more data
997  error = sshWriteChannel(&context->sshChannel,
998  (uint8_t *) data + totalLength, n, &n, flags);
999 
1000  //Check status code
1001  if(error == NO_ERROR || error == ERROR_TIMEOUT)
1002  {
1003  //Any data transmitted?
1004  if(n > 0)
1005  {
1006  //Advance data pointer
1007  totalLength += n;
1008  context->dataLen -= n;
1009 
1010  //Increment file offset
1011  context->fileOffset += n;
1012 
1013  //Save current time
1014  context->timestamp = osGetSystemTime();
1015  }
1016  }
1017  }
1018  else
1019  {
1020  //The total number of data written will be returned to the user
1021  //after the SSH_FXP_STATUS response has been received
1022  context->dataLen = totalLength;
1023  totalLength = 0;
1024 
1025  //Wait for the server's SSH_FXP_STATUS response
1027  }
1028  }
1029 
1030  //Check status code
1031  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1032  {
1033  //Process SSH connection events
1034  error = sftpClientProcessEvents(context);
1035  }
1036  }
1037  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
1038  {
1039  //Wait for the server's response
1040  error = sftpClientSendCommand(context);
1041 
1042  //Check status code
1043  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
1044  {
1045  //Retrieve the total number of data written
1046  totalLength = context->dataLen;
1047  //Update SFTP client state
1049  }
1050  }
1051  else
1052  {
1053  //Invalid state
1054  error = ERROR_WRONG_STATE;
1055  }
1056  }
1057 
1058  //Total number of data that have been written
1059  if(written != NULL)
1060  {
1061  *written = totalLength;
1062  }
1063 
1064  //Check status code
1065  if(error == ERROR_WOULD_BLOCK)
1066  {
1067  //Any data written?
1068  if(totalLength > 0)
1069  {
1070  error = NO_ERROR;
1071  }
1072  }
1073 
1074  //Return status code
1075  return error;
1076 }
1077 
1078 
1079 /**
1080  * @brief Read from a remote file
1081  * @param[in] context Pointer to the SFTP client context
1082  * @param[out] data Buffer where to store the incoming data
1083  * @param[in] size Maximum number of bytes that can be read
1084  * @param[out] received Actual number of bytes that have been read
1085  * @param[in] flags Set of flags that influences the behavior of this function
1086  * @return Error code
1087  **/
1088 
1089 error_t sftpClientReadFile(SftpClientContext *context, void *data, size_t size,
1090  size_t *received, uint_t flags)
1091 {
1092  error_t error;
1093  size_t n;
1094 
1095  //Check parameters
1096  if(context == NULL || data == NULL || received == NULL)
1097  return ERROR_INVALID_PARAMETER;
1098 
1099  //Initialize status code
1100  error = NO_ERROR;
1101  //No data has been read yet
1102  *received = 0;
1103 
1104  //Execute SFTP command
1105  while(!error)
1106  {
1107  //Check current state
1108  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
1109  {
1110  //Read as much data as possible
1111  if(*received < size)
1112  {
1113  //The maximum size of packets is determined by the client
1114  n = MIN(size - *received, SFTP_CLIENT_MAX_PACKET_SIZE);
1115 
1116  //Format SSH_FXP_READ packet
1117  error = sftpClientFormatFxpRead(context, context->handle,
1118  context->handleLen, context->fileOffset, n);
1119 
1120  //Check status code
1121  if(!error)
1122  {
1123  //Send the SSH_FXP_READ request and wait for the server's response
1125  }
1126  }
1127  else
1128  {
1129  //We are done
1130  break;
1131  }
1132  }
1133  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
1134  {
1135  //Send the SSH_FXP_READ request and wait for the server's response
1136  error = sftpClientSendCommand(context);
1137 
1138  //Check status code
1139  if(error == NO_ERROR)
1140  {
1141  //Update SFTP client state
1143  }
1144  else if(error == ERROR_UNEXPECTED_RESPONSE)
1145  {
1146  //If there are no more data is available in the file, the server
1147  //responds with an SSH_FX_EOF error code
1148  if(context->statusCode == SSH_FX_EOF)
1149  {
1150  //The user must be satisfied with data already on hand
1151  if(*received > 0)
1152  {
1153  //Some data are pending in the receive buffer
1154  error = NO_ERROR;
1155  break;
1156  }
1157  else
1158  {
1159  //The SSH_FX_EOF error code indicates end-of-file condition
1160  error = ERROR_END_OF_STREAM;
1161  }
1162  }
1163 
1164  //Update SFTP client state
1166  }
1167  else
1168  {
1169  //Just for sanity
1170  }
1171  }
1172  else if(context->state == SFTP_CLIENT_STATE_RECEIVING_DATA)
1173  {
1174  //The length of the payload shall not exceed the length of the
1175  //'data' field specified in the SSH_FXP_WRITE packet
1176  n = MIN(size - *received, context->dataLen);
1177 
1178  //Check whether there is any data left to read
1179  if(n > 0)
1180  {
1181  //Receive more data
1182  error = sshReadChannel(&context->sshChannel, data, n, &n, flags);
1183 
1184  //Check status code
1185  if(!error)
1186  {
1187  //Advance data pointer
1188  data = (uint8_t *) data + n;
1189  *received += n;
1190  context->dataLen -= n;
1191 
1192  //Increment file offset
1193  context->fileOffset += n;
1194 
1195  //Save current time
1196  context->timestamp = osGetSystemTime();
1197  }
1198 
1199  //Check status code
1200  if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1201  {
1202  //Process SSH connection events
1203  error = sftpClientProcessEvents(context);
1204  }
1205  }
1206  else
1207  {
1208  //Update SFTP client state
1210  }
1211  }
1212  else
1213  {
1214  //Invalid state
1215  error = ERROR_WRONG_STATE;
1216  }
1217  }
1218 
1219  //Check status code
1220  if(error == ERROR_WOULD_BLOCK)
1221  {
1222  //The user must be satisfied with data already on hand
1223  if(*received > 0)
1224  {
1225  error = NO_ERROR;
1226  }
1227  }
1228 
1229  //Return status code
1230  return error;
1231 }
1232 
1233 
1234 /**
1235  * @brief Close file
1236  * @param[in] context Pointer to the SFTP client context
1237  * @return Error code
1238  **/
1239 
1241 {
1242  error_t error;
1243 
1244  //Make sure the SFTP client context is valid
1245  if(context == NULL)
1246  return ERROR_INVALID_PARAMETER;
1247 
1248  //Initialize status code
1249  error = NO_ERROR;
1250 
1251  //Execute SFTP command
1252  while(!error)
1253  {
1254  //Check current state
1255  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
1256  {
1257  //Format SSH_FXP_CLOSE packet
1258  error = sftpClientFormatFxpClose(context, context->handle,
1259  context->handleLen);
1260 
1261  //Check status code
1262  if(!error)
1263  {
1264  //Send the SSH_FXP_CLOSE request and wait for the server's response
1266  }
1267  }
1268  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
1269  {
1270  //Send the SSH_FXP_CLOSE request and wait for the server's response
1271  error = sftpClientSendCommand(context);
1272 
1273  //Check status code
1274  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
1275  {
1276  //Update SFTP client state
1278  //We are done
1279  break;
1280  }
1281  }
1282  else
1283  {
1284  //Invalid state
1285  error = ERROR_WRONG_STATE;
1286  }
1287  }
1288 
1289  //Return status code
1290  return error;
1291 }
1292 
1293 
1294 /**
1295  * @brief Rename a file
1296  * @param[in] context Pointer to the SFTP client context
1297  * @param[in] oldPath Name of an existing file or directory
1298  * @param[in] newPath New name for the file or directory
1299  * @return Error code
1300  **/
1301 
1303  const char_t *newPath)
1304 {
1305  error_t error;
1306 
1307  //Check parameters
1308  if(context == NULL || oldPath == NULL || newPath == NULL)
1309  return ERROR_INVALID_PARAMETER;
1310 
1311  //The SSH_FXP_RENAME message was added in version 2
1312  if(context->version < SFTP_VERSION_2)
1313  return ERROR_INVALID_VERSION;
1314 
1315  //Initialize status code
1316  error = NO_ERROR;
1317 
1318  //Execute SFTP command
1319  while(!error)
1320  {
1321  //Check current state
1322  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
1323  {
1324  //Format SSH_FXP_RENAME packet
1325  error = sftpClientFormatFxpRename(context, oldPath, newPath);
1326 
1327  //Check status code
1328  if(!error)
1329  {
1330  //Send the SSH_FXP_RENAME request and wait for the server's response
1332  }
1333  }
1334  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
1335  {
1336  //Send the SSH_FXP_RENAME request and wait for the server's response
1337  error = sftpClientSendCommand(context);
1338 
1339  //Check status code
1340  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
1341  {
1342  //Update SFTP client state
1344  //We are done
1345  break;
1346  }
1347  }
1348  else
1349  {
1350  //Invalid state
1351  error = ERROR_WRONG_STATE;
1352  }
1353  }
1354 
1355  //Return status code
1356  return error;
1357 }
1358 
1359 
1360 /**
1361  * @brief Delete a file
1362  * @param[in] context Pointer to the SFTP client context
1363  * @param[in] path Path to the file to be be deleted
1364  * @return Error code
1365  **/
1366 
1368 {
1369  error_t error;
1370 
1371  //Check parameters
1372  if(context == NULL || path == NULL)
1373  return ERROR_INVALID_PARAMETER;
1374 
1375  //Initialize status code
1376  error = NO_ERROR;
1377 
1378  //Execute SFTP command
1379  while(!error)
1380  {
1381  //Check current state
1382  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
1383  {
1384  //Format SSH_FXP_REMOVE packet
1385  error = sftpClientFormatFxpRemove(context, path);
1386 
1387  //Check status code
1388  if(!error)
1389  {
1390  //Send the SSH_FXP_REMOVE request and wait for the server's response
1392  }
1393  }
1394  else if(context->state == SFTP_CLIENT_STATE_SENDING_COMMAND_1)
1395  {
1396  //Send the SSH_FXP_REMOVE request and wait for the server's response
1397  error = sftpClientSendCommand(context);
1398 
1399  //Check status code
1400  if(error == NO_ERROR || error == ERROR_UNEXPECTED_RESPONSE)
1401  {
1402  //Update SFTP client state
1404  //We are done
1405  break;
1406  }
1407  }
1408  else
1409  {
1410  //Invalid state
1411  error = ERROR_WRONG_STATE;
1412  }
1413  }
1414 
1415  //Return status code
1416  return error;
1417 }
1418 
1419 
1420 /**
1421  * @brief Retrieve SFTP status code
1422  * @param[in] context Pointer to the SFTP client context
1423  * @return SFTP status code
1424  **/
1425 
1427 {
1428  SftpStatusCode statusCode;
1429 
1430  //Make sure the SFTP client context is valid
1431  if(context != NULL)
1432  {
1433  //Get SFTP status code
1434  statusCode = (SftpStatusCode) context->statusCode;
1435  }
1436  else
1437  {
1438  //The SFTP client context is not valid
1439  statusCode = SSH_FX_FAILURE;
1440  }
1441 
1442  //Return SFTP status code
1443  return statusCode;
1444 }
1445 
1446 
1447 /**
1448  * @brief Gracefully disconnect from the SFTP server
1449  * @param[in] context Pointer to the SFTP client context
1450  * @return Error code
1451  **/
1452 
1454 {
1455  error_t error;
1456 
1457  //Make sure the SFTP client context is valid
1458  if(context == NULL)
1459  return ERROR_INVALID_PARAMETER;
1460 
1461  //Initialize status code
1462  error = NO_ERROR;
1463 
1464  //Gracefully disconnect from the SFTP server
1465  while(!error)
1466  {
1467  //Check current state
1468  if(context->state == SFTP_CLIENT_STATE_CONNECTED)
1469  {
1470  //Update SFTP client state
1472  }
1473  else if(context->state == SFTP_CLIENT_STATE_DISCONNECTING_1)
1474  {
1475  //When either party wishes to terminate the channel, it sends an
1476  //SSH_MSG_CHANNEL_CLOSE message
1477  error = sshCloseChannel(&context->sshChannel);
1478 
1479  //Check status code
1480  if(error == NO_ERROR)
1481  {
1482  //Send an SSH_MSG_DISCONNECT message
1483  error = sshSendDisconnect(&context->sshConnection,
1484  SSH_DISCONNECT_BY_APPLICATION, "Connection closed by user");
1485 
1486  //Check status code
1487  if(!error)
1488  {
1489  //Update SFTP client state
1491  }
1492  }
1493  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1494  {
1495  //Process SSH connection events
1496  error = sftpClientProcessEvents(context);
1497  }
1498  else
1499  {
1500  //Just for sanity
1501  }
1502  }
1503  else if(context->state == SFTP_CLIENT_STATE_DISCONNECTING_2)
1504  {
1505  //Wait for the SSH_MSG_DISCONNECT message to be transmitted
1506  error = sftpClientProcessEvents(context);
1507 
1508  //Check status code
1509  if(error == ERROR_CONNECTION_CLOSING)
1510  {
1511  //Catch exception
1512  error = NO_ERROR;
1513  //Set timeout
1514  socketSetTimeout(context->sshConnection.socket, context->timeout);
1515  //Update SFTP client state
1517  }
1518  }
1519  else if(context->state == SFTP_CLIENT_STATE_DISCONNECTING_3)
1520  {
1521  //Shutdown TCP connection
1522  error = socketShutdown(context->sshConnection.socket, SOCKET_SD_BOTH);
1523 
1524  //Check status code
1525  if(error == NO_ERROR)
1526  {
1527  //Close network connection
1528  sftpClientCloseConnection(context);
1529  //Update SFTP client state
1531  }
1532  else if(error == ERROR_WOULD_BLOCK || error == ERROR_TIMEOUT)
1533  {
1534  //Check whether the timeout has elapsed
1535  error = sftpClientCheckTimeout(context);
1536  }
1537  else
1538  {
1539  //A communication error has occurred
1540  }
1541  }
1542  else if(context->state == SFTP_CLIENT_STATE_DISCONNECTED)
1543  {
1544  //We are done
1545  break;
1546  }
1547  else
1548  {
1549  //Invalid state
1550  error = ERROR_WRONG_STATE;
1551  }
1552  }
1553 
1554  //Failed to gracefully disconnect from the SFTP server?
1555  if(error != NO_ERROR && error != ERROR_WOULD_BLOCK)
1556  {
1557  //Close network connection
1558  sftpClientCloseConnection(context);
1559  //Update SFTP client state
1561  }
1562 
1563  //Return status code
1564  return error;
1565 }
1566 
1567 
1568 /**
1569  * @brief Close the connection with the SFTP server
1570  * @param[in] context Pointer to the SFTP client context
1571  * @return Error code
1572  **/
1573 
1575 {
1576  //Make sure the SFTP client context is valid
1577  if(context == NULL)
1578  return ERROR_INVALID_PARAMETER;
1579 
1580  //Close network connection
1581  sftpClientCloseConnection(context);
1582  //Update SFTP client state
1584 
1585  //Successful processing
1586  return NO_ERROR;
1587 }
1588 
1589 
1590 /**
1591  * @brief Release SFTP client context
1592  * @param[in] context Pointer to the SFTP client context
1593  **/
1594 
1596 {
1597  //Make sure the SFTP client context is valid
1598  if(context != NULL)
1599  {
1600  //Close network connection
1601  sftpClientCloseConnection(context);
1602 
1603  //Clear SFTP client context
1604  osMemset(context, 0, sizeof(SftpClientContext));
1605  }
1606 }
1607 
1608 #endif
error_t sftpClientWriteFile(SftpClientContext *context, const void *data, size_t length, size_t *written, uint_t flags)
Write to a remote file.
Definition: sftp_client.c:915
error_t sftpClientCloseDir(SftpClientContext *context)
Close directory.
Definition: sftp_client.c:666
error_t sftpClientFormatFxpWrite(SftpClientContext *context, const uint8_t *handle, size_t handleLen, uint64_t offset, uint32_t dataLen)
Format SSH_FXP_WRITE packet.
SftpStatusCode sftpClientGetStatusCode(SftpClientContext *context)
Retrieve SFTP status code.
Definition: sftp_client.c:1426
#define SFTP_CLIENT_BUFFER_SIZE
Definition: sftp_client.h:75
@ ERROR_WOULD_BLOCK
Definition: error.h:96
SFTP packet parsing and formatting.
uint64_t size
Definition: sftp_client.h:185
IP network address.
Definition: ip.h:90
error_t sftpClientFormatFxpRename(SftpClientContext *context, const char_t *oldPath, const char_t *newPath)
Format SSH_FXP_RENAME packet.
error_t sftpClientFormatFxpRemove(SftpClientContext *context, const char_t *filename)
Format SSH_FXP_REMOVE packet.
error_t sftpClientFormatFxpRmDir(SftpClientContext *context, const char_t *path)
Format SSH_FXP_RMDIR packet.
#define SFTP_CLIENT_DEFAULT_TIMEOUT
Definition: sftp_client.h:61
uint8_t data[]
Definition: ethernet.h:224
error_t sshCloseChannel(SshChannel *channel)
Close channel.
Definition: ssh.c:2490
error_t sftpClientFormatFxpReadDir(SftpClientContext *context, const uint8_t *handle, size_t handleLen)
Format SSH_FXP_READDIR packet.
error_t sftpClientSetTimeout(SftpClientContext *context, systime_t timeout)
Set communication timeout.
Definition: sftp_client.c:103
SSH transport layer protocol.
@ SFTP_CLIENT_STATE_RECEIVING_NAME
Definition: sftp_client.h:129
@ SFTP_CLIENT_STATE_CONNECTING
Definition: sftp_client.h:118
error_t sftpClientOpenConnection(SftpClientContext *context)
Open SSH connection.
char_t name[]
uint16_t totalLength
Definition: ipv4.h:347
Directory entry.
Definition: sftp_client.h:182
error_t sftpClientRenameFile(SftpClientContext *context, const char_t *oldPath, const char_t *newPath)
Rename a file.
Definition: sftp_client.c:1302
error_t sftpClientBindToInterface(SftpClientContext *context, NetInterface *interface)
Bind the SFTP client to a particular network interface.
Definition: sftp_client.c:124
@ ERROR_END_OF_STREAM
Definition: error.h:211
error_t sftpClientProcessEvents(SftpClientContext *context)
Process SFTP client events.
@ ERROR_INVALID_VERSION
Definition: error.h:118
@ SFTP_CLIENT_STATE_SENDING_DATA
Definition: sftp_client.h:127
@ ERROR_WRONG_STATE
Definition: error.h:210
error_t sshReadChannel(SshChannel *channel, void *data, size_t size, size_t *received, uint_t flags)
Receive data from the specified channel.
Definition: ssh.c:2205
#define SFTP_CLIENT_MAX_PATH_LEN
Definition: sftp_client.h:96
SftpStatusCode
Status codes.
Definition: sftp_common.h:170
error_t sftpClientCheckTimeout(SftpClientContext *context)
Determine whether a timeout error has occurred.
@ SSH_DISCONNECT_BY_APPLICATION
Definition: ssh.h:1030
error_t sftpClientOpenFile(SftpClientContext *context, const char_t *path, uint_t mode)
Open a file for reading, writing, or appending.
Definition: sftp_client.c:848
error_t sftpClientCloseFile(SftpClientContext *context)
Close file.
Definition: sftp_client.c:1240
char_t name[SFTP_CLIENT_MAX_FILENAME_LEN+1]
Definition: sftp_client.h:183
error_t sftpClientFormatFxpInit(SftpClientContext *context, uint32_t version)
Format SSH_FXP_INIT packet.
@ ERROR_INVALID_PARAMETER
Invalid parameter.
Definition: error.h:47
error_t sftpClientFormatFxpRealPath(SftpClientContext *context, const char_t *path)
Format SSH_FXP_REALPATH packet.
error_t sftpClientConnect(SftpClientContext *context, const IpAddr *serverIpAddr, uint16_t serverPort)
Establish a connection with the specified SFTP server.
Definition: sftp_client.c:147
error_t
Error codes.
Definition: error.h:43
error_t(* SftpClientSshInitCallback)(SftpClientContext *context, SshContext *sshContext)
SSH initialization callback function.
Definition: sftp_client.h:140
error_t sftpParseName(SftpVersion version, SftpName *name, const uint8_t *data, size_t length, size_t *consumed)
Parse name structure.
Definition: sftp_common.c:370
error_t sftpClientInit(SftpClientContext *context)
Initialize SFTP client context.
Definition: sftp_client.c:52
@ SFTP_CLIENT_STATE_CHANNEL_REQUEST
Definition: sftp_client.h:122
error_t sftpClientEstablishConnection(SftpClientContext *context)
Establish SSH connection.
@ SFTP_CLIENT_STATE_CONNECTED
Definition: sftp_client.h:119
#define NetInterface
Definition: net.h:40
@ SSH_FX_FAILURE
Definition: sftp_common.h:175
NetContext * netGetDefaultContext(void)
Get default TCP/IP stack context.
Definition: net.c:527
error_t sftpClientDisconnect(SftpClientContext *context)
Gracefully disconnect from the SFTP server.
Definition: sftp_client.c:1453
error_t sshWriteChannel(SshChannel *channel, const void *data, size_t length, size_t *written, uint_t flags)
Write data to the specified channel.
Definition: ssh.c:2076
error_t sshSendDisconnect(SshConnection *connection, uint32_t reasonCode, const char_t *description)
Send SSH_MSG_DISCONNECT message.
error_t socketConnect(Socket *socket, const IpAddr *remoteIpAddr, uint16_t remotePort)
Establish a connection to a specified socket.
Definition: socket.c:1377
SFTP client.
@ SFTP_CLIENT_STATE_DISCONNECTING_2
Definition: sftp_client.h:131
error_t socketShutdown(Socket *socket, uint_t how)
Disable reception, transmission, or both.
Definition: socket.c:2052
@ ERROR_UNEXPECTED_RESPONSE
Definition: error.h:70
uint8_t length
Definition: tcp.h:375
error_t sftpClientFormatFxpOpen(SftpClientContext *context, const char_t *filename, uint32_t pflags)
Format SSH_FXP_OPEN packet.
#define MIN(a, b)
Definition: os_port.h:63
error_t sftpClientClose(SftpClientContext *context)
Close the connection with the SFTP server.
Definition: sftp_client.c:1574
error_t sftpClientCreateDir(SftpClientContext *context, const char_t *path)
Create a new directory.
Definition: sftp_client.c:727
error_t sftpClientFormatFxpRead(SftpClientContext *context, const uint8_t *handle, size_t handleLen, uint64_t offset, uint32_t dataLen)
Format SSH_FXP_READ packet.
error_t sftpClientReadDir(SftpClientContext *context, SftpDirEntry *dirEntry)
Read an entry from the directory.
Definition: sftp_client.c:511
error_t sftpClientChangeWorkingDir(SftpClientContext *context, const char_t *path)
Change working directory.
Definition: sftp_client.c:343
@ SFTP_CLIENT_STATE_CHANNEL_REPLY
Definition: sftp_client.h:123
@ ERROR_CONNECTION_CLOSING
Definition: error.h:78
@ SFTP_VERSION_2
Definition: sftp_common.h:121
Helper functions for SFTP client.
void sftpClientChangeState(SftpClientContext *context, SftpClientState newState)
Update SFTP client state.
uint32_t systime_t
System time.
error_t sftpClientDeleteFile(SftpClientContext *context, const char_t *path)
Delete a file.
Definition: sftp_client.c:1367
@ ERROR_TIMEOUT
Definition: error.h:95
char char_t
Definition: compiler_port.h:55
Name structure.
Definition: sftp_common.h:265
@ SFTP_CLIENT_STATE_DISCONNECTING_1
Definition: sftp_client.h:130
#define SFTP_CLIENT_MAX_PACKET_SIZE
Definition: sftp_client.h:68
error_t sftpClientDeleteDir(SftpClientContext *context, const char_t *path)
Remove a directory.
Definition: sftp_client.c:787
uint32_t permissions
Definition: sftp_client.h:186
@ SFTP_CLIENT_STATE_RECEIVING_DATA
Definition: sftp_client.h:128
error_t sftpClientRegisterSshInitCallback(SftpClientContext *context, SftpClientSshInitCallback callback)
Register SSH initialization callback function.
Definition: sftp_client.c:81
uint8_t n
#define SftpClientContext
Definition: sftp_client.h:103
@ ERROR_INVALID_DIRECTORY
Definition: error.h:164
@ SFTP_CLIENT_STATE_CHANNEL_DATA
Definition: sftp_client.h:124
@ SFTP_CLIENT_STATE_SENDING_COMMAND_1
Definition: sftp_client.h:125
uint32_t type
Definition: sftp_client.h:184
const char_t * sftpClientGetWorkingDir(SftpClientContext *context)
Get current working directory.
Definition: sftp_client.c:316
void sftpGetAbsolutePath(SftpClientContext *context, const char_t *path, char_t *fullPath)
Retrieve the full pathname.
#define osStrncpy(s1, s2, length)
Definition: os_port.h:216
@ SFTP_CLIENT_STATE_SENDING_COMMAND_2
Definition: sftp_client.h:126
error_t sftpClientFormatFxpMkDir(SftpClientContext *context, const char_t *path)
Format SSH_FXP_MKDIR packet.
@ SFTP_CLIENT_STATE_DISCONNECTING_3
Definition: sftp_client.h:132
error_t sftpClientOpenDir(SftpClientContext *context, const char_t *path)
Open a directory.
Definition: sftp_client.c:451
error_t sftpClientChangeToParentDir(SftpClientContext *context)
Change to parent directory.
Definition: sftp_client.c:437
void sftpClientCloseConnection(SftpClientContext *context)
Close SSH connection.
@ SFTP_CLIENT_STATE_CHANNEL_OPEN
Definition: sftp_client.h:120
uint8_t flags
Definition: tcp.h:358
DateTime modified
Definition: sftp_client.h:187
unsigned int uint_t
Definition: compiler_port.h:57
void sftpClientDeinit(SftpClientContext *context)
Release SFTP client context.
Definition: sftp_client.c:1595
error_t sftpClientSendCommand(SftpClientContext *context)
Send SFTP request and wait for a response.
#define osMemset(p, value, length)
Definition: os_port.h:138
@ SFTP_CLIENT_STATE_CHANNEL_OPEN_REPLY
Definition: sftp_client.h:121
Secure Shell (SSH)
error_t sftpClientFormatFxpOpenDir(SftpClientContext *context, const char_t *path)
Format SSH_FXP_OPENDIR packet.
@ SOCKET_SD_BOTH
Definition: socket.h:161
#define osStrcpy(s1, s2)
Definition: os_port.h:210
#define SFTP_CLIENT_MAX_FILENAME_LEN
Definition: sftp_client.h:89
error_t socketSetTimeout(Socket *socket, systime_t timeout)
Set timeout value for blocking operations.
Definition: socket.c:169
@ SSH_FX_EOF
Definition: sftp_common.h:172
@ SFTP_CLIENT_STATE_DISCONNECTED
Definition: sftp_client.h:117
error_t sftpClientReadFile(SftpClientContext *context, void *data, size_t size, size_t *received, uint_t flags)
Read from a remote file.
Definition: sftp_client.c:1089
@ NO_ERROR
Success.
Definition: error.h:44
Debugging facilities.
#define osMemmove(dest, src, length)
Definition: os_port.h:150
#define SFTP_CLIENT_MAX_VERSION
Definition: sftp_client.h:54
error_t sftpClientFormatFxpClose(SftpClientContext *context, const uint8_t *handle, size_t handleLen)
Format SSH_FXP_CLOSE packet.
systime_t osGetSystemTime(void)
Retrieve system time.