More FTP bugfixes

git-svn-id: svn://svn.code.sf.net/p/nuttx/code/trunk@3665 42af7a65-404d-4744-a932-0658087f49c3
This commit is contained in:
patacongo 2011-06-03 20:27:30 +00:00
parent a94c011b4e
commit da50c819f9
23 changed files with 350 additions and 209 deletions

View File

@ -56,9 +56,13 @@ examples/ftpc
to that it will only work as a "built-in" program that can be run from to that it will only work as a "built-in" program that can be run from
NSH when CONFIG_NSH_BUILTIN_APPS is defined. NSH when CONFIG_NSH_BUILTIN_APPS is defined.
From NSH, the startup command line is then: From NSH, the startup command sequence is as follows. This is only
an example, your configration could have different mass storage devices,
mount paths, and FTP directories:
ftpc xx.xx.xx.xx[:pp] mount -t vfat /dev/mmcsd0 /tmp # Mount the SD card at /tmp
cd /tmp # cd into the /tmp directory
ftpc xx.xx.xx.xx[:pp] # Start the FTP client
where xx.xx.xx.xx is the IP address of the FTP server and pp is an where xx.xx.xx.xx is the IP address of the FTP server and pp is an
optional port number. optional port number.

View File

@ -108,7 +108,7 @@ int cmd_rchdir(SESSION handle, int argc, char **argv)
int cmd_rpwd(SESSION handle, int argc, char **argv) int cmd_rpwd(SESSION handle, int argc, char **argv)
{ {
FAR char *pwd = ftpc_pwd(handle); FAR char *pwd = ftpc_rpwd(handle);
if (pwd) if (pwd)
{ {
printf("PWD: %s\n", pwd); printf("PWD: %s\n", pwd);
@ -178,8 +178,8 @@ int cmd_rrename(SESSION handle, int argc, char **argv)
int cmd_rsize(SESSION handle, int argc, char **argv) int cmd_rsize(SESSION handle, int argc, char **argv)
{ {
uint64_t size = ftpc_filesize(handle, argv[1]); off_t size = ftpc_filesize(handle, argv[1]);
printf("SIZE: %ull\n", size); printf("SIZE: %lu\n", size);
return OK; return OK;
} }
@ -190,7 +190,7 @@ int cmd_rsize(SESSION handle, int argc, char **argv)
int cmd_rtime(SESSION handle, int argc, char **argv) int cmd_rtime(SESSION handle, int argc, char **argv)
{ {
time_t filetime = ftpc_filetime(handle, argv[1]); time_t filetime = ftpc_filetime(handle, argv[1]);
printf("TIME: %ul\n", (long)filetime); printf("TIME: %lu\n", (long)filetime);
return OK; return OK;
} }
@ -264,6 +264,7 @@ int cmd_rls(SESSION handle, int argc, char **argv)
{ {
printf(" %s\n", dirlist->name[i]); printf(" %s\n", dirlist->name[i]);
} }
FFLUSH();
ftpc_dirfree(dirlist); ftpc_dirfree(dirlist);
return OK; return OK;

View File

@ -42,6 +42,7 @@
#include <nuttx/config.h> #include <nuttx/config.h>
#include <sys/types.h>
#include <stdbool.h> #include <stdbool.h>
#include <signal.h> #include <signal.h>
#include <time.h> #include <time.h>
@ -184,7 +185,7 @@ EXTERN int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login);
EXTERN int ftpc_quit(SESSION handle); EXTERN int ftpc_quit(SESSION handle);
EXTERN int ftpc_chdir(SESSION handle, FAR const char *path); EXTERN int ftpc_chdir(SESSION handle, FAR const char *path);
EXTERN FAR char *ftpc_pwd(SESSION handle); EXTERN FAR char *ftpc_rpwd(SESSION handle);
EXTERN int ftpc_cdup(SESSION handle); EXTERN int ftpc_cdup(SESSION handle);
EXTERN int ftpc_mkdir(SESSION handle, FAR const char *path); EXTERN int ftpc_mkdir(SESSION handle, FAR const char *path);
EXTERN int ftpc_rmdir(SESSION handle, FAR const char *path); EXTERN int ftpc_rmdir(SESSION handle, FAR const char *path);
@ -192,7 +193,7 @@ EXTERN int ftpc_rmdir(SESSION handle, FAR const char *path);
EXTERN int ftpc_unlink(SESSION handle, FAR const char *path); EXTERN int ftpc_unlink(SESSION handle, FAR const char *path);
EXTERN int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode); EXTERN int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode);
EXTERN int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname); EXTERN int ftpc_rename(SESSION handle, FAR const char *oldname, FAR const char *newname);
EXTERN uint64_t ftpc_filesize(SESSION handle, FAR const char *path); EXTERN off_t ftpc_filesize(SESSION handle, FAR const char *path);
EXTERN time_t ftpc_filetime(SESSION handle, FAR const char *filename); EXTERN time_t ftpc_filetime(SESSION handle, FAR const char *filename);
EXTERN int ftpc_idle(SESSION handle, unsigned int idletime); EXTERN int ftpc_idle(SESSION handle, unsigned int idletime);

View File

@ -49,7 +49,7 @@ CSRCS = ftpc_connect.c ftpc_disconnect.c
# FTP commands # FTP commands
CSRCS += ftpc_cdup.c ftpc_chdir.c ftpc_chmod.c ftpc_filesize.c ftpc_filetime.c CSRCS += ftpc_cdup.c ftpc_chdir.c ftpc_chmod.c ftpc_filesize.c ftpc_filetime.c
CSRCS += ftpc_help.c ftpc_idle.c ftpc_listdir.c ftpc_login.c ftpc_mkdir.c CSRCS += ftpc_help.c ftpc_idle.c ftpc_listdir.c ftpc_login.c ftpc_mkdir.c
CSRCS += ftpc_noop.c ftpc_pwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c CSRCS += ftpc_noop.c ftpc_rpwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c
CSRCS += ftpc_cmd.c CSRCS += ftpc_cmd.c
# FTP transfers # FTP transfers

View File

@ -81,7 +81,7 @@
int ret; int ret;
ret = ftpc_cmd(session, "CDUP"); ret = ftpc_cmd(session, "CDUP");
ftpc_curdir(session); ftpc_currdir(session);
return ret; return ret;
} }

View File

@ -86,6 +86,6 @@ int ftpc_chdir(SESSION handle, FAR const char *path)
return ret; return ret;
} }
ftpc_curdir(session); ftpc_currdir(session);
return OK; return OK;
} }

View File

@ -85,7 +85,7 @@ int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode)
if (FTPC_HAS_CHMOD(session)) if (FTPC_HAS_CHMOD(session))
{ {
ret = ftpc_cmd(session, "SITE CHMOD %s %s", mode, path); ret = ftpc_cmd(session, "SITE CHMOD %s %s", path, mode);
/* Check for "502 Command not implemented" */ /* Check for "502 Command not implemented" */

View File

@ -87,8 +87,8 @@ static int ftpc_restore(struct ftpc_session_s *session)
{ {
/* Set the initial directory to the last valid current directory */ /* Set the initial directory to the last valid current directory */
free(session->initdir); free(session->initrdir);
session->initdir = ftpc_dequote(session->curdir); session->initrdir = ftpc_dequote(session->currdir);
/* Reconnect to the server */ /* Reconnect to the server */

View File

@ -41,6 +41,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <string.h>
#include <errno.h> #include <errno.h>
#include <debug.h> #include <debug.h>
@ -114,6 +115,15 @@ SESSION ftpc_connect(FAR struct ftpc_connect_s *server)
session->port = htons(server->port); session->port = htons(server->port);
} }
/* Get the local home directory, i.e., the value of the PWD environment
* variable at the time of the connection. We keep a local copy so that
* we can change the current working directory without effecting any other
* logic that may be in same context.
*/
session->homeldir = strdup(ftpc_lpwd());
/* session->curldir = strdup(sssion->homeldir); */
/* Create up a timer to prevent hangs */ /* Create up a timer to prevent hangs */
session->wdog = wd_create(); session->wdog = wd_create();

View File

@ -91,10 +91,10 @@ void ftpc_disconnect(SESSION handle)
free(session->uname); free(session->uname);
free(session->pwd); free(session->pwd);
free(session->initdir); free(session->initrdir);
free(session->homedir); free(session->homerdir);
free(session->curdir); free(session->currdir);
free(session->prevdir); free(session->prevrdir);
free(session->rname); free(session->rname);
free(session->lname); free(session->lname);

View File

@ -78,10 +78,10 @@
* *
****************************************************************************/ ****************************************************************************/
uint64_t ftpc_filesize(SESSION handle, FAR const char *path) off_t ftpc_filesize(SESSION handle, FAR const char *path)
{ {
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
uint64_t ret; unsigned long ret;
/* Check if the host supports the SIZE command */ /* Check if the host supports the SIZE command */
@ -107,6 +107,6 @@
return ERROR; return ERROR;
} }
sscanf(session->reply, "%*s %llu", &ret); sscanf(session->reply, "%*s %lu", &ret);
return ret; return (off_t)ret;
} }

View File

@ -270,20 +270,30 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
struct stat statbuf; struct stat statbuf;
FILE *loutstream; FILE *loutstream;
FAR char *abslpath;
off_t offset; off_t offset;
int ret; int ret;
/* Get the full path to the local file */
abslpath = ftpc_abslpath(session, lname);
if (!abslpath)
{
ndbg("ftpc_abslpath(%s) failed: %d\n", errno);
goto errout;
}
/* Get information about the local file */ /* Get information about the local file */
ret = stat(lname, &statbuf); ret = stat(abslpath, &statbuf);
if (ret == 0) if (ret == 0)
{ {
/* It already exists. Is it a directory? */ /* It already exists. Is it a directory? */
if (S_ISDIR(statbuf.st_mode)) if (S_ISDIR(statbuf.st_mode))
{ {
ndbg("'%s' is a directory\n", lname); ndbg("'%s' is a directory\n", abslpath);
return ERROR; goto errout_with_abspath;
} }
} }
@ -292,8 +302,8 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
#ifdef S_IWRITE #ifdef S_IWRITE
if (!(statbuf.st_mode & S_IWRITE)) if (!(statbuf.st_mode & S_IWRITE))
{ {
ndbg("'%s' permission denied\n", lname); ndbg("'%s' permission denied\n", abslpath);
return ERROR; goto errout_with_abspath;
} }
#endif #endif
@ -316,27 +326,14 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
if (ret != OK) if (ret != OK)
{ {
ndbg("ftpc_recvinit failed\n"); ndbg("ftpc_recvinit failed\n");
return ERROR; goto errout_with_abspath;
} }
loutstream = fopen(lname, (offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w"); loutstream = fopen(abslpath, (offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w");
if (!loutstream) if (!loutstream)
{ {
ndbg("fopen failed: %d\n", errno); ndbg("fopen failed: %d\n", errno);
session->offset = 0; goto errout_with_abspath;
return ERROR;
}
if (offset > 0)
{
ret = fseek(loutstream, offset, SEEK_SET);
if (ret != OK)
{
ndbg("fseek failed: %d\n", errno);
fclose(loutstream);
session->offset = 0;
return ERROR;
}
} }
/* Save the new local and remote file names */ /* Save the new local and remote file names */
@ -344,7 +341,17 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
free(session->rname); free(session->rname);
free(session->lname); free(session->lname);
session->rname = strdup(rname); session->rname = strdup(rname);
session->lname = strdup(lname); session->lname = abslpath;
if (offset > 0)
{
ret = fseek(loutstream, offset, SEEK_SET);
if (ret != OK)
{
ndbg("fseek failed: %d\n", errno);
goto errout_with_outstream;
}
}
/* And receive the new file data */ /* And receive the new file data */
@ -364,8 +371,26 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
fptc_getreply(session); fptc_getreply(session);
} }
/* On success, the last rname and lname are retained for debug purpose */
if (ret == OK && !FTPC_INTERRUPTED(session))
{
fclose(loutstream); fclose(loutstream);
return (ret == OK && !FTPC_INTERRUPTED(session)) ? OK : ERROR; return OK;
}
/* Various error exits */
errout_with_outstream:
fclose(loutstream);
free(session->rname);
session->rname = NULL;
session->lname = NULL;
errout_with_abspath:
free(abslpath);
session->offset = 0;
errout:
return ERROR;
} }
/**************************************************************************** /****************************************************************************

View File

@ -91,7 +91,7 @@ int ftpc_idle(SESSION handle, unsigned int idletime)
if (!FTPC_HAS_IDLE(session)) if (!FTPC_HAS_IDLE(session))
{ {
ndbg("Server doesn't support SITE IDLE\n"); ndbg("Server does not support SITE IDLE\n");
return ERROR; return ERROR;
} }
@ -108,12 +108,13 @@ int ftpc_idle(SESSION handle, unsigned int idletime)
ret = ftpc_cmd(session, "SITE IDLE"); ret = ftpc_cmd(session, "SITE IDLE");
} }
/* Check for "502 Command not implemented" */ /* Check for "502 Command not implemented" or 500 "Unknown SITE command" */
if (session->code == 502) if (session->code == 500 || session->code == 502)
{ {
/* Server does not support SITE IDLE */ /* Server does not support SITE IDLE */
ndbg("Server does not support SITE IDLE\n");
FTPC_CLR_IDLE(session); FTPC_CLR_IDLE(session);
} }

View File

@ -153,11 +153,12 @@ struct ftpc_session_s
WDOG_ID wdog; /* Timer */ WDOG_ID wdog; /* Timer */
FAR char *uname; /* Login uname */ FAR char *uname; /* Login uname */
FAR char *pwd; /* Login pwd */ FAR char *pwd; /* Login pwd */
FAR char *initdir; /* Initial remote directory */ FAR char *initrdir; /* Initial remote directory */
FAR char *homedir; /* Home directory (curdir on startup) */ FAR char *homerdir; /* Remote home directory (currdir on startup) */
FAR char *curdir; /* Current directory */ FAR char *currdir; /* Remote current directory */
FAR char *prevdir; /* Previous directory */ FAR char *prevrdir; /* Previous remote directory */
FAR char *rname; /* Remote file name */ FAR char *rname; /* Remote file name */
FAR char *homeldir; /* Local home directory (PWD on startup) */
FAR char *lname; /* Local file name */ FAR char *lname; /* Local file name */
pid_t pid; /* Task ID of FTP client */ pid_t pid; /* Task ID of FTP client */
uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */ uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */
@ -174,6 +175,13 @@ struct ftpc_session_s
char reply[CONFIG_FTP_MAXREPLY+1]; /* Last reply string from server */ char reply[CONFIG_FTP_MAXREPLY+1]; /* Last reply string from server */
}; };
/* There is not yet any want to change the local working directly (an lcd
* command), but the following definition is provided to reserve the name
* for the storage location for the local current working directory.
*/
#define curldir homeldir
/**************************************************************************** /****************************************************************************
* Public Data * Public Data
****************************************************************************/ ****************************************************************************/
@ -212,16 +220,23 @@ EXTERN void ftpc_stripcrlf(FAR char *str);
EXTERN void ftpc_stripslash(FAR char *str); EXTERN void ftpc_stripslash(FAR char *str);
EXTERN FAR char *ftpc_dequote(FAR const char *hostname); EXTERN FAR char *ftpc_dequote(FAR const char *hostname);
/* Connection helpers */
EXTERN int ftpc_reconnect(FAR struct ftpc_session_s *session);
EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session);
/* FTP helpers */ /* FTP helpers */
EXTERN void ftpc_reset(struct ftpc_session_s *session); EXTERN void ftpc_reset(struct ftpc_session_s *session);
EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...); EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...);
EXTERN int fptc_getreply(struct ftpc_session_s *session); EXTERN int fptc_getreply(struct ftpc_session_s *session);
EXTERN void ftpc_curdir(struct ftpc_session_s *session); EXTERN void ftpc_currdir(struct ftpc_session_s *session);
EXTERN FAR const char *ftpc_lpwd(void);
EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode); EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode);
EXTERN FAR char *ftpc_absrpath(FAR struct ftpc_session_s *session,
EXTERN int ftpc_reconnect(FAR struct ftpc_session_s *session); FAR const char *relpath);
EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session); EXTERN FAR char *ftpc_abslpath(FAR struct ftpc_session_s *session,
FAR const char *relpath);
/* Socket helpers */ /* Socket helpers */

View File

@ -73,79 +73,6 @@ typedef void (*callback_t)(FAR const char *name, FAR void *arg);
* Private Functions * Private Functions
****************************************************************************/ ****************************************************************************/
/****************************************************************************
* Name: ftpc_abspath
*
* Description:
* Get the absolute path to a file, handling tilde expansion.
*
****************************************************************************/
static FAR char *ftpc_abspath(FAR struct ftpc_session_s *session,
FAR const char *relpath)
{
FAR char *ptr = NULL;
int ret = OK;
/* If no relative path was provide, then use the current working directory */
if (!relpath)
{
return strdup(session->curdir);
}
/* Handle tilde expansion */
if (relpath[0] == '~')
{
/* Is the relative path only '~' */
if (relpath[1] == '\0')
{
return strdup(session->homedir);
}
/* No... then a '/' better follow the tilde */
else if (relpath[1] == '/')
{
ret = asprintf(&ptr, "%s%s", session->homedir, &relpath[1]);
}
/* Hmmm... this prety much guaranteed to fail */
else
{
ptr = strdup(relpath);
}
}
/* No tilde expansion. Check for a path relative to the current
* directory.
*/
else if (strncmp(relpath, "./", 2) == 0)
{
ret = asprintf(&ptr, "%s%s", session->curdir, relpath+1);
}
/* Check for an absolute path */
else if (relpath[0] == '/' && relpath[1] == ':' && relpath[2] == '\\')
{
ptr = strdup(relpath);
}
/* Take a wild guess */
else
{
ret = asprintf(&ptr, "%s/%s", session->curdir, relpath);
}
return ptr;
}
/**************************************************************************** /****************************************************************************
* Name: ftpc_dircount * Name: ftpc_dircount
* *
@ -342,30 +269,30 @@ FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
struct ftpc_dirlist_s *dirlist; struct ftpc_dirlist_s *dirlist;
FILE *filestream; FILE *filestream;
FAR char *abspath; FAR char *absrpath;
FAR char *tmpfname; FAR char *tmpfname;
bool iscurdir; bool iscurrdir;
unsigned int nnames; unsigned int nnames;
int allocsize; int allocsize;
int ret; int ret;
/* Get the absolute path to the directory */ /* Get the absolute path to the directory */
abspath = ftpc_abspath(session, dirpath); absrpath = ftpc_absrpath(session, dirpath);
ftpc_stripslash(abspath); ftpc_stripslash(absrpath);
/* Is the directory also the remote current working directory? */ /* Is the directory also the remote current working directory? */
iscurdir = (strcmp(abspath, session->curdir) == 0); iscurrdir = (strcmp(absrpath, session->currdir) == 0);
/* Create a temporary file to hold the directory listing */ /* Create a temporary file to hold the directory listing */
asprintf(&tmpfname, "%s/TMP%s.dat", CONFIG_FTP_TMPDIR, getpid()); asprintf(&tmpfname, "%s/TMP%d.dat", CONFIG_FTP_TMPDIR, getpid());
filestream = fopen(tmpfname, "w+"); filestream = fopen(tmpfname, "w+");
if (!filestream) if (!filestream)
{ {
ndbg("Failed to create %s: %d\n", tmpfname, errno); ndbg("Failed to create %s: %d\n", tmpfname, errno);
free(abspath); free(absrpath);
free(tmpfname); free(tmpfname);
return NULL; return NULL;
} }
@ -374,12 +301,12 @@ FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
* directory itself. * directory itself.
*/ */
if (!iscurdir) if (!iscurrdir)
{ {
ret = ftpc_cmd(session, "CWD %s", abspath); ret = ftpc_cmd(session, "CWD %s", absrpath);
if (ret != OK) if (ret != OK)
{ {
ndbg("CWD to %s failed\n", abspath); ndbg("CWD to %s failed\n", absrpath);
} }
} }
@ -391,12 +318,12 @@ FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
/* Go back to the correct current working directory */ /* Go back to the correct current working directory */
if (!iscurdir) if (!iscurrdir)
{ {
int tmpret = ftpc_cmd(session, "CWD %s", session->curdir); int tmpret = ftpc_cmd(session, "CWD %s", session->currdir);
if (tmpret != OK) if (tmpret != OK)
{ {
ndbg("CWD back to to %s failed\n", session->curdir); ndbg("CWD back to to %s failed\n", session->currdir);
} }
} }
@ -435,7 +362,7 @@ FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
errout: errout:
fclose(filestream); fclose(filestream);
free(abspath); free(absrpath);
unlink(tmpfname); unlink(tmpfname);
free(tmpfname); free(tmpfname);
return dirlist; return dirlist;

View File

@ -107,7 +107,7 @@ int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login)
session->uname = ftpc_dequote(login->uname); session->uname = ftpc_dequote(login->uname);
session->pwd = ftpc_dequote(login->pwd); session->pwd = ftpc_dequote(login->pwd);
session->initdir = ftpc_dequote(login->rdir); session->initrdir = ftpc_dequote(login->rdir);
/* Is passive mode requested? */ /* Is passive mode requested? */
@ -198,17 +198,17 @@ int ftpc_relogin(FAR struct ftpc_session_s *session)
*/ */
FTPC_SET_LOGGEDIN(session); FTPC_SET_LOGGEDIN(session);
session->homedir = ftpc_pwd((SESSION)session); session->homerdir = ftpc_rpwd((SESSION)session);
session->curdir = strdup(session->homedir); session->currdir = strdup(session->homerdir);
session->prevdir = strdup(session->homedir); session->prevrdir = strdup(session->homerdir);
/* If the user has requested a special start up directory, then change to /* If the user has requested a special start up directory, then change to
* that directory now. * that directory now.
*/ */
if (session->initdir) if (session->initrdir)
{ {
ftpc_chdir((SESSION)session, session->initdir); ftpc_chdir((SESSION)session, session->initrdir);
} }
return OK; return OK;

View File

@ -286,15 +286,15 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
len = strlen(str); len = strlen(str);
if (len) if (len)
{ {
free(session->lname); free(session->rname);
if (*str == '\'') if (*str == '\'')
{ {
session->lname = strndup(str+1, len-3); session->rname = strndup(str+1, len-3);
} }
else else
{ {
session->lname = strndup(str, len-1); session->rname = strndup(str, len-1);
nvdbg("Unique filename is: %s\n", session->lname); nvdbg("Unique filename is: %s\n", session->rname);
} }
} }
} }
@ -383,34 +383,45 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
uint8_t how, uint8_t xfrmode) uint8_t how, uint8_t xfrmode)
{ {
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
FAR char *abslpath;
struct stat statbuf; struct stat statbuf;
FILE *finstream; FILE *finstream;
int ret; int ret;
/* Get the full path to the local file */
abslpath = ftpc_abslpath(session, lname);
if (!abslpath)
{
ndbg("ftpc_abslpath(%s) failed: %d\n", errno);
goto errout;
}
/* Make sure that the local file exists */ /* Make sure that the local file exists */
ret = stat(lname, &statbuf); ret = stat(abslpath, &statbuf);
if (ret != OK) if (ret != OK)
{ {
ndbg("stat() failed: %d\n", errno); ndbg("stat(%s) failed: %d\n", errno);
return ERROR; free(abslpath);
goto errout;
} }
/* Make sure that the local name does not refer to a directory */ /* Make sure that the local name does not refer to a directory */
if (S_ISDIR(statbuf.st_mode)) if (S_ISDIR(statbuf.st_mode))
{ {
ndbg("%s is a directory\n", lname); ndbg("%s is a directory\n", abslpath);
return ERROR; goto errout_with_abspath;
} }
/* Open the local file for reading */ /* Open the local file for reading */
finstream = fopen(lname, "r"); finstream = fopen(abslpath, "r");
if (!finstream == 0) if (!finstream == 0)
{ {
ndbg("fopen() failed: %d\n", errno); ndbg("fopen() failed: %d\n", errno);
return ERROR; goto errout_with_abspath;
} }
/* Configure for the transfer */ /* Configure for the transfer */
@ -418,8 +429,8 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
session->filesize = statbuf.st_size; session->filesize = statbuf.st_size;
free(session->rname); free(session->rname);
free(session->lname); free(session->lname);
session->rname = strdup(lname); session->rname = strdup(rname);
session->lname = strdup(rname); session->lname = abslpath;
/* Are we resuming a transfer? */ /* Are we resuming a transfer? */
@ -434,6 +445,7 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
if (session->offset == (off_t)ERROR) if (session->offset == (off_t)ERROR)
{ {
ndbg("Failed to get size of remote file: %s\n", rname); ndbg("Failed to get size of remote file: %s\n", rname);
goto errout_with_instream;
} }
else else
{ {
@ -445,13 +457,29 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
if (ret != OK) if (ret != OK)
{ {
ndbg("fseek failed: %d\n", errno); ndbg("fseek failed: %d\n", errno);
fclose(finstream); goto errout_with_instream;
return ERROR;
} }
} }
} }
/* On success, the last rname and lname are retained for debug purpose */
ret = ftpc_sendfile(session, rname, finstream, how, xfrmode); ret = ftpc_sendfile(session, rname, finstream, how, xfrmode);
if (ret == OK)
{
fclose(finstream); fclose(finstream);
return ret; return OK;
}
/* Various error exits */
errout_with_instream:
fclose(finstream);
free(session->rname);
session->rname = NULL;
session->lname = NULL;
errout_with_abspath:
free(abslpath);
errout:
return ERROR;
} }

View File

@ -1,5 +1,5 @@
/**************************************************************************** /****************************************************************************
* apps/netutils/ftpc/ftpc_pwd.c * apps/netutils/ftpc/ftpc_rpwd.c
* *
* Copyright (C) 2011 Gregory Nutt. All rights reserved. * Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <spudmonkey@racsa.co.cr> * Author: Gregory Nutt <spudmonkey@racsa.co.cr>
@ -72,14 +72,14 @@
****************************************************************************/ ****************************************************************************/
/**************************************************************************** /****************************************************************************
* Name: ftpc_pwd * Name: ftpc_rpwd
* *
* Descripton: * Descripton:
* Returns the current working directory on the remote server. * Returns the current working directory on the remote server.
* *
****************************************************************************/ ****************************************************************************/
FAR char *ftpc_pwd(SESSION handle) FAR char *ftpc_rpwd(SESSION handle)
{ {
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle; FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
FAR char *start; FAR char *start;

View File

@ -216,7 +216,6 @@ int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive)
{ {
struct sockaddr addr; struct sockaddr addr;
socklen_t addrlen; socklen_t addrlen;
int sd;
/* Any previous socket should have been uninitialized (0) or explicitly /* Any previous socket should have been uninitialized (0) or explicitly
* closed (-1). * closed (-1).
@ -245,7 +244,7 @@ int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive)
{ {
addrlen = sizeof(addr); addrlen = sizeof(addr);
sock->sd = accept(sock->sd, &addr, &addrlen); sock->sd = accept(sock->sd, &addr, &addrlen);
if (sd == -1) if (sock->sd == -1)
{ {
ndbg("accept() failed: %d\n", errno); ndbg("accept() failed: %d\n", errno);
return ERROR; return ERROR;

View File

@ -158,6 +158,80 @@ static int ftp_pasvmode(struct ftpc_session_s *session,
return OK; return OK;
} }
/****************************************************************************
* Name: ftpc_abspath
*
* Description:
* Get the absolute path to a file, handling tilde expansion.
*
****************************************************************************/
static FAR char *ftpc_abspath(FAR struct ftpc_session_s *session,
FAR const char *relpath, FAR const char *homedir,
FAR const char *curdir)
{
FAR char *ptr = NULL;
int ret = OK;
/* If no relative path was provide, then use the current working directory */
if (!relpath)
{
return strdup(curdir);
}
/* Handle tilde expansion */
if (relpath[0] == '~')
{
/* Is the relative path only '~' */
if (relpath[1] == '\0')
{
return strdup(homedir);
}
/* No... then a '/' better follow the tilde */
else if (relpath[1] == '/')
{
ret = asprintf(&ptr, "%s%s", homedir, &relpath[1]);
}
/* Hmmm... this pretty much guaranteed to fail */
else
{
ptr = strdup(relpath);
}
}
/* No tilde expansion. Check for a path relative to the current
* directory.
*/
else if (strncmp(relpath, "./", 2) == 0)
{
ret = asprintf(&ptr, "%s%s", curdir, relpath+1);
}
/* Check for an absolute path */
else if (relpath[0] == '/' && relpath[1] == ':' && relpath[2] == '\\')
{
ptr = strdup(relpath);
}
/* Assume it a relative path */
else
{
ret = asprintf(&ptr, "%s/%s", curdir, relpath);
}
return ptr;
}
/**************************************************************************** /****************************************************************************
* Public Functions * Public Functions
****************************************************************************/ ****************************************************************************/
@ -182,6 +256,7 @@ int ftpc_xfrinit(FAR struct ftpc_session_s *session)
if (!ftpc_connected(session)) if (!ftpc_connected(session))
{ {
ndbg("Not connected\n");
goto errout; goto errout;
} }
@ -207,6 +282,7 @@ int ftpc_xfrinit(FAR struct ftpc_session_s *session)
ret = ftp_pasvmode(session, addrport); ret = ftp_pasvmode(session, addrport);
if (ret != OK) if (ret != OK)
{ {
ndbg("ftp_pasvmode() failed: %d\n", errno);
goto errout_with_data; goto errout_with_data;
} }
} }
@ -343,7 +419,7 @@ int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream)
* <IAC IP><IAC DM>ABORT<CR><LF> * <IAC IP><IAC DM>ABORT<CR><LF>
*/ */
ndbg("Telnet ABORt sequence\n"); nvdbg("Telnet ABORt sequence\n");
ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */ ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_IP); /* Interrupt process */
ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */ ftpc_sockprintf(&session->cmd, "%c%c", TELNET_IAC, TELNET_DM); /* Telnet synch signal */
ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */ ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */
@ -435,3 +511,39 @@ void ftpc_timeout(int argc, uint32_t arg1, ...)
DEBUGASSERT(argc == 1 && session); DEBUGASSERT(argc == 1 && session);
kill(session->pid, CONFIG_FTP_SIGNAL); kill(session->pid, CONFIG_FTP_SIGNAL);
} }
/****************************************************************************
* Name: ftpc_absrpath
*
* Description:
* Get the absolute path to a remote file, handling tilde expansion.
*
****************************************************************************/
FAR char *ftpc_absrpath(FAR struct ftpc_session_s *session,
FAR const char *relpath)
{
FAR char *absrpath = ftpc_abspath(session, relpath,
session->homerdir, session->currdir);
nvdbg("%s -> %s\n", relpath, absrpath);
return absrpath;
}
/****************************************************************************
* Name: ftpc_abslpath
*
* Description:
* Get the absolute path to a local file, handling tilde expansion.
*
****************************************************************************/
FAR char *ftpc_abslpath(FAR struct ftpc_session_s *session,
FAR const char *relpath)
{
FAR char *abslpath = ftpc_abspath(session, relpath,
session->homeldir, session->curldir);
nvdbg("%s -> %s\n", relpath, abslpath);
return abslpath;
}

View File

@ -109,8 +109,8 @@ void ftpc_reset(struct ftpc_session_s *session)
session->uname = NULL; session->uname = NULL;
free(session->pwd); free(session->pwd);
session->pwd = NULL; session->pwd = NULL;
free(session->initdir); free(session->initrdir);
session->initdir = NULL; session->initrdir = NULL;
session->flags = FTPC_FLAGS_INIT; session->flags = FTPC_FLAGS_INIT;
session->xfrmode = FTPC_XFRMODE_UNKNOWN; session->xfrmode = FTPC_XFRMODE_UNKNOWN;
session->code = 0; session->code = 0;
@ -119,18 +119,43 @@ void ftpc_reset(struct ftpc_session_s *session)
} }
/**************************************************************************** /****************************************************************************
* Name: ftpc_curdir * Name: ftpc_currdir
* *
* Description: * Description:
* Update the current working directory * Update the remote current working directory
* *
****************************************************************************/ ****************************************************************************/
void ftpc_curdir(struct ftpc_session_s *session) void ftpc_currdir(struct ftpc_session_s *session)
{ {
free(session->prevdir); free(session->prevrdir);
session->prevdir = session->curdir; session->prevrdir = session->currdir;
session->curdir = ftpc_pwd((SESSION)session); session->currdir = ftpc_rpwd((SESSION)session);
}
/****************************************************************************
* Name: ftpc_lpwd
*
* Description:
* Return the local current working directory. NOTE: This is a peek at
* a global copy. The caller should call strdup if it wants to keep it.
*
****************************************************************************/
FAR const char *ftpc_lpwd(void)
{
#ifndef CONFIG_DISABLE_ENVIRON
FAR const char *val;
val = getenv("PWD");
if (!val)
{
val = CONFIG_FTP_TMPDIR;
}
return val;
#else
return CONFIG_FTP_TMPDIR;
#endif
} }
/**************************************************************************** /****************************************************************************

View File

@ -89,9 +89,6 @@
int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd, int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
FAR char *argv[]) FAR char *argv[])
{ {
#ifndef CONFIG_APPS_BINDIR
FAR const char * name;
#endif
int ret = OK; int ret = OK;
/* Try to find command within pre-built application list. */ /* Try to find command within pre-built application list. */
@ -99,30 +96,7 @@ int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
ret = exec_namedapp(cmd, argv); ret = exec_namedapp(cmd, argv);
if (ret < 0) if (ret < 0)
{ {
int err = -errno; return -errno;
#ifndef CONFIG_APPS_BINDIR
int i;
/* On failure, list the set of available built-in commands */
nsh_output(vtbl, "Builtin Apps: ");
for (i = 0; (name = namedapp_getname(i)) != NULL; i++)
{
nsh_output(vtbl, "%s ", name);
}
nsh_output(vtbl, "\nand type 'help' for more NSH commands.\n\n");
/* If the failing command was '?', then do not report an error */
if (strcmp(cmd, "?") != 0)
{
return err;
}
return OK;
#else
return err;
#endif
} }
#ifdef CONFIG_SCHED_WAITPID #ifdef CONFIG_SCHED_WAITPID

View File

@ -140,6 +140,10 @@ static const struct cmdmap_s g_cmdmap[] =
{ "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" }, { "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" },
#endif #endif
#ifndef CONFIG_NSH_DISABLE_HELP
{ "?", cmd_help, 1, 1, NULL },
#endif
#if CONFIG_NFILE_DESCRIPTORS > 0 #if CONFIG_NFILE_DESCRIPTORS > 0
# ifndef CONFIG_NSH_DISABLE_CAT # ifndef CONFIG_NSH_DISABLE_CAT
{ "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, "<path> [<path> [<path> ...]]" }, { "cat", cmd_cat, 2, NSH_MAX_ARGUMENTS, "<path> [<path> [<path> ...]]" },
@ -391,6 +395,10 @@ const char g_fmtsignalrecvd[] = "nsh: %s: Interrupted by signal\n";
static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv) static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
{ {
const struct cmdmap_s *ptr; const struct cmdmap_s *ptr;
#ifdef CONFIG_NSH_BUILTIN_APPS
FAR const char * name;
int i;
#endif
nsh_output(vtbl, "NSH command forms:\n"); nsh_output(vtbl, "NSH command forms:\n");
#ifndef CONFIG_NSH_DISABLEBG #ifndef CONFIG_NSH_DISABLEBG
@ -419,6 +427,17 @@ static int cmd_help(FAR struct nsh_vtbl_s *vtbl, int argc, char **argv)
nsh_output(vtbl, " %s\n", ptr->cmd); nsh_output(vtbl, " %s\n", ptr->cmd);
} }
} }
/* List the set of available built-in commands */
#ifdef CONFIG_NSH_BUILTIN_APPS
nsh_output(vtbl, "\nBuiltin Apps: ");
for (i = 0; (name = namedapp_getname(i)) != NULL; i++)
{
nsh_output(vtbl, " %s\n", name);
}
#endif
return OK; return OK;
} }
#endif #endif