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