diff --git a/examples/README.txt b/examples/README.txt index 2a15dac5d..a67d9ad04 100644 --- a/examples/README.txt +++ b/examples/README.txt @@ -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. diff --git a/examples/ftpc/ftpc_cmds.c b/examples/ftpc/ftpc_cmds.c index fd07a68ca..f0a0a2413 100755 --- a/examples/ftpc/ftpc_cmds.c +++ b/examples/ftpc/ftpc_cmds.c @@ -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; diff --git a/include/ftpc.h b/include/ftpc.h index 3f373dad8..ed5e3fab9 100644 --- a/include/ftpc.h +++ b/include/ftpc.h @@ -42,6 +42,7 @@ #include +#include #include #include #include @@ -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); diff --git a/netutils/ftpc/Makefile b/netutils/ftpc/Makefile index 9c5862a53..59121e3b7 100644 --- a/netutils/ftpc/Makefile +++ b/netutils/ftpc/Makefile @@ -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 diff --git a/netutils/ftpc/ftpc_cdup.c b/netutils/ftpc/ftpc_cdup.c index a5f22bbc2..75c02bd96 100644 --- a/netutils/ftpc/ftpc_cdup.c +++ b/netutils/ftpc/ftpc_cdup.c @@ -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; } diff --git a/netutils/ftpc/ftpc_chdir.c b/netutils/ftpc/ftpc_chdir.c index 0bc47ddf8..0081b4870 100644 --- a/netutils/ftpc/ftpc_chdir.c +++ b/netutils/ftpc/ftpc_chdir.c @@ -86,6 +86,6 @@ int ftpc_chdir(SESSION handle, FAR const char *path) return ret; } - ftpc_curdir(session); + ftpc_currdir(session); return OK; } diff --git a/netutils/ftpc/ftpc_chmod.c b/netutils/ftpc/ftpc_chmod.c index f349edb09..13d06f403 100644 --- a/netutils/ftpc/ftpc_chmod.c +++ b/netutils/ftpc/ftpc_chmod.c @@ -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" */ diff --git a/netutils/ftpc/ftpc_cmd.c b/netutils/ftpc/ftpc_cmd.c index ec89050ba..dc031790d 100644 --- a/netutils/ftpc/ftpc_cmd.c +++ b/netutils/ftpc/ftpc_cmd.c @@ -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 */ diff --git a/netutils/ftpc/ftpc_connect.c b/netutils/ftpc/ftpc_connect.c index 3af6ef65f..8affbdade 100644 --- a/netutils/ftpc/ftpc_connect.c +++ b/netutils/ftpc/ftpc_connect.c @@ -41,6 +41,7 @@ #include #include +#include #include #include @@ -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(); diff --git a/netutils/ftpc/ftpc_disconnect.c b/netutils/ftpc/ftpc_disconnect.c index 90c47ee1d..787de5f1b 100644 --- a/netutils/ftpc/ftpc_disconnect.c +++ b/netutils/ftpc/ftpc_disconnect.c @@ -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); diff --git a/netutils/ftpc/ftpc_filesize.c b/netutils/ftpc/ftpc_filesize.c index 18561eb1d..d827f736e 100644 --- a/netutils/ftpc/ftpc_filesize.c +++ b/netutils/ftpc/ftpc_filesize.c @@ -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; } diff --git a/netutils/ftpc/ftpc_getfile.c b/netutils/ftpc/ftpc_getfile.c index e9816e5b4..bf9fc69ea 100644 --- a/netutils/ftpc/ftpc_getfile.c +++ b/netutils/ftpc/ftpc_getfile.c @@ -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; } /**************************************************************************** diff --git a/netutils/ftpc/ftpc_idle.c b/netutils/ftpc/ftpc_idle.c index 2d049f8b4..95a94d233 100644 --- a/netutils/ftpc/ftpc_idle.c +++ b/netutils/ftpc/ftpc_idle.c @@ -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); } diff --git a/netutils/ftpc/ftpc_internal.h b/netutils/ftpc/ftpc_internal.h index 5e177b36b..6eab632a5 100644 --- a/netutils/ftpc/ftpc_internal.h +++ b/netutils/ftpc/ftpc_internal.h @@ -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 */ diff --git a/netutils/ftpc/ftpc_listdir.c b/netutils/ftpc/ftpc_listdir.c index 4c36445ad..e5309daed 100644 --- a/netutils/ftpc/ftpc_listdir.c +++ b/netutils/ftpc/ftpc_listdir.c @@ -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; diff --git a/netutils/ftpc/ftpc_login.c b/netutils/ftpc/ftpc_login.c index 83d2cde05..1d6ff395c 100644 --- a/netutils/ftpc/ftpc_login.c +++ b/netutils/ftpc/ftpc_login.c @@ -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; diff --git a/netutils/ftpc/ftpc_putfile.c b/netutils/ftpc/ftpc_putfile.c index f0e85a0bc..c465cc66d 100644 --- a/netutils/ftpc/ftpc_putfile.c +++ b/netutils/ftpc/ftpc_putfile.c @@ -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; } diff --git a/netutils/ftpc/ftpc_pwd.c b/netutils/ftpc/ftpc_rpwd.c similarity index 98% rename from netutils/ftpc/ftpc_pwd.c rename to netutils/ftpc/ftpc_rpwd.c index e8cfaef70..091a12944 100644 --- a/netutils/ftpc/ftpc_pwd.c +++ b/netutils/ftpc/ftpc_rpwd.c @@ -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 @@ -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; diff --git a/netutils/ftpc/ftpc_socket.c b/netutils/ftpc/ftpc_socket.c index 129e6f565..d70bf1d63 100644 --- a/netutils/ftpc/ftpc_socket.c +++ b/netutils/ftpc/ftpc_socket.c @@ -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; diff --git a/netutils/ftpc/ftpc_transfer.c b/netutils/ftpc/ftpc_transfer.c index bc0ca8b03..8d1a577e9 100644 --- a/netutils/ftpc/ftpc_transfer.c +++ b/netutils/ftpc/ftpc_transfer.c @@ -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) * ABORT */ - 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; +} + + diff --git a/netutils/ftpc/ftpc_utils.c b/netutils/ftpc/ftpc_utils.c index 9692cae4f..eec52ec8f 100644 --- a/netutils/ftpc/ftpc_utils.c +++ b/netutils/ftpc/ftpc_utils.c @@ -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 } /**************************************************************************** diff --git a/nshlib/nsh_apps.c b/nshlib/nsh_apps.c index 0d460a391..ec3d6ec88 100644 --- a/nshlib/nsh_apps.c +++ b/nshlib/nsh_apps.c @@ -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 diff --git a/nshlib/nsh_parse.c b/nshlib/nsh_parse.c index f6a778a03..5819def75 100644 --- a/nshlib/nsh_parse.c +++ b/nshlib/nsh_parse.c @@ -140,6 +140,10 @@ static const struct cmdmap_s g_cmdmap[] = { "[", cmd_lbracket, 4, NSH_MAX_ARGUMENTS, " ]" }, #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, " [ [ ...]]" }, @@ -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