Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of Smoothie by
libs/Network/uip/sftp/sftpd.cpp
- Committer:
- Michael J. Spencer
- Date:
- 2014-02-28
- Revision:
- 2:1df0b61d3b5a
File content as of revision 2:1df0b61d3b5a:
#pragma GCC diagnostic ignored "-Wunused-but-set-variable" #include "sftpd.h" #include "string.h" #include "stdlib.h" extern "C" { #include "uip.h" } #define ISO_nl 0x0a #define ISO_cr 0x0d #define ISO_sp 0x20 #define DEBUG_PRINTF(...) Sftpd::Sftpd() { fd = NULL; state = STATE_NORMAL; outbuf = NULL; filename= NULL; } Sftpd::~Sftpd() { if (fd != NULL) { fclose(fd); } } int Sftpd::senddata() { if (outbuf != NULL) { DEBUG_PRINTF("sftp: senddata %s\n", outbuf); strcpy((char *)uip_appdata, outbuf); uip_send(uip_appdata, strlen(outbuf)); } return 0; } int Sftpd::handle_command() { PSOCK_BEGIN(&sin); do { PSOCK_READTO(&sin, ISO_nl); buf[PSOCK_DATALEN(&sin) - 1] = 0; int len = PSOCK_DATALEN(&sin) - 1; DEBUG_PRINTF("sftp: got command: %s, %d\n", buf, len); if (state == STATE_CONNECTED) { if (strncmp(buf, "USER", 4) == 0) { outbuf = "!user logged in\n"; } else if (strncmp(buf, "KILL", 4) == 0) { if (len < 6) { outbuf = "- incomplete KILL command\n"; } else { char *fn = &buf[5]; int s = remove(fn); if (s == 0) outbuf = "+ deleted\n"; else outbuf = "- delete failed\n"; } } else if (strncmp(buf, "DONE", 4) == 0) { outbuf = "+ exit\n"; state = STATE_CLOSE; } else if (strncmp(buf, "STOR", 4) == 0) { if (len < 11) { outbuf = "- incomplete STOR command\n"; } else { char *fn = &buf[9]; if(this->filename != NULL) free(this->filename); this->filename= strdup(fn); // REMOVE when bug fixed // get { NEW|OLD|APP } if (strncmp(&buf[5], "OLD", 3) == 0) { DEBUG_PRINTF("sftp: Opening file: %s\n", fn); fd = fopen(fn, "w"); if (fd != NULL) { outbuf = "+ new file\n"; state = STATE_GET_LENGTH; } else { outbuf = "- failed\n"; } } else if (strncmp(&buf[5], "APP", 3) == 0) { fd = fopen(fn, "a"); if (fd != NULL) { outbuf = "+ append file\n"; state = STATE_GET_LENGTH; } else { outbuf = "- failed\n"; } } else { outbuf = "- Only OLD|APP supported\n"; } } } else { outbuf = "- Unknown command\n"; } } else if (state == STATE_GET_LENGTH) { if (len < 6 || strncmp(buf, "SIZE", 4) != 0) { fclose(fd); fd = NULL; outbuf = "- Expected size\n"; state = STATE_CONNECTED; } else { filesize = atoi(&buf[5]); if (filesize > 0) { outbuf = "+ ok, waiting for file\n"; state = STATE_DOWNLOAD; } else { fclose(fd); fd = NULL; outbuf = "- bad filesize\n"; state = STATE_CONNECTED; } } } else { DEBUG_PRINTF("WTF state: %d\n", state); } } while(state == STATE_CONNECTED || state == STATE_GET_LENGTH); PSOCK_END(&sin); } int Sftpd::handle_download() { // Note this is not using PSOCK and it consumes all read data char *readptr = (char *)uip_appdata; unsigned int readlen = uip_datalen(); DEBUG_PRINTF("sftp: starting download, expecting %d bytes, read %d\n", filesize, readlen); if (filesize > 0 && readlen > 0) { if (readlen > filesize) readlen = filesize; if (fwrite(readptr, 1, readlen, fd) != readlen) { DEBUG_PRINTF("sftp: Error writing file\n"); fclose(fd); fd = NULL; outbuf = "- Error saving file\n"; state = STATE_CONNECTED; return 0; } filesize -= readlen; DEBUG_PRINTF("sftp: saved %d bytes %d left\n", readlen, filesize); // HACK ALERT... to work around the fwrite/filesystem bug where writing large amounts of data corrupts the file // we workaround by closing the file, the reopening for append until we are done fclose(fd); fd = fopen(this->filename, "a"); } if (filesize == 0) { DEBUG_PRINTF("sftp: download complete\n"); fclose(fd); fd = NULL; outbuf = "+ Saved file\n"; state = STATE_CONNECTED; return 0; } return 1; } int Sftpd::acked() { outbuf= NULL; return 0; } void Sftpd::appcall(void) { if (uip_connected()) { // TODO check for other connections PSOCK_INIT(&sin, buf, sizeof(buf)); state = STATE_CONNECTED; outbuf = "+Smoothie SFTP Service\n"; } if (state == STATE_CLOSE) { DEBUG_PRINTF("sftp: state close\n"); state = STATE_NORMAL; uip_close(); return; } if (uip_closed() || uip_aborted() || uip_timedout()) { DEBUG_PRINTF("sftp: closed\n"); if (fd != NULL) fclose(fd); fd = NULL; state = STATE_NORMAL; return; } if (uip_acked()) { DEBUG_PRINTF("sftp: acked\n"); this->acked(); } if (uip_newdata()) { DEBUG_PRINTF("sftp: newdata\n"); if (state == STATE_DOWNLOAD) { if(handle_download() == 0) { // we need to reset the input PSOCK again before using it after using the raw input buffer PSOCK_INIT(&sin, buf, sizeof(buf)); } } else { handle_command(); } } if (uip_rexmit() || uip_newdata() || uip_acked() || uip_connected() || uip_poll()) { this->senddata(); } } void Sftpd::init(void) { }