1892 linhas
56 KiB
C
1892 linhas
56 KiB
C
/**
|
|
* @file ardrone_ftp.c
|
|
* @author nicolas.brulez@parrot.com
|
|
* @date 2011/04/06
|
|
* Copyright Parrot SA. 2011
|
|
*/
|
|
|
|
#include <utils/ardrone_ftp.h>
|
|
|
|
#include <stdio.h>
|
|
#include <netdb.h>
|
|
#include <unistd.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
#include <arpa/inet.h>
|
|
|
|
#include <VP_Os/vp_os_thread.h>
|
|
#include <VP_Os/vp_os_malloc.h>
|
|
#include <VP_Os/vp_os_signal.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <VP_Os/vp_os_print.h>
|
|
|
|
/* CONFIGURATION */
|
|
|
|
// All following macros MUST be defined !
|
|
// To activate, define to (1)
|
|
// To deactivate, define to (0)
|
|
|
|
#ifdef DEBUG // Debug options
|
|
#define _FTP_DEBUG (0) // Common debug informations
|
|
#define _FTP_VERBOSE (0) // Extended debug information (many outputs on ftpList)
|
|
#define _FTP_ERRORS_PRINT (1) // Display of error messages
|
|
#else // Release options
|
|
#define _FTP_DEBUG (0)
|
|
#define _FTP_VERBOSE (0)
|
|
#define _FTP_ERRORS_PRINT (0)
|
|
#endif
|
|
|
|
#define FTP_PREFIX "FTP : "
|
|
|
|
/* LOCAL PRINT MACROS */
|
|
|
|
#if _FTP_ERRORS_PRINT
|
|
#define FTP_ERROR(...) \
|
|
do \
|
|
{ \
|
|
PRINT ("Error in function %s at line %d : ", __FUNCTION__, __LINE__); \
|
|
PRINT (__VA_ARGS__); \
|
|
char *errorBuffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1); \
|
|
if (NULL != errorBuffer) \
|
|
{ \
|
|
snprintf (errorBuffer, COMMAND_BUFFER_SIZE-1, __VA_ARGS__); \
|
|
FTPlastErrorMessageSize = strlen (errorBuffer) + 1; \
|
|
FTPlastErrorMessage = vp_os_realloc (FTPlastErrorMessage, FTPlastErrorMessageSize); \
|
|
if (NULL != FTPlastErrorMessage) \
|
|
{ \
|
|
strncpy (FTPlastErrorMessage, errorBuffer, FTPlastErrorMessageSize); \
|
|
} \
|
|
vp_os_free (errorBuffer); \
|
|
} \
|
|
} while (0)
|
|
#else
|
|
#define FTP_ERROR(...) \
|
|
do \
|
|
{ \
|
|
char *errorBuffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1); \
|
|
if (NULL != errorBuffer) \
|
|
{ \
|
|
snprintf (errorBuffer, COMMAND_BUFFER_SIZE-1, __VA_ARGS__); \
|
|
FTPlastErrorMessageSize = strlen (errorBuffer) + 1; \
|
|
FTPlastErrorMessage = vp_os_realloc (FTPlastErrorMessage, FTPlastErrorMessageSize); \
|
|
if (NULL != FTPlastErrorMessage) \
|
|
{ \
|
|
strncpy (FTPlastErrorMessage, errorBuffer, FTPlastErrorMessageSize); \
|
|
} \
|
|
vp_os_free (errorBuffer); \
|
|
} \
|
|
} while (0)
|
|
#endif
|
|
|
|
#if _FTP_DEBUG
|
|
#define FTP_DEBUG(...) \
|
|
do \
|
|
{ \
|
|
PRINT ("Debug from function %s at line %d : ", __FUNCTION__, __LINE__); \
|
|
PRINT (__VA_ARGS__); \
|
|
} while (0)
|
|
#else
|
|
#define FTP_DEBUG(...)
|
|
#endif
|
|
|
|
#if _FTP_VERBOSE
|
|
#define FTP_PRINT(...) \
|
|
do \
|
|
{ \
|
|
PRINT (FTP_PREFIX); \
|
|
PRINT (__VA_ARGS__); \
|
|
} while (0)
|
|
#else
|
|
#define FTP_PRINT(...)
|
|
#endif
|
|
|
|
/* SIZE MACROS */
|
|
|
|
#ifndef MAX_SIZE_MSG
|
|
#define MAX_SIZE_MSG 32768
|
|
#endif
|
|
#ifndef COMMAND_BUFFER_SIZE
|
|
#define COMMAND_BUFFER_SIZE 512
|
|
#endif
|
|
#define IP_STRING_SIZE 16 // IP strings goes from 8 ("w.x.y.z\0") to 16 ("www.xxx.yyy.zzz\0") chars
|
|
#define LIST_BUFFER_BLOCKSIZE 1024
|
|
#define FILE_NAME_MAX_SIZE 512
|
|
|
|
/* TIMEOUT MACROS */
|
|
|
|
/* Total socket timeout : SOCK_TO_SEC + SOCK_TO_USEC */
|
|
#define SOCK_TO_SEC 3 // Socket timeout (seconds)
|
|
#define SOCK_TO_USEC 0 // Socket timeout (useconds)
|
|
|
|
/* GLOBAL ERROR MESSAGE STRING */
|
|
char *FTPlastErrorMessage = NULL;
|
|
int FTPlastErrorMessageSize = 0;
|
|
|
|
/* THREAD STRUCTURES */
|
|
|
|
typedef struct _ftp_list_param_s _ftp_list_param;
|
|
typedef struct _ftp_get_param_s _ftp_get_param;
|
|
typedef struct _ftp_put_param_s _ftp_put_param;
|
|
|
|
struct _ftp_put_param_s
|
|
{
|
|
_ftp_t *ftp;
|
|
char localName [FILE_NAME_MAX_SIZE];
|
|
char remoteName [FILE_NAME_MAX_SIZE];
|
|
int useResume;
|
|
ftp_callback callback;
|
|
char *fileList;
|
|
};
|
|
|
|
struct _ftp_get_param_s
|
|
{
|
|
_ftp_t *ftp;
|
|
char localName [FILE_NAME_MAX_SIZE];
|
|
char remoteName [FILE_NAME_MAX_SIZE];
|
|
int useResume;
|
|
ftp_callback callback;
|
|
char *fileList;
|
|
};
|
|
|
|
struct _ftp_list_param_s
|
|
{
|
|
_ftp_t *ftp;
|
|
char *fileList;
|
|
int listSize;
|
|
ftp_callback callback;
|
|
};
|
|
|
|
/* LOCAL FUNCTIONS PROTOTYPES */
|
|
int isLANIp (const char *ip);
|
|
void emptyCallback (_ftp_status status, void *arg, _ftp_t *callingFtp);
|
|
_ftp_status waitFor226Answer (_ftp_t *ftp);
|
|
int setSockTimeout (int socket, int timeoutSec, int timeoutUsec);
|
|
_ftp_status goToBinaryMode (_ftp_t *ftp);
|
|
void flushFtp (_ftp_t *ftp);
|
|
int getFileSize (_ftp_t *ftp, const char *distPath);
|
|
int getLocalFileSize (const char *localPath);
|
|
int getResponseCode (const char *response);
|
|
_ftp_status getPassiveIpAndPort (_ftp_t *ftp, const char *response, char *ip, int *port, int ipLen);
|
|
_ftp_status ftpTransfert (_ftp_t *ftp, const char *message, char *answer, int answSize);
|
|
_ftp_status ftpSend (_ftp_t *ftp, const char *message);
|
|
_ftp_status ftpRecv (_ftp_t *ftp, char *answer, int answSize);
|
|
DEFINE_THREAD_ROUTINE (ftpGet, param);
|
|
DEFINE_THREAD_ROUTINE (ftpPut, param);
|
|
DEFINE_THREAD_ROUTINE (ftpList, param);
|
|
|
|
/* FUNCTIONS IMPLEMENTATION */
|
|
int
|
|
isLANIp (const char *ip)
|
|
{
|
|
int retVal = -1;
|
|
uint32_t ip0, ip1, ip2, ip3;
|
|
if (4 == sscanf (ip, "%u.%u.%u.%u", &ip0, &ip1, &ip2, &ip3))
|
|
{
|
|
/* LAN address classes :
|
|
* 127.x.x.x
|
|
* 10.x.x.x
|
|
* 192.168.x.x
|
|
* 169.254.x.x
|
|
* 172.[16-31].x.x
|
|
*
|
|
* Test IP is :
|
|
* ip0.ip1.ip2.ip3
|
|
*/
|
|
if (((127 == ip0)) ||
|
|
((10 == ip0)) ||
|
|
((192 == ip0) && (168 == ip1)) ||
|
|
((169 == ip0) && (254 == ip1)) ||
|
|
((172 == ip0) && (16 <= ip1) && (31 >= ip1)))
|
|
{
|
|
retVal = 1;
|
|
}
|
|
else
|
|
{
|
|
retVal = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
FTP_ERROR ("String %s does not represent a valid ipv4 address\n", ip);
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
void
|
|
emptyCallback (_ftp_status status, void *arg, _ftp_t *callingFtp)
|
|
{
|
|
FTP_PRINT ("Called with status %d\n", status);
|
|
#if _FTP_VERBOSE
|
|
if (FTP_PROGRESS == status)
|
|
{
|
|
FTP_PRINT ("Trying float arg : %f\n", (NULL != arg) ? *(float *)arg : -1.0);
|
|
}
|
|
#endif
|
|
if (NULL != callingFtp)
|
|
{
|
|
callingFtp->lastStatus = status;
|
|
if(FTP_SUCCESS == status && NULL != arg)
|
|
{
|
|
callingFtp->lastFileList = (char *)arg;
|
|
}
|
|
}
|
|
}
|
|
|
|
#define FTP_MAX_NUM_RETRIES 10
|
|
_ftp_status
|
|
waitFor226Answer (_ftp_t *ftp)
|
|
{
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
return FTP_FAIL;
|
|
}
|
|
int repCode = 0;
|
|
int numretries = FTP_MAX_NUM_RETRIES;
|
|
|
|
_ftp_status ftp_result = FTP_SUCCESS;
|
|
while (226 != repCode && 0 < numretries)
|
|
{
|
|
ftp_result = ftpRecv (ftp, srvMsg, MAX_SIZE_MSG-1);
|
|
numretries--;
|
|
repCode = getResponseCode (srvMsg);
|
|
}
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
int
|
|
setSockTimeout (int socket, int timeoutSec, int timeoutUsec)
|
|
{
|
|
#ifdef _WIN32
|
|
int winTO = (1000 * timeoutSec) + (timeoutUsec / 1000);
|
|
#else
|
|
struct timeval posixTO;
|
|
posixTO.tv_sec = timeoutSec;
|
|
posixTO.tv_usec = timeoutUsec;
|
|
#endif
|
|
|
|
if (0 > setsockopt (socket, SOL_SOCKET, SO_RCVTIMEO,
|
|
#ifdef _WIN32
|
|
(const char *)&winTO, sizeof (winTO)
|
|
#else
|
|
(const char *)&posixTO, sizeof (posixTO)
|
|
#endif
|
|
))
|
|
{
|
|
FTP_ERROR ("Unable to set recv timeout\n");
|
|
return -1;
|
|
}
|
|
|
|
if (0 > setsockopt (socket, SOL_SOCKET, SO_SNDTIMEO,
|
|
#ifdef _WIN32
|
|
(const char *)&winTO, sizeof (winTO)
|
|
#else
|
|
(const char *)&posixTO, sizeof (posixTO)
|
|
#endif
|
|
))
|
|
{
|
|
FTP_ERROR ("Unable to set send timeout\n");
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
_ftp_status
|
|
goToBinaryMode (_ftp_t *ftp)
|
|
{
|
|
char *ftpAnswer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
if (NULL == ftpAnswer)
|
|
{
|
|
return FTP_FAIL;
|
|
}
|
|
_ftp_status ftp_result = ftpTransfert (ftp, "TYPE I\r\n\0", ftpAnswer, COMMAND_BUFFER_SIZE-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to go to binary mode\n");
|
|
}
|
|
vp_os_free (ftpAnswer);
|
|
return ftp_result;
|
|
}
|
|
|
|
void
|
|
flushFtp (_ftp_t *ftp)
|
|
{
|
|
FTP_DEBUG ("Starting flush\n");
|
|
char c = 0;
|
|
int bytes = 1;
|
|
int flushedBytes = 0;
|
|
VP_COM_SOCKET_BLOCKING_OPTIONS oldOptions = ftp->socket->block;
|
|
ftp->socket->block = VP_COM_DONTWAIT;
|
|
C_RESULT vp_result = ftp->readSock (ftp->socket, (uint8_t *)&c, &bytes);
|
|
while (0 < bytes && VP_SUCCEEDED (vp_result))
|
|
{
|
|
flushedBytes++;
|
|
#if _FTP_DEBUG
|
|
printf ("%c", c);
|
|
#endif
|
|
vp_result = ftp->readSock (ftp->socket, (uint8_t *)&c, &bytes);
|
|
}
|
|
FTP_DEBUG ("Flushed %d bytes\n", flushedBytes);
|
|
ftp->socket->block = oldOptions;
|
|
}
|
|
|
|
int
|
|
getFileSize (_ftp_t *ftp, const char *distPath)
|
|
{
|
|
char *ftpCommand = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *ftpAnswer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
if (NULL == ftpCommand || NULL == ftpAnswer)
|
|
{
|
|
vp_os_free (ftpCommand);
|
|
vp_os_free (ftpAnswer);
|
|
return -1;
|
|
}
|
|
snprintf (ftpCommand, COMMAND_BUFFER_SIZE-1, "SIZE %s\r\n", distPath);
|
|
_ftp_status ftp_result = ftpTransfert (ftp, ftpCommand, ftpAnswer, COMMAND_BUFFER_SIZE-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to get file size\n");
|
|
vp_os_free (ftpCommand);
|
|
vp_os_free (ftpAnswer);
|
|
return -1;
|
|
}
|
|
int size = -1;
|
|
int repCode = 0;
|
|
sscanf (ftpAnswer, "%d %d", &repCode, &size);
|
|
vp_os_free (ftpCommand);
|
|
vp_os_free (ftpAnswer);
|
|
return size;
|
|
}
|
|
|
|
int
|
|
getLocalFileSize (const char *localPath)
|
|
{
|
|
FILE *localFile = fopen (localPath, "r");
|
|
if (NULL == localFile)
|
|
{
|
|
FTP_DEBUG ("File %s does not exist\n", localPath);
|
|
return -1;
|
|
}
|
|
fseek (localFile, 0, SEEK_END);
|
|
int size = (int)ftell (localFile);
|
|
FTP_DEBUG ("Size of file %s : %d o\n", localPath, size);
|
|
fclose (localFile);
|
|
return size;
|
|
}
|
|
|
|
int
|
|
getResponseCode (const char *response)
|
|
{
|
|
int retVal = -1;
|
|
sscanf (response, "%d", &retVal);
|
|
return retVal;
|
|
}
|
|
|
|
_ftp_status
|
|
getPassiveIpAndPort (_ftp_t *ftp, const char *response, char *ip, int *port, int ipLen)
|
|
{
|
|
int ip1, ip2, ip3, ip4, port1, port2;
|
|
int indexOfFirstIpField = 0;
|
|
char atIndex = '\0';
|
|
int maxIndex = strlen (response);
|
|
while (indexOfFirstIpField < maxIndex && '(' != atIndex)
|
|
{
|
|
atIndex = response[indexOfFirstIpField++];
|
|
}
|
|
int numread = sscanf (&response[indexOfFirstIpField], "%d,%d,%d,%d,%d,%d)", &ip1, &ip2, &ip3, &ip4, &port1, &port2);
|
|
_ftp_status result = FTP_SUCCESS;
|
|
if (6 == numread)
|
|
{
|
|
snprintf (ip, ipLen-1, "%d.%d.%d.%d", ip1, ip2, ip3, ip4);
|
|
*port = 256 * port1 + port2;
|
|
FTP_DEBUG ("IP : %s | Port : %d\n", ip, *port);
|
|
}
|
|
else
|
|
{
|
|
result = FTP_FAIL;
|
|
}
|
|
int pasvIsLan = isLANIp (ip);
|
|
int servIsLan = isLANIp (ftp->socket->serverHost);
|
|
if (-1 == pasvIsLan || -1 == servIsLan)
|
|
{
|
|
// Error while parsing IP ...
|
|
result = FTP_FAIL;
|
|
}
|
|
else if (1 == pasvIsLan && 0 == servIsLan)
|
|
{
|
|
FTP_DEBUG ("pasv ip is a LAN ip (not routable), but server ip is not a LAN ip. We'll use the server ip (%s) instead of the pasv ip (%s)\n", ftp->socket->serverHost, ip);
|
|
strncpy (ip, ftp->socket->serverHost, ipLen);
|
|
}
|
|
// No else : if pasv addr is routable or if both address are LAN address, keep pasv ip.
|
|
|
|
return result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpTransfert (_ftp_t *ftp, const char *message, char *answer, int answSize)
|
|
{
|
|
flushFtp (ftp);
|
|
_ftp_status ftp_result = ftpSend (ftp, message);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
return ftp_result;
|
|
}
|
|
return ftpRecv (ftp, answer, answSize);
|
|
}
|
|
|
|
_ftp_status
|
|
ftpSend (_ftp_t *ftp, const char *message)
|
|
{
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
FTP_DEBUG ("Sending %sto FTP at %s:%d\n", message, ftp->socket->serverHost, ftp->socket->port);
|
|
|
|
int bytes = strlen (message);
|
|
C_RESULT vp_result = ftp->writeSock (ftp->socket, (uint8_t *)message, &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending data\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (0 == bytes)
|
|
{
|
|
FTP_ERROR ("Unable to send data\n");
|
|
return FTP_TIMEOUT;
|
|
}
|
|
return FTP_SUCCESS;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpRecv (_ftp_t *ftp, char *answer, int answSize)
|
|
{
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
vp_os_memset (answer, 0x0, answSize);
|
|
int index = 0;
|
|
do
|
|
{
|
|
int bytes = 1;
|
|
C_RESULT vp_result = ftp->readSock (ftp->socket, (uint8_t *)(&answer [index]), &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Error while reading data\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (0 == bytes)
|
|
{
|
|
FTP_ERROR ("Recv timeout\n");
|
|
return FTP_TIMEOUT;
|
|
}
|
|
}
|
|
while (index < answSize && '\n' != answer [index++]);
|
|
|
|
FTP_DEBUG ("Answer:\n<---START--->\n%s\n<---END--->\n", answer);
|
|
return FTP_SUCCESS;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpClose (_ftp_t **ftp)
|
|
{
|
|
FTP_DEBUG ("Closing ftp\n");
|
|
_ftp_status retVal = FTP_FAIL;
|
|
if (NULL != *ftp)
|
|
{
|
|
FTP_DEBUG ("Not null ftp\n");
|
|
if (NULL != (*ftp)->socket)
|
|
{
|
|
FTP_DEBUG ("Not null socket\n");
|
|
if (1 == (*ftp)->connected)
|
|
{
|
|
if (FTP_SUCCESS == ftpAbort ((*ftp))) // An operation was in progress, abort and let time to cleanup.
|
|
{
|
|
usleep (100000); // 100ms
|
|
}
|
|
ftpSend ((*ftp), "QUIT\r\n\0");
|
|
(*ftp)->connected = 0;
|
|
}
|
|
vp_com_close_socket ((*ftp)->socket);
|
|
vp_os_free ((*ftp)->socket);
|
|
(*ftp)->socket = NULL;
|
|
retVal = FTP_SUCCESS;
|
|
}
|
|
vp_os_free (*ftp);
|
|
*ftp = NULL;
|
|
}
|
|
return retVal;
|
|
}
|
|
|
|
_ftp_t *
|
|
ftpConnectFromName (const char *name, int port, const char *username, const char *password, _ftp_status *status)
|
|
{
|
|
struct hostent *hostent = gethostbyname(name);
|
|
return ftpConnect(inet_ntoa( *( struct in_addr*)( hostent->h_addr)), port, username, password, status);
|
|
}
|
|
|
|
_ftp_t *
|
|
ftpConnect (const char *ip, int port, const char *username, const char *password, _ftp_status *status)
|
|
{
|
|
if (NULL == ip ||
|
|
NULL == username ||
|
|
NULL == password ||
|
|
NULL == status)
|
|
{
|
|
FTP_ERROR ("Must not pass NULL pointers to ftpConnect\n");
|
|
if (NULL != status) { *status = FTP_FAIL; }
|
|
return NULL;
|
|
}
|
|
int isAnonymous = ((0 == strcmp (username, "anonymous")) || (0 == strcmp (username, ""))) ? 1 : 0;
|
|
if (1 == isAnonymous)
|
|
{
|
|
FTP_DEBUG ("Connecting to %s:%d, anonymous\n", ip, port);
|
|
}
|
|
else
|
|
{
|
|
FTP_DEBUG ("Connecting to %s:%d, USER = %s, Password = %s\n", ip, port, username, password);
|
|
}
|
|
|
|
*status = FTP_FAIL;
|
|
_ftp_t *retFtp = vp_os_malloc (sizeof (_ftp_t));
|
|
if (NULL == retFtp)
|
|
{
|
|
FTP_ERROR ("Unable to allocate a ftp structure\n");
|
|
return NULL;
|
|
}
|
|
retFtp->lastStatus = FTP_SUCCESS;
|
|
retFtp->lastFileList = NULL;
|
|
|
|
retFtp->socket = vp_os_malloc (sizeof (vp_com_socket_t));
|
|
if (NULL == retFtp->socket)
|
|
{
|
|
FTP_ERROR ("Unable to allocate socket filed of the ftp structure\n");
|
|
ftpClose (&retFtp);
|
|
return NULL;
|
|
}
|
|
|
|
retFtp->connected = 0;
|
|
|
|
retFtp->socket->type = VP_COM_CLIENT;
|
|
retFtp->socket->protocol = VP_COM_TCP;
|
|
retFtp->socket->port = port;
|
|
strncpy (retFtp->socket->serverHost, ip, VP_COM_NAME_MAXSIZE-1);
|
|
retFtp->socket->is_multicast = 0;
|
|
retFtp->socket->block = VP_COM_DEFAULT;
|
|
|
|
C_RESULT vp_result = vp_com_open_socket (retFtp->socket, &(retFtp->readSock), &(retFtp->writeSock));
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to connect\n");
|
|
ftpClose (&retFtp);
|
|
return NULL;
|
|
}
|
|
|
|
int result = setSockTimeout ((int)retFtp->socket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
|
|
if (0 > result)
|
|
{
|
|
FTP_ERROR ("Unable to set socket timeout\n");
|
|
ftpClose (&retFtp);
|
|
return NULL;
|
|
}
|
|
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to allocate buffer\n");
|
|
ftpClose (&retFtp);
|
|
return NULL;
|
|
}
|
|
if (FTP_FAILED (ftpRecv (retFtp, srvMsg, MAX_SIZE_MSG-1)))
|
|
{
|
|
FTP_ERROR ("Unable to recieve data from server\n");
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
return NULL;
|
|
}
|
|
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (220 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 220)\n", repCode);
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
return NULL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
if (NULL == buffer)
|
|
{
|
|
FTP_ERROR ("Unable to allocate buffer\n");
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
return NULL;
|
|
}
|
|
if (1 == isAnonymous)
|
|
{
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "USER anonymous\r\n");
|
|
}
|
|
else
|
|
{
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "USER %s\r\n", username);
|
|
}
|
|
if (FTP_FAILED (ftpTransfert (retFtp, buffer, srvMsg, MAX_SIZE_MSG-1)))
|
|
{
|
|
FTP_ERROR ("Error while sending command\n");
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
vp_os_free (buffer);
|
|
return NULL;
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
int goodRepCode = 331;
|
|
if (1 == isAnonymous)
|
|
{
|
|
goodRepCode = 230;
|
|
}
|
|
if (goodRepCode != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected %d)\n", repCode, goodRepCode);
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
vp_os_free (buffer);
|
|
return NULL;
|
|
}
|
|
|
|
if (0 == isAnonymous)
|
|
{
|
|
vp_os_memset (buffer, 0x0, COMMAND_BUFFER_SIZE);
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "PASS %s\r\n", password);
|
|
if (FTP_FAILED (ftpTransfert (retFtp, buffer, srvMsg, MAX_SIZE_MSG-1)))
|
|
{
|
|
FTP_ERROR ("Error while sending command\n");
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
vp_os_free (buffer);
|
|
return NULL;
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
if (230 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 230)\n", repCode);
|
|
ftpClose (&retFtp);
|
|
vp_os_free (srvMsg);
|
|
vp_os_free (buffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
*status = FTP_SUCCESS;
|
|
retFtp->connected = 1;
|
|
retFtp->opInProgress = 0;
|
|
retFtp->abortCurrentOp = 0;
|
|
retFtp->tag = NULL;
|
|
vp_os_free (srvMsg);
|
|
vp_os_free (buffer);
|
|
return retFtp;
|
|
}
|
|
|
|
|
|
#undef CLEAN_PARAMS
|
|
#define CLEAN_PARAMS(status) CLEAN_PARAMS_WITH_ARG(status,NULL)
|
|
#undef CLEAN_PARAMS_WITH_ARG
|
|
#define CLEAN_PARAMS_WITH_ARG(status,arg) \
|
|
do \
|
|
{ \
|
|
if (NULL != params->ftp) \
|
|
{ \
|
|
params->ftp->opInProgress = 0; \
|
|
} \
|
|
CLEAN_PARAMS_ABORT (status,arg); \
|
|
} while (0)
|
|
#undef CLEAN_PARAMS_ABORT
|
|
#define CLEAN_PARAMS_ABORT(status,arg) \
|
|
do \
|
|
{ \
|
|
_ftp_status locStat = (status); \
|
|
if (NULL != localFile) fclose (localFile); \
|
|
if (NULL != srvMsg) vp_os_free (srvMsg); \
|
|
if (NULL != buffer) vp_os_free (buffer); \
|
|
if (NULL != filePart) vp_os_free (filePart); \
|
|
if (NULL != dataSocket) \
|
|
{ \
|
|
vp_com_close_socket (dataSocket); \
|
|
vp_os_free (dataSocket); \
|
|
dataSocket = NULL; \
|
|
} \
|
|
params->callback (locStat, arg, params->ftp); \
|
|
if (FTP_SUCCESS != status && NULL != params->fileList) \
|
|
{ \
|
|
vp_os_free (params->fileList); \
|
|
params->fileList = NULL; \
|
|
} \
|
|
vp_os_free (param); \
|
|
FTP_DEBUG ("Returning from thread %s with status %d\n", __FUNCTION__, locStat); \
|
|
THREAD_RETURN (locStat); \
|
|
} \
|
|
while (0)
|
|
#undef CHECK_ABORT
|
|
#define CHECK_ABORT \
|
|
do \
|
|
{ \
|
|
if (1 <= params->ftp->abortCurrentOp) \
|
|
{ \
|
|
vp_os_memset (srvMsg, 0x0, MAX_SIZE_MSG); \
|
|
if (NULL != dataSocket) \
|
|
{ \
|
|
vp_com_close_socket (dataSocket); \
|
|
vp_os_free (dataSocket); \
|
|
dataSocket = NULL; \
|
|
} \
|
|
ftpTransfert (params->ftp, "ABOR\r\n\0", srvMsg, MAX_SIZE_MSG-1); \
|
|
flushFtp (params->ftp); \
|
|
params->ftp->abortCurrentOp = 0; \
|
|
params->ftp->opInProgress = 0; \
|
|
CLEAN_PARAMS_ABORT (FTP_ABORT, NULL); \
|
|
} \
|
|
} while (0)
|
|
|
|
DEFINE_THREAD_ROUTINE (ftpList, param)
|
|
{
|
|
char *srvMsg = NULL;
|
|
char *buffer = NULL; // Compatibility with macros
|
|
char *filePart = NULL; // Compatibility with macros
|
|
FILE *localFile = NULL; // Compatibilty with macros
|
|
vp_com_socket_t *dataSocket = NULL;
|
|
Read dataRead = NULL;
|
|
Write dataWrite = NULL;
|
|
_ftp_list_param *params = (_ftp_list_param *)param;
|
|
if (NULL == params->ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
flushFtp (params->ftp);
|
|
|
|
srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to allocate buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
_ftp_status ftp_result = ftpTransfert (params->ftp, "PASV\r\n\0", srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending command\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (227 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
char dataIp [IP_STRING_SIZE] = {0};
|
|
int dataPort = 0;
|
|
getPassiveIpAndPort (params->ftp, srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
|
|
|
|
FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
|
|
dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
|
|
if (NULL == dataSocket)
|
|
{
|
|
FTP_ERROR ("Unable to allocate socket structure\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
dataSocket->type = VP_COM_CLIENT;
|
|
dataSocket->protocol = VP_COM_TCP;
|
|
dataSocket->port = dataPort;
|
|
strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
|
|
dataSocket->is_multicast = 0;
|
|
dataSocket->block = VP_COM_WAITALL;
|
|
|
|
C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to connect\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
|
|
if (0 > result)
|
|
{
|
|
FTP_ERROR ("Unable to set data socket timeout\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
CHECK_ABORT;
|
|
|
|
ftp_result = ftpSend (params->ftp, "LIST\r\n\0");
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending LIST command\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
|
|
CHECK_ABORT;
|
|
char ftpData [2] = {0};
|
|
int bytes = 1, totalBytes;
|
|
vp_os_memset (params->fileList, 0x0, params->listSize);
|
|
vp_result = dataRead (dataSocket, (uint8_t *)ftpData, &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to receive data\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
if(0 == bytes)
|
|
{
|
|
FTP_DEBUG ("Empty folder\n");
|
|
waitFor226Answer (params->ftp);
|
|
flushFtp (params->ftp);
|
|
CLEAN_PARAMS (FTP_SAMESIZE);
|
|
}
|
|
|
|
if (strlen (ftpData) > params->listSize - 1)
|
|
{
|
|
params->listSize += LIST_BUFFER_BLOCKSIZE;
|
|
params->fileList = vp_os_realloc(params->fileList, params->listSize);
|
|
if(NULL == params->fileList)
|
|
{
|
|
FTP_ERROR ("Not enough space in response string, can't reallocate buffer list\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
}
|
|
snprintf (params->fileList, params->listSize-1, "%s", ftpData);
|
|
totalBytes = bytes;
|
|
while (1) // Loop is killed by a return or a break statement
|
|
{
|
|
CHECK_ABORT;
|
|
ftpData [0] = 0;
|
|
bytes = 1;
|
|
vp_result = dataRead (dataSocket, (uint8_t *)ftpData, &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to receive data\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
if (0 == bytes && '\n' == params->fileList [totalBytes-1])
|
|
{
|
|
FTP_DEBUG ("Got all listing !\n");
|
|
// Timeouted. We got all the listing !
|
|
// Timeout is voluntary, so still return FTP_SUCCESS
|
|
break;
|
|
}
|
|
else if (0 == bytes)
|
|
{
|
|
// Timeout
|
|
FTP_ERROR ("Recv timeout\n");
|
|
CLEAN_PARAMS (FTP_TIMEOUT);
|
|
}
|
|
if (strlen (ftpData) > (params->listSize - 1 - strlen (params->fileList)))
|
|
{
|
|
params->listSize += LIST_BUFFER_BLOCKSIZE;
|
|
params->fileList = vp_os_realloc(params->fileList, params->listSize);
|
|
if(NULL == params->fileList)
|
|
{
|
|
FTP_ERROR ("Not enough space in response string, can't reallocate buffer list\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
}
|
|
strcat (params->fileList, ftpData);
|
|
totalBytes += bytes;
|
|
FTP_PRINT ("Progress of listing : finished ? %d : (%d->%d bytes) %s\n", (params->response [totalBytes -1] == '\n') ? 1: 0, bytes, totalBytes, params->response);
|
|
}
|
|
|
|
ftp_result = ftpRecv (params->ftp, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while getting answer\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
if (150 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
/* Cleaning FTP */
|
|
if (NULL != dataSocket)
|
|
{
|
|
vp_com_close_socket (dataSocket);
|
|
vp_os_free (dataSocket);
|
|
dataSocket = NULL;
|
|
}
|
|
_ftp_status loc226Status = waitFor226Answer (params->ftp);
|
|
flushFtp (params->ftp);
|
|
|
|
|
|
CLEAN_PARAMS_WITH_ARG (loc226Status, (void *)params->fileList);
|
|
}
|
|
|
|
DEFINE_THREAD_ROUTINE (ftpGet, param)
|
|
{
|
|
char *srvMsg = NULL;
|
|
char *buffer = NULL;
|
|
char *filePart = NULL;
|
|
vp_com_socket_t *dataSocket = NULL;
|
|
Read dataRead = NULL;
|
|
Write dataWrite = NULL;
|
|
FILE *localFile = NULL;
|
|
_ftp_get_param *params = (_ftp_get_param *)param;
|
|
FTP_DEBUG ("Downloading %s to %s [resume : %c]\n", params->remoteName, params->localName, params->useResume ? 'y' : 'n');
|
|
if (NULL == params->ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
flushFtp (params->ftp);
|
|
|
|
buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
if (NULL == buffer)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "PASV\r\n");
|
|
_ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while entering passive mode\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (227 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
char dataIp [IP_STRING_SIZE] = {0};
|
|
int dataPort = 0;
|
|
getPassiveIpAndPort (params->ftp, srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
|
|
|
|
ftp_result = goToBinaryMode (params->ftp);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to go to binary mode\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
|
|
int fileSize = getFileSize (params->ftp, params->remoteName);
|
|
if (0 > fileSize)
|
|
{
|
|
FTP_ERROR ("File %s does not exist on server\n", params->remoteName);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
int sizeToGet = fileSize;
|
|
int localFileSize = getLocalFileSize (params->localName);
|
|
int appendToFile = params->useResume;
|
|
int appendOffset = 0;
|
|
if (-1 == localFileSize && 0 == fileSize)
|
|
{
|
|
// Zero byte file on server
|
|
FTP_DEBUG ("Zero byte file on server, create empty file locally\n");
|
|
FILE *fdesc = fopen (params->localName, "ab");
|
|
if (NULL != fdesc)
|
|
{
|
|
fclose (fdesc);
|
|
}
|
|
CLEAN_PARAMS (FTP_SUCCESS);
|
|
}
|
|
|
|
if (-1 == localFileSize && 1 == params->useResume)
|
|
{
|
|
FTP_DEBUG ("File does not exist ... full download\n");
|
|
appendToFile = 0;
|
|
}
|
|
if (1 == appendToFile)
|
|
{
|
|
if (localFileSize == fileSize)
|
|
{
|
|
FTP_DEBUG ("File already downloaded\n");
|
|
CLEAN_PARAMS (FTP_SAMESIZE);
|
|
}
|
|
else if (localFileSize > fileSize)
|
|
{
|
|
FTP_ERROR ("Local file (%s) is greater than distant file (%s)\n", params->localName, params->remoteName);
|
|
CLEAN_PARAMS (FTP_BADSIZE);
|
|
}
|
|
sizeToGet = fileSize - localFileSize;
|
|
|
|
appendOffset = fileSize - sizeToGet;
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "REST %d\r\n", appendOffset);
|
|
_ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to set server offset\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
}
|
|
|
|
FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
|
|
dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
|
|
if (NULL == dataSocket)
|
|
{
|
|
FTP_ERROR ("Unable to allocate socket structure\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
dataSocket->type = VP_COM_CLIENT;
|
|
dataSocket->protocol = VP_COM_TCP;
|
|
dataSocket->port = dataPort;
|
|
strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
|
|
dataSocket->is_multicast = 0;
|
|
dataSocket->block = VP_COM_WAITALL;
|
|
|
|
C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to connect\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
|
|
if (0 > result)
|
|
{
|
|
FTP_ERROR ("Unable to set data socket timeout\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
CHECK_ABORT;
|
|
|
|
vp_os_memset (buffer, 0x0, COMMAND_BUFFER_SIZE);
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "RETR %s\r\n", params->remoteName);
|
|
ftp_result = ftpSend (params->ftp, buffer);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending RETR command\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
|
|
int sizeGot = appendOffset;
|
|
float percentGot = (sizeGot * 100.0) / (fileSize *1.0);
|
|
params->callback (FTP_PROGRESS, (void *)&percentGot, params->ftp);
|
|
|
|
filePart = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == filePart)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
if (1 == appendToFile)
|
|
{
|
|
localFile = fopen (params->localName, "ab");
|
|
}
|
|
else
|
|
{
|
|
localFile = fopen (params->localName, "wb");
|
|
}
|
|
if (NULL == localFile)
|
|
{
|
|
FTP_ERROR ("Unable to open dest file %s\n", params->localName);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
while (sizeGot < fileSize)
|
|
{
|
|
CHECK_ABORT;
|
|
int bytes = MAX_SIZE_MSG-1;
|
|
C_RESULT vp_result = dataRead (dataSocket, (uint8_t *)filePart, &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Error while receiving data\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
if (0 >= bytes)
|
|
{
|
|
FTP_ERROR ("Recv timeout\n");
|
|
CLEAN_PARAMS (FTP_TIMEOUT);
|
|
}
|
|
if (0 > fwrite (filePart, 1, bytes, localFile))
|
|
{
|
|
FTP_ERROR ("Unable to write to file\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
sizeGot += bytes;
|
|
percentGot = (sizeGot * 100.0) / (fileSize * 1.0);
|
|
params->callback (FTP_PROGRESS, (void *)&percentGot, params->ftp);
|
|
}
|
|
ftp_result = ftpRecv (params->ftp, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while getting answer\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
if (150 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
/* Cleaning FTP */
|
|
if (NULL != dataSocket)
|
|
{
|
|
vp_com_close_socket (dataSocket);
|
|
vp_os_free (dataSocket);
|
|
dataSocket = NULL;
|
|
}
|
|
_ftp_status loc226Status = waitFor226Answer (params->ftp);
|
|
flushFtp (params->ftp);
|
|
|
|
CLEAN_PARAMS (loc226Status);
|
|
}
|
|
|
|
DEFINE_THREAD_ROUTINE (ftpPut, param)
|
|
{
|
|
char *srvMsg = NULL;
|
|
char *buffer = NULL;
|
|
char *filePart = NULL;
|
|
vp_com_socket_t *dataSocket = NULL;
|
|
Read dataRead = NULL;
|
|
Write dataWrite = NULL;
|
|
FILE *localFile = NULL;
|
|
_ftp_put_param *params = (_ftp_put_param *)param;
|
|
FTP_DEBUG ("Uploading %s to %s [resume : %c]\n", params->localName, params->remoteName, params->useResume ? 'y' : 'n');
|
|
if (NULL == params->ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
flushFtp (params->ftp);
|
|
|
|
buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
if (NULL == buffer)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "PASV\r\n");
|
|
_ftp_status ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while entering passive mode\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (227 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 227)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
char dataIp [IP_STRING_SIZE] = {0};
|
|
int dataPort = 0;
|
|
getPassiveIpAndPort (params->ftp, srvMsg, dataIp, &dataPort, IP_STRING_SIZE);
|
|
|
|
ftp_result = goToBinaryMode (params->ftp);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to go to binary mode\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
|
|
int localFileSize = getLocalFileSize (params->localName);
|
|
if (0 >= localFileSize)
|
|
{
|
|
FTP_ERROR ("File %s does not exist on filesystem\n", params->localName);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
int fileSize = getFileSize (params->ftp, params->remoteName);
|
|
int sizeToPut = localFileSize;
|
|
int appendToFile = params->useResume;
|
|
int appendOffset = 0;
|
|
if (-1 == fileSize && 1 == params->useResume)
|
|
{
|
|
FTP_DEBUG ("File does not exist on server ... full upload\n");
|
|
appendToFile = 0;
|
|
}
|
|
if (1 == appendToFile)
|
|
{
|
|
if (localFileSize == fileSize)
|
|
{
|
|
FTP_DEBUG ("File already uploaded\n");
|
|
CLEAN_PARAMS (FTP_SAMESIZE);
|
|
}
|
|
else if (localFileSize < fileSize)
|
|
{
|
|
FTP_ERROR ("Distant file (%s) is greather than local file (%s)\n", params->remoteName, params->localName);
|
|
CLEAN_PARAMS (FTP_BADSIZE);
|
|
}
|
|
sizeToPut = localFileSize - fileSize;
|
|
|
|
appendOffset = localFileSize - sizeToPut;
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "REST %d\r\n", appendOffset);
|
|
ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Unable to set server offset\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
}
|
|
|
|
FTP_DEBUG ("Thread will connect to %s:%d\n", dataIp, dataPort);
|
|
dataSocket = vp_os_malloc (sizeof (vp_com_socket_t));
|
|
if (NULL == dataSocket)
|
|
{
|
|
FTP_ERROR ("Unable to allocate socket structure\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
dataSocket->type = VP_COM_CLIENT;
|
|
dataSocket->protocol = VP_COM_TCP;
|
|
dataSocket->port = dataPort;
|
|
strncpy (dataSocket->serverHost, dataIp, VP_COM_NAME_MAXSIZE);
|
|
dataSocket->is_multicast = 0;
|
|
dataSocket->block = VP_COM_DEFAULT;
|
|
|
|
C_RESULT vp_result = vp_com_open_socket (dataSocket, &dataRead, &dataWrite);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to connect\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
int result = setSockTimeout ((int)dataSocket->priv, SOCK_TO_SEC, SOCK_TO_USEC);
|
|
if (0 > result)
|
|
{
|
|
FTP_ERROR ("Unable to set data socket timeout\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
CHECK_ABORT;
|
|
|
|
vp_os_memset (buffer, 0x0, COMMAND_BUFFER_SIZE);
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "STOR %s\r\n", params->remoteName);
|
|
ftp_result = ftpTransfert (params->ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending command\n");
|
|
CLEAN_PARAMS (ftp_result);
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
if (150 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 150)\n", repCode);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
int sizeSent = appendOffset;
|
|
float percentSend = (sizeSent * 100.0) / (localFileSize *1.0);
|
|
params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
|
|
|
|
int numberOfFullSendNeeded = (sizeToPut / (MAX_SIZE_MSG-1));
|
|
int partialSendNeeded = (sizeToPut % (MAX_SIZE_MSG-1)); // Zero if not needed, non-zero if needed
|
|
filePart = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == filePart)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer \n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
|
|
localFile = fopen (params->localName, "rb");
|
|
if (NULL == localFile)
|
|
{
|
|
FTP_ERROR ("Unable to open source file %s\n", params->localName);
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
fseek (localFile, appendOffset, SEEK_SET);
|
|
|
|
int numSend = 0;
|
|
for (numSend = 0; numSend < numberOfFullSendNeeded; numSend++)
|
|
{
|
|
CHECK_ABORT;
|
|
int bytes = fread (filePart, 1, MAX_SIZE_MSG-1, localFile);
|
|
if (MAX_SIZE_MSG-1 != bytes)
|
|
{
|
|
FTP_ERROR ("Unable to read from file\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
C_RESULT vp_result = dataWrite (dataSocket, (uint8_t *)filePart, &bytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to send data\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
if (MAX_SIZE_MSG-1 > bytes)
|
|
{
|
|
FTP_ERROR ("Send timeout\n");
|
|
CLEAN_PARAMS (FTP_TIMEOUT);
|
|
}
|
|
sizeSent += bytes;
|
|
percentSend = (sizeSent * 100.0) / (localFileSize * 1.0);
|
|
params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
|
|
}
|
|
|
|
if (0 != partialSendNeeded)
|
|
{
|
|
CHECK_ABORT;
|
|
vp_os_memset (filePart, 0x0, MAX_SIZE_MSG);
|
|
int bytes = fread (filePart, 1, MAX_SIZE_MSG-1, localFile);
|
|
FTP_DEBUG ("Read %d bytes\n", bytes);
|
|
if (0 > bytes)
|
|
{
|
|
FTP_ERROR ("Unable to read from file\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
int sendBytes = bytes;
|
|
C_RESULT vp_result = dataWrite (dataSocket, (uint8_t *)filePart, &sendBytes);
|
|
if (VP_FAILED (vp_result))
|
|
{
|
|
FTP_ERROR ("Unable to send data\n");
|
|
CLEAN_PARAMS (FTP_FAIL);
|
|
}
|
|
if (bytes > sendBytes)
|
|
{
|
|
FTP_ERROR ("Send timeout\n");
|
|
CLEAN_PARAMS (FTP_TIMEOUT);
|
|
}
|
|
sizeSent += bytes;
|
|
percentSend = (sizeSent * 100.0) / (localFileSize * 1.0);
|
|
params->callback (FTP_PROGRESS, (void *)&percentSend, params->ftp);
|
|
}
|
|
|
|
|
|
/* Cleaning FTP */
|
|
if (NULL != dataSocket)
|
|
{
|
|
vp_com_close_socket (dataSocket);
|
|
vp_os_free (dataSocket);
|
|
dataSocket = NULL;
|
|
}
|
|
_ftp_status loc226Status = waitFor226Answer (params->ftp);
|
|
flushFtp (params->ftp);
|
|
|
|
CLEAN_PARAMS (loc226Status);
|
|
}
|
|
|
|
|
|
_ftp_status
|
|
ftpPut (_ftp_t *ftp, const char *localName, const char *remoteName, int useResume, ftp_callback callback)
|
|
{
|
|
THREAD_HANDLE putThread;
|
|
ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
|
|
if (NULL == ftp)
|
|
{
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
return FTP_FAIL;
|
|
}
|
|
if (1 == ftp->opInProgress)
|
|
{
|
|
actualCallback (FTP_BUSY, NULL, ftp);
|
|
return FTP_BUSY;
|
|
}
|
|
ftp->opInProgress = 1;
|
|
|
|
_ftp_put_param *param = vp_os_malloc (sizeof (_ftp_put_param));
|
|
|
|
if (NULL == param)
|
|
{
|
|
FTP_ERROR ("Unable to allocate thread param\n");
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
ftp->opInProgress = 0;
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
param->ftp = ftp;
|
|
strncpy (param->localName, localName, FILE_NAME_MAX_SIZE);
|
|
param->localName [FILE_NAME_MAX_SIZE-1] = '\0';
|
|
strncpy (param->remoteName, remoteName, FILE_NAME_MAX_SIZE);
|
|
param->remoteName [FILE_NAME_MAX_SIZE-1] = '\0';
|
|
param->useResume = useResume;
|
|
param->callback = actualCallback;
|
|
param->fileList = NULL;
|
|
_ftp_status threadReturn = FTP_SUCCESS;
|
|
|
|
vp_os_thread_create (thread_ftpPut, (THREAD_PARAMS)param, &putThread);
|
|
|
|
if (NULL == callback)
|
|
{
|
|
vp_os_thread_join (putThread);
|
|
threadReturn = ftp->lastStatus;
|
|
}
|
|
|
|
return threadReturn;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpGet (_ftp_t *ftp, const char *remoteName, const char *localName, int useResume, ftp_callback callback)
|
|
{
|
|
THREAD_HANDLE getThread;
|
|
ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
|
|
if (NULL == ftp)
|
|
{
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
return FTP_FAIL;
|
|
}
|
|
if (1 == ftp->opInProgress)
|
|
{
|
|
actualCallback (FTP_BUSY, NULL, ftp);
|
|
return FTP_BUSY;
|
|
}
|
|
ftp->opInProgress = 1;
|
|
|
|
_ftp_get_param *param = vp_os_malloc (sizeof (_ftp_get_param));
|
|
|
|
if (NULL == param)
|
|
{
|
|
FTP_ERROR ("Unable to allocate thread param\n");
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
ftp->opInProgress = 0;
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
param->ftp = ftp;
|
|
strncpy (param->localName, localName, FILE_NAME_MAX_SIZE);
|
|
param->localName [FILE_NAME_MAX_SIZE-1] = '\0';
|
|
strncpy (param->remoteName, remoteName, FILE_NAME_MAX_SIZE);
|
|
param->remoteName [FILE_NAME_MAX_SIZE-1] = '\0';
|
|
param->useResume = useResume;
|
|
param->callback = actualCallback;
|
|
param->fileList = NULL;
|
|
_ftp_status threadReturn = FTP_SUCCESS;
|
|
|
|
vp_os_thread_create (thread_ftpGet, (THREAD_PARAMS)param, &getThread);
|
|
|
|
if (NULL == callback)
|
|
{
|
|
vp_os_thread_join (getThread);
|
|
threadReturn = ftp->lastStatus;
|
|
}
|
|
|
|
return threadReturn;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpList (_ftp_t *ftp, char **fileList, ftp_callback callback)
|
|
{
|
|
if (NULL == fileList && NULL == callback)
|
|
{
|
|
FTP_ERROR ("file list and callback pointer must not be both NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
THREAD_HANDLE listThread;
|
|
ftp_callback actualCallback = (NULL != callback) ? callback : emptyCallback;
|
|
if (NULL == ftp)
|
|
{
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
return FTP_FAIL;
|
|
}
|
|
if (1 == ftp->opInProgress)
|
|
{
|
|
actualCallback (FTP_BUSY, NULL, ftp);
|
|
return FTP_BUSY;
|
|
}
|
|
ftp->opInProgress = 1;
|
|
|
|
_ftp_list_param *param = vp_os_malloc (sizeof (_ftp_list_param));
|
|
|
|
if (NULL == param)
|
|
{
|
|
FTP_ERROR ("Unable to allocate thread param\n");
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
ftp->opInProgress = 0;
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
param->fileList = vp_os_malloc (sizeof (char) * LIST_BUFFER_BLOCKSIZE);
|
|
if (NULL == param->fileList)
|
|
{
|
|
FTP_ERROR ("Unable to allocate list buffer\n");
|
|
actualCallback (FTP_FAIL, NULL, ftp);
|
|
ftp->opInProgress = 0;
|
|
vp_os_free (param);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
param->ftp = ftp;
|
|
param->listSize = LIST_BUFFER_BLOCKSIZE;
|
|
param->callback = actualCallback;
|
|
_ftp_status threadReturn = FTP_SUCCESS;
|
|
|
|
vp_os_thread_create (thread_ftpList, (THREAD_PARAMS)param, &listThread);
|
|
|
|
if (NULL == callback)
|
|
{
|
|
vp_os_thread_join (listThread);
|
|
threadReturn = ftp->lastStatus;
|
|
if (FTP_SUCCESS == threadReturn)
|
|
{
|
|
*fileList = ftp->lastFileList;
|
|
ftp->lastFileList = NULL;
|
|
}
|
|
}
|
|
|
|
return threadReturn;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpRemove (_ftp_t *ftp, const char *remoteName)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == remoteName)
|
|
{
|
|
FTP_ERROR ("remoteName must not be a NULL pointer\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == buffer || NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "DELE %s\r\n", remoteName);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the delete command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (250 != repCode && 550 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpRename (_ftp_t *ftp, const char *origin, const char *dest)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == origin ||
|
|
NULL == dest)
|
|
{
|
|
FTP_ERROR ("origin and dest pointers must not be NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == buffer || NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "RNFR %s\r\n", origin);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the RNFR command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (350 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 350)\n", repCode);
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
ftp_result = FTP_FAIL;
|
|
return ftp_result;
|
|
}
|
|
|
|
vp_os_memset (buffer, 0x0, COMMAND_BUFFER_SIZE);
|
|
vp_os_memset (srvMsg, 0x0, MAX_SIZE_MSG);
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "RNTO %s\r\n", dest);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the RNTO command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
repCode = getResponseCode (srvMsg);
|
|
if (250 == repCode) // Rename worked
|
|
{
|
|
ftp_result = FTP_SUCCESS;
|
|
}
|
|
else if (550 == repCode) // Source file don't exist
|
|
{
|
|
FTP_DEBUG ("File %s doest not exist on FTP\n", origin);
|
|
ftp_result = FTP_SAMESIZE;
|
|
}
|
|
else
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpCd (_ftp_t *ftp, const char *nextDir)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == nextDir)
|
|
{
|
|
FTP_ERROR ("nextDir must not be NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == buffer || NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "CWD %s\r\n", nextDir);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the CWD command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (250 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 250)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpPwd (_ftp_t *ftp, char *workingDir, int wdLen)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == workingDir)
|
|
{
|
|
FTP_ERROR ("workingDir must not be NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
ftp_result = ftpTransfert (ftp, "PWD\r\n\0", srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the CWD command\n");
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (257 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 257)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
else
|
|
{
|
|
int pwdStartIndex = 0;
|
|
int pwdEndIndex = 0;
|
|
for (pwdStartIndex = 0; (pwdStartIndex < MAX_SIZE_MSG) && (srvMsg[pwdStartIndex] != '\"'); pwdStartIndex++);
|
|
for (pwdEndIndex = pwdStartIndex+1; (pwdEndIndex < MAX_SIZE_MSG) && (srvMsg[pwdEndIndex] != '\"'); pwdEndIndex++);
|
|
if (MAX_SIZE_MSG == pwdStartIndex ||
|
|
MAX_SIZE_MSG == pwdEndIndex)
|
|
{
|
|
FTP_ERROR ("FTP Answer does not conains PWD\n");
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
else
|
|
{
|
|
int srvLen = pwdEndIndex - (pwdStartIndex + 1);
|
|
int totalLen = (srvLen < wdLen) ? srvLen : wdLen;
|
|
strncpy (workingDir, &(srvMsg[pwdStartIndex+1]), totalLen);
|
|
FTP_DEBUG ("PWD is %s\n", workingDir);
|
|
}
|
|
}
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpMkdir (_ftp_t *ftp, const char *dirName)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == dirName)
|
|
{
|
|
FTP_ERROR ("dirName must not be NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == buffer || NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "MKD %s\r\n", dirName);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the MKD command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (257 != repCode)
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 257)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status
|
|
ftpRmdir (_ftp_t *ftp, const char *dirName)
|
|
{
|
|
_ftp_status ftp_result = FTP_FAIL;
|
|
|
|
if (NULL == dirName)
|
|
{
|
|
FTP_ERROR ("dirName must not be NULL\n");
|
|
return FTP_FAIL;
|
|
}
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
char *buffer = vp_os_calloc (COMMAND_BUFFER_SIZE, 1);
|
|
char *srvMsg = vp_os_calloc (MAX_SIZE_MSG, 1);
|
|
if (NULL == buffer || NULL == srvMsg)
|
|
{
|
|
FTP_ERROR ("Unable to alloc buffer\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return FTP_FAIL;
|
|
}
|
|
|
|
snprintf (buffer, COMMAND_BUFFER_SIZE-1, "RMD %s\r\n", dirName);
|
|
ftp_result = ftpTransfert (ftp, buffer, srvMsg, MAX_SIZE_MSG-1);
|
|
if (FTP_FAILED (ftp_result))
|
|
{
|
|
FTP_ERROR ("Error while sending the RMD command\n");
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
int repCode = getResponseCode (srvMsg);
|
|
if (250 == repCode) // Deleted
|
|
{
|
|
FTP_DEBUG ("Successfully deleted %s directory\n", dirName);
|
|
ftp_result = FTP_SUCCESS;
|
|
}
|
|
else if (550 == repCode) // Didn't exist / not empty
|
|
{
|
|
FTP_DEBUG ("Did not delete directory %s : did not exist or was not empty\n", dirName);
|
|
ftp_result = FTP_BADSIZE;
|
|
}
|
|
else
|
|
{
|
|
FTP_ERROR ("Bad response from server (%d, expected 250 or 550)\n", repCode);
|
|
ftp_result = FTP_FAIL;
|
|
}
|
|
vp_os_free (buffer);
|
|
vp_os_free (srvMsg);
|
|
return ftp_result;
|
|
}
|
|
|
|
_ftp_status ftpAbort (_ftp_t *ftp)
|
|
{
|
|
_ftp_status retVal = FTP_FAIL;
|
|
if (NULL == ftp)
|
|
{
|
|
FTP_ERROR ("FTP not open\n");
|
|
}
|
|
else
|
|
{
|
|
if (1 == ftp->opInProgress)
|
|
{
|
|
ftp->abortCurrentOp = 1;
|
|
retVal = FTP_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
retVal = FTP_SAMESIZE;
|
|
}
|
|
}
|
|
return retVal;
|
|
}
|