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:
parent
a94c011b4e
commit
da50c819f9
@ -56,9 +56,13 @@ examples/ftpc
|
||||
to that it will only work as a "built-in" program that can be run from
|
||||
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
|
||||
optional port number.
|
||||
|
@ -108,7 +108,7 @@ int cmd_rchdir(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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
uint64_t size = ftpc_filesize(handle, argv[1]);
|
||||
printf("SIZE: %ull\n", size);
|
||||
off_t size = ftpc_filesize(handle, argv[1]);
|
||||
printf("SIZE: %lu\n", size);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ int cmd_rsize(SESSION handle, int argc, char **argv)
|
||||
int cmd_rtime(SESSION handle, int argc, char **argv)
|
||||
{
|
||||
time_t filetime = ftpc_filetime(handle, argv[1]);
|
||||
printf("TIME: %ul\n", (long)filetime);
|
||||
printf("TIME: %lu\n", (long)filetime);
|
||||
return OK;
|
||||
}
|
||||
|
||||
@ -264,6 +264,7 @@ int cmd_rls(SESSION handle, int argc, char **argv)
|
||||
{
|
||||
printf(" %s\n", dirlist->name[i]);
|
||||
}
|
||||
FFLUSH();
|
||||
|
||||
ftpc_dirfree(dirlist);
|
||||
return OK;
|
||||
|
@ -42,6 +42,7 @@
|
||||
|
||||
#include <nuttx/config.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <signal.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_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_mkdir(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_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 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 int ftpc_idle(SESSION handle, unsigned int idletime);
|
||||
|
@ -49,7 +49,7 @@ CSRCS = ftpc_connect.c ftpc_disconnect.c
|
||||
# FTP commands
|
||||
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_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
|
||||
|
||||
# FTP transfers
|
||||
|
@ -75,13 +75,13 @@
|
||||
*
|
||||
****************************************************************************/
|
||||
|
||||
int ftpc_cdup(SESSION handle)
|
||||
int ftpc_cdup(SESSION handle)
|
||||
{
|
||||
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
|
||||
int ret;
|
||||
|
||||
ret = ftpc_cmd(session, "CDUP");
|
||||
ftpc_curdir(session);
|
||||
ftpc_currdir(session);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -86,6 +86,6 @@ int ftpc_chdir(SESSION handle, FAR const char *path)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ftpc_curdir(session);
|
||||
ftpc_currdir(session);
|
||||
return OK;
|
||||
}
|
||||
|
@ -85,7 +85,7 @@ int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode)
|
||||
|
||||
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" */
|
||||
|
||||
|
@ -87,8 +87,8 @@ static int ftpc_restore(struct ftpc_session_s *session)
|
||||
{
|
||||
/* Set the initial directory to the last valid current directory */
|
||||
|
||||
free(session->initdir);
|
||||
session->initdir = ftpc_dequote(session->curdir);
|
||||
free(session->initrdir);
|
||||
session->initrdir = ftpc_dequote(session->currdir);
|
||||
|
||||
/* Reconnect to the server */
|
||||
|
||||
|
@ -41,6 +41,7 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <debug.h>
|
||||
|
||||
@ -114,6 +115,15 @@ SESSION ftpc_connect(FAR struct ftpc_connect_s *server)
|
||||
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 */
|
||||
|
||||
session->wdog = wd_create();
|
||||
|
@ -91,10 +91,10 @@ void ftpc_disconnect(SESSION handle)
|
||||
|
||||
free(session->uname);
|
||||
free(session->pwd);
|
||||
free(session->initdir);
|
||||
free(session->homedir);
|
||||
free(session->curdir);
|
||||
free(session->prevdir);
|
||||
free(session->initrdir);
|
||||
free(session->homerdir);
|
||||
free(session->currdir);
|
||||
free(session->prevrdir);
|
||||
free(session->rname);
|
||||
free(session->lname);
|
||||
|
||||
|
@ -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;
|
||||
uint64_t ret;
|
||||
unsigned long ret;
|
||||
|
||||
/* Check if the host supports the SIZE command */
|
||||
|
||||
@ -107,6 +107,6 @@
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
sscanf(session->reply, "%*s %llu", &ret);
|
||||
return ret;
|
||||
sscanf(session->reply, "%*s %lu", &ret);
|
||||
return (off_t)ret;
|
||||
}
|
||||
|
@ -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;
|
||||
struct stat statbuf;
|
||||
FILE *loutstream;
|
||||
FAR char *abslpath;
|
||||
off_t offset;
|
||||
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 */
|
||||
|
||||
ret = stat(lname, &statbuf);
|
||||
ret = stat(abslpath, &statbuf);
|
||||
if (ret == 0)
|
||||
{
|
||||
/* It already exists. Is it a directory? */
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
ndbg("'%s' is a directory\n", lname);
|
||||
return ERROR;
|
||||
ndbg("'%s' is a directory\n", abslpath);
|
||||
goto errout_with_abspath;
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,8 +302,8 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
|
||||
#ifdef S_IWRITE
|
||||
if (!(statbuf.st_mode & S_IWRITE))
|
||||
{
|
||||
ndbg("'%s' permission denied\n", lname);
|
||||
return ERROR;
|
||||
ndbg("'%s' permission denied\n", abslpath);
|
||||
goto errout_with_abspath;
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -316,27 +326,14 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
|
||||
if (ret != OK)
|
||||
{
|
||||
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)
|
||||
{
|
||||
ndbg("fopen failed: %d\n", errno);
|
||||
session->offset = 0;
|
||||
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;
|
||||
}
|
||||
goto errout_with_abspath;
|
||||
}
|
||||
|
||||
/* 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->lname);
|
||||
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 */
|
||||
|
||||
@ -364,8 +371,26 @@ int ftpc_getfile(SESSION handle, FAR const char *rname, FAR const char *lname,
|
||||
fptc_getreply(session);
|
||||
}
|
||||
|
||||
/* On success, the last rname and lname are retained for debug purpose */
|
||||
|
||||
if (ret == OK && !FTPC_INTERRUPTED(session))
|
||||
{
|
||||
fclose(loutstream);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Various error exits */
|
||||
|
||||
errout_with_outstream:
|
||||
fclose(loutstream);
|
||||
return (ret == OK && !FTPC_INTERRUPTED(session)) ? OK : ERROR;
|
||||
free(session->rname);
|
||||
session->rname = NULL;
|
||||
session->lname = NULL;
|
||||
errout_with_abspath:
|
||||
free(abslpath);
|
||||
session->offset = 0;
|
||||
errout:
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -91,7 +91,7 @@ int ftpc_idle(SESSION handle, unsigned int idletime)
|
||||
|
||||
if (!FTPC_HAS_IDLE(session))
|
||||
{
|
||||
ndbg("Server doesn't support SITE IDLE\n");
|
||||
ndbg("Server does not support SITE IDLE\n");
|
||||
return ERROR;
|
||||
}
|
||||
|
||||
@ -108,12 +108,13 @@ int ftpc_idle(SESSION handle, unsigned int idletime)
|
||||
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 */
|
||||
|
||||
ndbg("Server does not support SITE IDLE\n");
|
||||
FTPC_CLR_IDLE(session);
|
||||
}
|
||||
|
||||
|
@ -153,11 +153,12 @@ struct ftpc_session_s
|
||||
WDOG_ID wdog; /* Timer */
|
||||
FAR char *uname; /* Login uname */
|
||||
FAR char *pwd; /* Login pwd */
|
||||
FAR char *initdir; /* Initial remote directory */
|
||||
FAR char *homedir; /* Home directory (curdir on startup) */
|
||||
FAR char *curdir; /* Current directory */
|
||||
FAR char *prevdir; /* Previous directory */
|
||||
FAR char *initrdir; /* Initial remote directory */
|
||||
FAR char *homerdir; /* Remote home directory (currdir on startup) */
|
||||
FAR char *currdir; /* Remote current directory */
|
||||
FAR char *prevrdir; /* Previous remote directory */
|
||||
FAR char *rname; /* Remote file name */
|
||||
FAR char *homeldir; /* Local home directory (PWD on startup) */
|
||||
FAR char *lname; /* Local file name */
|
||||
pid_t pid; /* Task ID of FTP client */
|
||||
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 */
|
||||
};
|
||||
|
||||
/* 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
|
||||
****************************************************************************/
|
||||
@ -212,16 +220,23 @@ EXTERN void ftpc_stripcrlf(FAR char *str);
|
||||
EXTERN void ftpc_stripslash(FAR char *str);
|
||||
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 */
|
||||
|
||||
EXTERN void ftpc_reset(struct ftpc_session_s *session);
|
||||
EXTERN int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...);
|
||||
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_reconnect(FAR struct ftpc_session_s *session);
|
||||
EXTERN int ftpc_relogin(FAR struct ftpc_session_s *session);
|
||||
EXTERN FAR char *ftpc_absrpath(FAR struct ftpc_session_s *session,
|
||||
FAR const char *relpath);
|
||||
EXTERN FAR char *ftpc_abslpath(FAR struct ftpc_session_s *session,
|
||||
FAR const char *relpath);
|
||||
|
||||
/* Socket helpers */
|
||||
|
||||
|
@ -73,79 +73,6 @@ typedef void (*callback_t)(FAR const char *name, FAR void *arg);
|
||||
* 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
|
||||
*
|
||||
@ -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;
|
||||
struct ftpc_dirlist_s *dirlist;
|
||||
FILE *filestream;
|
||||
FAR char *abspath;
|
||||
FAR char *absrpath;
|
||||
FAR char *tmpfname;
|
||||
bool iscurdir;
|
||||
bool iscurrdir;
|
||||
unsigned int nnames;
|
||||
int allocsize;
|
||||
int ret;
|
||||
|
||||
/* Get the absolute path to the directory */
|
||||
|
||||
abspath = ftpc_abspath(session, dirpath);
|
||||
ftpc_stripslash(abspath);
|
||||
absrpath = ftpc_absrpath(session, dirpath);
|
||||
ftpc_stripslash(absrpath);
|
||||
|
||||
/* 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 */
|
||||
|
||||
asprintf(&tmpfname, "%s/TMP%s.dat", CONFIG_FTP_TMPDIR, getpid());
|
||||
asprintf(&tmpfname, "%s/TMP%d.dat", CONFIG_FTP_TMPDIR, getpid());
|
||||
filestream = fopen(tmpfname, "w+");
|
||||
if (!filestream)
|
||||
{
|
||||
ndbg("Failed to create %s: %d\n", tmpfname, errno);
|
||||
free(abspath);
|
||||
free(absrpath);
|
||||
free(tmpfname);
|
||||
return NULL;
|
||||
}
|
||||
@ -374,12 +301,12 @@ FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
|
||||
* directory itself.
|
||||
*/
|
||||
|
||||
if (!iscurdir)
|
||||
if (!iscurrdir)
|
||||
{
|
||||
ret = ftpc_cmd(session, "CWD %s", abspath);
|
||||
ret = ftpc_cmd(session, "CWD %s", absrpath);
|
||||
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 */
|
||||
|
||||
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)
|
||||
{
|
||||
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:
|
||||
fclose(filestream);
|
||||
free(abspath);
|
||||
free(absrpath);
|
||||
unlink(tmpfname);
|
||||
free(tmpfname);
|
||||
return dirlist;
|
||||
|
@ -105,9 +105,9 @@ int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login)
|
||||
|
||||
/* Save the login parameter */
|
||||
|
||||
session->uname = ftpc_dequote(login->uname);
|
||||
session->pwd = ftpc_dequote(login->pwd);
|
||||
session->initdir = ftpc_dequote(login->rdir);
|
||||
session->uname = ftpc_dequote(login->uname);
|
||||
session->pwd = ftpc_dequote(login->pwd);
|
||||
session->initrdir = ftpc_dequote(login->rdir);
|
||||
|
||||
/* Is passive mode requested? */
|
||||
|
||||
@ -198,17 +198,17 @@ int ftpc_relogin(FAR struct ftpc_session_s *session)
|
||||
*/
|
||||
|
||||
FTPC_SET_LOGGEDIN(session);
|
||||
session->homedir = ftpc_pwd((SESSION)session);
|
||||
session->curdir = strdup(session->homedir);
|
||||
session->prevdir = strdup(session->homedir);
|
||||
session->homerdir = ftpc_rpwd((SESSION)session);
|
||||
session->currdir = strdup(session->homerdir);
|
||||
session->prevrdir = strdup(session->homerdir);
|
||||
|
||||
/* If the user has requested a special start up directory, then change to
|
||||
* that directory now.
|
||||
*/
|
||||
|
||||
if (session->initdir)
|
||||
if (session->initrdir)
|
||||
{
|
||||
ftpc_chdir((SESSION)session, session->initdir);
|
||||
ftpc_chdir((SESSION)session, session->initrdir);
|
||||
}
|
||||
|
||||
return OK;
|
||||
|
@ -286,15 +286,15 @@ static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
|
||||
len = strlen(str);
|
||||
if (len)
|
||||
{
|
||||
free(session->lname);
|
||||
free(session->rname);
|
||||
if (*str == '\'')
|
||||
{
|
||||
session->lname = strndup(str+1, len-3);
|
||||
session->rname = strndup(str+1, len-3);
|
||||
}
|
||||
else
|
||||
{
|
||||
session->lname = strndup(str, len-1);
|
||||
nvdbg("Unique filename is: %s\n", session->lname);
|
||||
session->rname = strndup(str, len-1);
|
||||
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)
|
||||
{
|
||||
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
|
||||
FAR char *abslpath;
|
||||
struct stat statbuf;
|
||||
FILE *finstream;
|
||||
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 */
|
||||
|
||||
ret = stat(lname, &statbuf);
|
||||
ret = stat(abslpath, &statbuf);
|
||||
if (ret != OK)
|
||||
{
|
||||
ndbg("stat() failed: %d\n", errno);
|
||||
return ERROR;
|
||||
ndbg("stat(%s) failed: %d\n", errno);
|
||||
free(abslpath);
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/* Make sure that the local name does not refer to a directory */
|
||||
|
||||
if (S_ISDIR(statbuf.st_mode))
|
||||
{
|
||||
ndbg("%s is a directory\n", lname);
|
||||
return ERROR;
|
||||
ndbg("%s is a directory\n", abslpath);
|
||||
goto errout_with_abspath;
|
||||
}
|
||||
|
||||
/* Open the local file for reading */
|
||||
|
||||
finstream = fopen(lname, "r");
|
||||
finstream = fopen(abslpath, "r");
|
||||
if (!finstream == 0)
|
||||
{
|
||||
ndbg("fopen() failed: %d\n", errno);
|
||||
return ERROR;
|
||||
goto errout_with_abspath;
|
||||
}
|
||||
|
||||
/* Configure for the transfer */
|
||||
@ -418,8 +429,8 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
|
||||
session->filesize = statbuf.st_size;
|
||||
free(session->rname);
|
||||
free(session->lname);
|
||||
session->rname = strdup(lname);
|
||||
session->lname = strdup(rname);
|
||||
session->rname = strdup(rname);
|
||||
session->lname = abslpath;
|
||||
|
||||
/* 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)
|
||||
{
|
||||
ndbg("Failed to get size of remote file: %s\n", rname);
|
||||
goto errout_with_instream;
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -445,13 +457,29 @@ int ftp_putfile(SESSION handle, const char *lname, const char *rname,
|
||||
if (ret != OK)
|
||||
{
|
||||
ndbg("fseek failed: %d\n", errno);
|
||||
fclose(finstream);
|
||||
return ERROR;
|
||||
goto errout_with_instream;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* On success, the last rname and lname are retained for debug purpose */
|
||||
|
||||
ret = ftpc_sendfile(session, rname, finstream, how, xfrmode);
|
||||
if (ret == OK)
|
||||
{
|
||||
fclose(finstream);
|
||||
return OK;
|
||||
}
|
||||
|
||||
/* Various error exits */
|
||||
|
||||
errout_with_instream:
|
||||
fclose(finstream);
|
||||
return ret;
|
||||
free(session->rname);
|
||||
session->rname = NULL;
|
||||
session->lname = NULL;
|
||||
errout_with_abspath:
|
||||
free(abslpath);
|
||||
errout:
|
||||
return ERROR;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/****************************************************************************
|
||||
* apps/netutils/ftpc/ftpc_pwd.c
|
||||
* apps/netutils/ftpc/ftpc_rpwd.c
|
||||
*
|
||||
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
|
||||
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||||
@ -72,14 +72,14 @@
|
||||
****************************************************************************/
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ftpc_pwd
|
||||
* Name: ftpc_rpwd
|
||||
*
|
||||
* Descripton:
|
||||
* 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 char *start;
|
@ -216,7 +216,6 @@ int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive)
|
||||
{
|
||||
struct sockaddr addr;
|
||||
socklen_t addrlen;
|
||||
int sd;
|
||||
|
||||
/* Any previous socket should have been uninitialized (0) or explicitly
|
||||
* closed (-1).
|
||||
@ -245,7 +244,7 @@ int ftpc_sockaccept(struct ftpc_socket_s *sock, const char *mode, bool passive)
|
||||
{
|
||||
addrlen = sizeof(addr);
|
||||
sock->sd = accept(sock->sd, &addr, &addrlen);
|
||||
if (sd == -1)
|
||||
if (sock->sd == -1)
|
||||
{
|
||||
ndbg("accept() failed: %d\n", errno);
|
||||
return ERROR;
|
||||
|
@ -158,6 +158,80 @@ static int ftp_pasvmode(struct ftpc_session_s *session,
|
||||
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
|
||||
****************************************************************************/
|
||||
@ -182,6 +256,7 @@ int ftpc_xfrinit(FAR struct ftpc_session_s *session)
|
||||
|
||||
if (!ftpc_connected(session))
|
||||
{
|
||||
ndbg("Not connected\n");
|
||||
goto errout;
|
||||
}
|
||||
|
||||
@ -207,6 +282,7 @@ int ftpc_xfrinit(FAR struct ftpc_session_s *session)
|
||||
ret = ftp_pasvmode(session, addrport);
|
||||
if (ret != OK)
|
||||
{
|
||||
ndbg("ftp_pasvmode() failed: %d\n", errno);
|
||||
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>
|
||||
*/
|
||||
|
||||
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_DM); /* Telnet synch signal */
|
||||
ftpc_sockprintf(&session->cmd, "ABOR\r\n"); /* Abort */
|
||||
@ -435,3 +511,39 @@ void ftpc_timeout(int argc, uint32_t arg1, ...)
|
||||
DEBUGASSERT(argc == 1 && session);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,8 +109,8 @@ void ftpc_reset(struct ftpc_session_s *session)
|
||||
session->uname = NULL;
|
||||
free(session->pwd);
|
||||
session->pwd = NULL;
|
||||
free(session->initdir);
|
||||
session->initdir = NULL;
|
||||
free(session->initrdir);
|
||||
session->initrdir = NULL;
|
||||
session->flags = FTPC_FLAGS_INIT;
|
||||
session->xfrmode = FTPC_XFRMODE_UNKNOWN;
|
||||
session->code = 0;
|
||||
@ -119,18 +119,43 @@ void ftpc_reset(struct ftpc_session_s *session)
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
* Name: ftpc_curdir
|
||||
* Name: ftpc_currdir
|
||||
*
|
||||
* 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);
|
||||
session->prevdir = session->curdir;
|
||||
session->curdir = ftpc_pwd((SESSION)session);
|
||||
free(session->prevrdir);
|
||||
session->prevrdir = session->currdir;
|
||||
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
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
|
@ -89,9 +89,6 @@
|
||||
int nsh_execapp(FAR struct nsh_vtbl_s *vtbl, FAR const char *cmd,
|
||||
FAR char *argv[])
|
||||
{
|
||||
#ifndef CONFIG_APPS_BINDIR
|
||||
FAR const char * name;
|
||||
#endif
|
||||
int ret = OK;
|
||||
|
||||
/* 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);
|
||||
if (ret < 0)
|
||||
{
|
||||
int err = -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
|
||||
return -errno;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SCHED_WAITPID
|
||||
|
@ -140,6 +140,10 @@ static const struct cmdmap_s g_cmdmap[] =
|
||||
{ "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, "<expression> ]" },
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_NSH_DISABLE_HELP
|
||||
{ "?", cmd_help, 1, 1, NULL },
|
||||
#endif
|
||||
|
||||
#if CONFIG_NFILE_DESCRIPTORS > 0
|
||||
# ifndef CONFIG_NSH_DISABLE_CAT
|
||||
{ "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)
|
||||
{
|
||||
const struct cmdmap_s *ptr;
|
||||
#ifdef CONFIG_NSH_BUILTIN_APPS
|
||||
FAR const char * name;
|
||||
int i;
|
||||
#endif
|
||||
|
||||
nsh_output(vtbl, "NSH command forms:\n");
|
||||
#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);
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user