Add nuttx to the system framework, which is 10.1.0

This commit is contained in:
TangYiwen123
2021-06-09 14:33:15 +08:00
parent 06c351e27c
commit 804bd57aa0
5000 changed files with 1488544 additions and 0 deletions
@@ -0,0 +1,53 @@
#
# For a description of the syntax of this configuration file,
# see the file kconfig-language.txt in the NuttX tools repository.
#
config NETUTILS_FTPC
bool "FTP client"
default n
---help---
Enable support for the FTP client.
if NETUTILS_FTPC
config DEBUG_FTPC
bool "Debug FTP client"
default n
depends on DEBUG_FEATURES
---help---
Enable debug support for the FTP client. This option simple forces
CONFIG_DEBUG_NET to be on, but only for the files within this directory.
config FTP_TMPDIR
string "TMP directory path for FTP"
default "/tmp"
---help---
The path to use for storing temporary files used in the transfer process
by the FTP client.
config FTP_SIZE_CMD_MODE_BINARY
bool "Use binary mode for size command"
default n
---help---
Use binary transfer mode for FTP size command.
config FTPC_DISABLE_EPRT
bool "Disable EPRT and use PORT instead"
default n
---help---
FTP uses PORT and EPRT when in active mode. EPRT replaced PORT to allow
for IPv6 support. EPRT is supported in most FTP implementations now. However,
if you need to use PORT instead, use this option to disable EPRT and
fallback to using PORT.
config FTPC_DISABLE_EPSV
bool "Disable EPSV and use PASV instead"
default n
---help---
FTP uses EPSV or PASV when in passive mode. EPSV replaced PASV to allow
for IPv6 support. EPSV is supported in most FTP implementations now. However,
if you need to use PASV instead, use this option to disable EPSV and
fallback to using PASV.
endif
@@ -0,0 +1,38 @@
# apps/netutils/ftpc/Make.defs
# Adds selected applications to apps/ build
#
# Copyright (C) 2016 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
ifeq ($(CONFIG_NETUTILS_FTPC),y)
CONFIGURED_APPS += $(APPDIR)/netutils/ftpc
endif
@@ -0,0 +1,58 @@
############################################################################
# apps/netutils/ftpc/Makefile
#
# Copyright (C) 2011-2012 Gregory Nutt. All rights reserved.
# Author: Gregory Nutt <gnutt@nuttx.org>
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the
# distribution.
# 3. Neither the name NuttX nor the names of its contributors may be
# used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
# COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
# OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
############################################################################
include $(APPDIR)/Make.defs
ifeq ($(CONFIG_NET_TCP),y)
# FTP connection management
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_rpwd.c ftpc_quit.c ftpc_rename.c ftpc_rmdir.c ftpc_unlink.c
CSRCS += ftpc_cmd.c
# FTP transfers
CSRCS += ftpc_getfile.c ftpc_putfile.c ftpc_transfer.c
# FTP responses
CSRCS += ftpc_response.c ftpc_getreply.c
# FTP helpers
CSRCS += ftpc_utils.c ftpc_socket.c
endif
include $(APPDIR)/Application.mk
@@ -0,0 +1,81 @@
# Network Utilities / `ftpc` FTP Client
## FTP Commands
- `ABOR` abort a file transfer
- `ACCT` send account information
- `APPE` append to a remote file
- `CDUP` CWD to the parent of the current directory
- `CWD` change working directory
- `DELE` delete a remote file
- `HELP` return help on using the server
- `LIST` list remote files
- `MDTM` return the modification time of a file
- `MKD` make a remote directory
- `MLSD` Standardized directory listing (instead of `LIST`)
- `MLST` Standardized object listing (instead of `LIST`)
- `MODE` set transfer mode
- `NLST` name list of remote directory
- `NOOP` do nothing
- `PASS` send password
- `PASV` enter passive mode
- `PORT` open a data port
- `PWD` print working directory
- `QUIT` terminate the connection
- `REIN` reinitialize the connection
- `RETR` retrieve a remote file
- `REST` Sets the point at which a file transfer should start
- `RMD` remove a remote directory
- `RNFR` rename from
- `RNTO` rename to
- `SITE` site-specific commands
- `SIZE` return the size of a file
- `STOR` store a file on the remote host
- `STOU` store a file uniquely
- `STRU` set file transfer structure
- `STAT` return server status
- `SYST` return system type
- `TYPE` set transfer type
- `USER` send username
## FTP Replies
- `110` Restart marker reply.
- `120` Service ready in nnn minutes.
- `125` Data connection already open; transfer starting.
- `150` File status okay; about to open data connection.
- `200` Command okay.
- `202` Command not implemented, superfluous at this site.
- `211` System status, or system help reply.
- `212` Directory status.
- `213` File status.
- `214` Help message.
- `215` NAME system type.
- `220` Service ready for new user.
- `221` Service closing control connection.
- `225` Data connection open; no transfer in progress.
- `226` Closing data connection.
- `227` Entering Passive Mode (`h1`, `h2`, `h3`, `h4`, `p1`, `p2`).
- `230` User logged in, proceed.
- `250` Requested file action okay, completed.
- `257` `PATHNAME` created.
- `331` User name okay, need password.
- `332` Need account for login.
- `350` Requested file action pending further information.
- `421` Service not available, closing control connection.
- `425` Can't open data connection.
- `426` Connection closed; transfer aborted.
- `450` Requested file action not taken.
- `451` Requested action aborted: local error in processing.
- `452` Requested action not taken.
- `500` Syntax error, command unrecognized.
- `501` Syntax error in parameters or arguments.
- `502` Command not implemented.
- `503` Bad sequence of commands.
- `504` Command not implemented for that parameter.
- `530` Not logged in.
- `532` Need account for storing files.
- `550` Requested action not taken.
- `551` Requested action aborted: page type unknown.
- `552` Requested file action aborted.
- `553` Requested action not taken.
@@ -0,0 +1,86 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_cdup.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_cdup
*
* Description:
* Make the parent of the current directory be the new current directory.
*
****************************************************************************/
int ftpc_cdup(SESSION handle)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret;
ret = ftpc_cmd(session, "CDUP");
session->currdir = ftpc_rpwd(handle);
return ret;
}
@@ -0,0 +1,80 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_chdir.c
*
* Copyright (C) 2011, 2017 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_chdir
*
* Description:
* Change the current working directory.
*
****************************************************************************/
int ftpc_chdir(SESSION handle, FAR const char *path)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret;
ret = ftpc_cmd(session, "CWD %s", path);
if (ret != OK)
{
return ret;
}
/* Free any previous setting and set the new working directory */
if (session->currdir != NULL)
{
free(session->currdir);
}
session->currdir = ftpc_rpwd(handle);
return OK;
}
@@ -0,0 +1,106 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_chmod.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_chmod
*
* Description:
* Change the protections on the remote file.
*
****************************************************************************/
int ftpc_chmod(SESSION handle, FAR const char *path, FAR const char *mode)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
/* Does the server support the size CHMOD command? */
if (FTPC_HAS_CHMOD(session))
{
ftpc_cmd(session, "SITE CHMOD %s %s", path, mode);
/* Check for "502 Command not implemented" */
if (session->code == 502)
{
/* No.. the server does not support the SITE CHMOD command */
FTPC_CLR_CHMOD(session);
}
return OK;
}
else
{
nwarn("WARNING: Server does not support SITE CHMOD\n");
}
return ERROR;
}
@@ -0,0 +1,233 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_cmd.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <strings.h>
#include <stdarg.h>
#include <errno.h>
#include <debug.h>
#include "ftpc_internal.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_restore
*
* Description:
* Restore the connection to the server and log in again.
*
****************************************************************************/
#ifdef CONFIG_FTP_AUTORECONNECT
static int ftpc_restore(struct ftpc_session_s *session)
{
int ret;
if (session)
{
/* Set the initial directory to the last valid current directory */
free(session->initrdir);
session->initrdir = ftpc_dequote(session->currdir);
/* Reconnect to the server */
ret = ftpc_reconnect(session);
if (ret == 0)
{
/* Log into the server */
ret = ftpc_relogin(session);
}
else
{
/* Failed to reconnect to the server */
ftpc_reset(session);
}
return ret;
}
return ERROR;
}
#endif
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_cmd
*
* Description:
* Send the specified command to the server.
*
****************************************************************************/
int ftpc_cmd(struct ftpc_session_s *session, const char *cmd, ...)
{
va_list ap;
#ifdef CONFIG_FTP_AUTORECONNECT
bool reconnect = false;
#endif
int ret;
/* Verify that we are still connected to the server */
if (!ftpc_sockconnected(&session->cmd))
{
nwarn("WARNING: Cmd channel is not connected\n");
goto errout;
}
/* Loop, reconnecting as necessary until the command is sent */
#ifdef CONFIG_FTP_AUTORECONNECT
for (; ; )
#endif
{
/* Send the command */
va_start(ap, cmd);
ret = ftpc_sockvprintf(&session->cmd, cmd, ap);
if (ret >= 0)
{
ret = ftpc_sockprintf(&session->cmd, "\r\n");
if (ret >= 0)
{
ret = ftpc_sockflush(&session->cmd);
}
}
va_end(ap);
/* Check for an error in sending the data */
if (ret < 0)
{
nerr("ERROR: Error sending cmd %s: %d\n", cmd, errno);
goto errout;
}
/* Get the response to the command */
ret = fptc_getreply(session);
if (ret < 0)
{
nerr("ERROR: Error getting reply: %d\n", errno);
goto errout;
}
/* Check for "421 Service not available, closing control connection" */
if (session->code == 421)
{
/* Server is closing the control connection. */
nwarn("WARNING: Server closed control connection\n");
/* If we were previously logged in and this is not a QUIT command
* then attempt to automatically reconnect to the server.
*/
#ifdef CONFIG_FTP_AUTORECONNECT
if (ftpc_loggedin(session) && strcasecmp(cmd, "QUIT") != 0)
{
/* Don't try re-connecting more than once */
if (reconnect)
{
nwarn("WARNING: Reconnect failed\n");
goto errout;
}
else
{
/* Try to restore the connection and, if successful,
* continue the loop and try to send the command again.
*/
ninfo("Reconnecting...\n");
reconnect = true;
ret = ftpc_restore();
if (ret < 0)
{
nwarn("WARNING: Failed to restore the connection");
goto errout;
}
continue;
}
}
else
#endif
{
/* Don't try to connect, just return an error (retaining
* the session response code (421)
*/
return ERROR;
}
}
/* Error codes 5xx are Permanent Negative Completion. These can be
* handled generically for all commands. An example is error code 530
* which means 'not logged in'. The reply should include a string to
* display to the user
*/
else if (session->code > 500 && session->code < 600)
{
return ERROR;
}
/* The command was successfully sent */
return OK;
}
errout:
session->code = -1;
return ERROR;
}
@@ -0,0 +1,79 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_config.h
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __APPS_NETUTILS_FTPC_FTPC_CONFIG_H
#define __APPS_NETUTILS_FTPC_FTPC_CONFIG_H
/****************************************************************************
* Included Files
****************************************************************************/
#include <nuttx/config.h>
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* This is a mindless little wrapper around include/nuttx/config.h. Every
* file in the ftpc directory includes this file at the very beginning of
* of the file (instead of include/nuttx/config.h). The only purpose of
* this file is to muck with some of the settings to support some debug
* features.
*
* The FPT client uses common networking debug macros (ndbg and ninfo).
* This can be overwhelming if there is a lot of networking debug output
* as well. But by defining CONFIG_DEBUG_FTPC, this file will force
* networking debug ON only for the files within this directory.
*/
#if !defined(CONFIG_DEBUG_NET) && defined(CONFIG_DEBUG_FTPC)
# undef CONFIG_DEBUG_NET
# define CONFIG_DEBUG_NET 1
# undef CONFIG_DEBUG_NET_ERROR
# define CONFIG_DEBUG_NET_ERROR 1
# undef CONFIG_DEBUG_NET_WARN
# define CONFIG_DEBUG_NET_WARN 1
# undef CONFIG_DEBUG_NET_INFO
# define CONFIG_DEBUG_NET_INFO 1
#endif
/****************************************************************************
* Public Types
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
#endif /* __APPS_NETUTILS_FTPC_FTPC_CONFIG_H */
@@ -0,0 +1,276 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_connect.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <debug.h>
#include <arpa/inet.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_connect
*
* Description:
* Create a session handle and connect to the server.
*
****************************************************************************/
SESSION ftpc_connect(FAR union ftpc_sockaddr_u *server)
{
FAR struct ftpc_session_s *session;
int ret;
/* Allocate a session structure */
session = (struct ftpc_session_s *)zalloc(sizeof(struct ftpc_session_s));
if (!session)
{
nerr("ERROR: Failed to allocate a session\n");
errno = ENOMEM;
goto errout;
}
/* Initialize the session structure with all non-zero and variable values */
memcpy(&session->server, server, sizeof(union ftpc_sockaddr_u));
session->flags &= ~FTPC_FLAGS_CLEAR;
session->flags |= FTPC_FLAGS_SET;
session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
session->pid = getpid();
/* Use the default port if the user specified port number zero */
#ifdef CONFIG_NET_IPv6
if (session->server.sa.sa_family == AF_INET6)
{
if (!session->server.in6.sin6_port)
{
session->server.in6.sin6_port = HTONS(CONFIG_FTP_DEFPORT);
}
}
#endif
#ifdef CONFIG_NET_IPv4
if (session->server.sa.sa_family == AF_INET)
{
if (!session->server.in4.sin_port)
{
session->server.in4.sin_port = HTONS(CONFIG_FTP_DEFPORT);
}
}
#endif
/* 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());
/* And (Re-)connect to the server */
ret = ftpc_reconnect(session);
if (ret != OK)
{
nerr("ERROR: ftpc_reconnect() failed: %d\n", errno);
goto errout_with_alloc;
}
return (SESSION)session;
errout_with_alloc:
if (session->homeldir != NULL)
{
free(session->homeldir);
}
free(session);
errout:
return NULL;
}
/****************************************************************************
* Name: ftpc_reconnect
*
* Description:
* re-connect to the server either initially, or after loss of connection.
*
****************************************************************************/
int ftpc_reconnect(FAR struct ftpc_session_s *session)
{
#ifdef CONFIG_DEBUG_NET_ERROR
char buffer[48];
#endif
int ret;
/* Re-initialize the session structure */
session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
session->xfrmode = FTPC_XFRMODE_UNKNOWN;
/* Set up a timer to prevent hangs */
ret = wd_start(&session->wdog, session->conntimeo,
ftpc_timeout, (wdparm_t)session);
if (ret != OK)
{
nerr("ERROR: wd_start() failed\n");
goto errout;
}
/* Initialize a socket */
ret = ftpc_sockinit(&session->cmd, session->server.sa.sa_family);
if (ret != OK)
{
nerr("ERROR: ftpc_sockinit() failed: %d\n", errno);
goto errout;
}
/* Connect the socket to the server */
#ifdef CONFIG_DEBUG_NET_ERROR
#ifdef CONFIG_NET_IPv6
if (session->server.sa.sa_family == AF_INET6)
{
if (inet_ntop(AF_INET6, &session->server.in6.sin6_addr, buffer, 48))
{
ninfo("Connecting to server address %s:%d\n", buffer,
ntohs(session->server.in6.sin6_port));
}
}
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_IPv4
if (session->server.sa.sa_family == AF_INET)
{
if (inet_ntop(AF_INET, &session->server.in4.sin_addr, buffer, 48))
{
ninfo("Connecting to server address %s:%d\n", buffer,
ntohs(session->server.in4.sin_port));
}
}
#endif /* CONFIG_NET_IPv4 */
#endif /* CONFIG_DEBUG_NET_ERROR */
ret = ftpc_sockconnect(&session->cmd,
(FAR struct sockaddr *)&session->server);
if (ret != OK)
{
nerr("ERROR: ftpc_sockconnect() failed: %d\n", errno);
goto errout_with_socket;
}
/* Read startup message from server */
fptc_getreply(session);
/* Check for "120 Service ready in nnn minutes" */
if (session->code == 120)
{
fptc_getreply(session);
}
wd_cancel(&session->wdog);
if (!ftpc_sockconnected(&session->cmd))
{
ftpc_reset(session);
goto errout;
}
/* Check for "220 Service ready for new user" */
if (session->code == 220)
{
FTPC_SET_CONNECTED(session);
}
if (!FTPC_IS_CONNECTED(session))
{
goto errout_with_socket;
}
#ifdef CONFIG_DEBUG_NET_ERROR
ninfo("Connected\n");
#ifdef CONFIG_NET_IPv6
if (session->server.sa.sa_family == AF_INET6)
{
if (inet_ntop(AF_INET6, &session->server.in6.sin6_addr, buffer, 48))
{
ninfo(" Remote address: %s:%d\n", buffer,
ntohs(session->server.in6.sin6_port));
}
if (inet_ntop(AF_INET6, &session->cmd.laddr.in6.sin6_addr, buffer, 48))
{
ninfo(" Local address: %s:%d\n", buffer,
ntohs(session->cmd.laddr.in6.sin6_port));
}
}
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_IPv4
if (session->server.sa.sa_family == AF_INET)
{
if (inet_ntop(AF_INET, &session->server.in4.sin_addr, buffer, 48))
{
ninfo(" Remote address: %s:%d\n", buffer,
ntohs(session->server.in4.sin_port));
}
if (inet_ntop(AF_INET, &session->cmd.laddr.in4.sin_addr, buffer, 48))
{
ninfo(" Local address: %s:%d\n", buffer,
ntohs(session->cmd.laddr.in4.sin_port));
}
}
#endif /* CONFIG_NET_IPv4 */
#endif /* CONFIG_DEBUG_NET_ERROR */
return OK;
errout_with_socket:
ftpc_sockclose(&session->cmd);
errout:
return ERROR;
}
@@ -0,0 +1,104 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_disconnect.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_disconnect
*
* Description:
* Disconnect from the server and destroy the session handle..
*
****************************************************************************/
void ftpc_disconnect(SESSION handle)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
if (session)
{
/* Release sockets */
ftpc_sockclose(&session->data);
ftpc_sockclose(&session->dacceptor);
ftpc_sockclose(&session->cmd);
/* Free strings */
free(session->uname);
free(session->pwd);
free(session->initrdir);
free(session->homerdir);
free(session->homeldir);
free(session->currdir);
/* Then destroy the session */
free(session);
}
}
@@ -0,0 +1,97 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_filesize.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdint.h>
#include <stdio.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_filesize
*
* Description:
* Return the size of the given file on the remote server.
*
****************************************************************************/
off_t ftpc_filesize(SESSION handle, FAR const char *path)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
unsigned long ret;
uint8_t mode = FTPC_XFRMODE_ASCII;
/* Check if the host supports the SIZE command */
if (!FTPC_HAS_SIZE(session))
{
return ERROR;
}
#ifdef CONFIG_FTP_SIZE_CMD_MODE_BINARY
mode = FTPC_XFRMODE_BINARY;
#endif
if (ftpc_xfrmode(session, mode) != 0)
{
return ERROR;
}
ret = ftpc_cmd(session, "SIZE %s", path);
/* Check for "502 Command not implemented" */
if (session->code == 502)
{
/* No.. the host does not support the SIZE command */
FTPC_CLR_SIZE(session);
return ERROR;
}
sscanf(session->reply, "%*s %lu", &ret);
return (off_t)ret;
}
@@ -0,0 +1,134 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_filetime.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <string.h>
#include <time.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_filetime
*
* Description:
* Return the timestamp on the remote file. Returned time is UTC
* (Universal Coordinated Time).
*
****************************************************************************/
time_t ftpc_filetime(SESSION handle, FAR const char *filename)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
struct tm timestamp;
int ret;
/* Make sure that the server is still connected */
if (!ftpc_connected(session))
{
return ERROR;
}
/* Does the server support the MDTM command? */
if (!FTPC_HAS_MDTM(session))
{
return ERROR;
}
/* Get the file time in UTC */
memset(&timestamp, 0, sizeof(timestamp));
ret = ftpc_cmd(session, "MDTM %s", filename);
if (ret != OK)
{
return ERROR;
}
/* Check for "202 Command not implemented, superfluous at this site" */
if (session->code == 202)
{
FTPC_CLR_MDTM(session);
return ERROR;
}
/* Check for "213 File status" */
if (session->code != 213)
{
return ERROR;
}
/* Time is Universal Coordinated Time */
sscanf(session->reply, "%*s %04d%02d%02d%02d%02d%02d",
&timestamp.tm_year, &timestamp.tm_mon, &timestamp.tm_mday,
&timestamp.tm_hour, &timestamp.tm_min, &timestamp.tm_sec);
timestamp.tm_year -= 1900;
timestamp.tm_mon--;
return mktime(&timestamp);
}
@@ -0,0 +1,431 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_getfile.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <debug.h>
#include <errno.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_recvinit
*
* Description:
* Initialize to receive a file
*
****************************************************************************/
static int ftpc_recvinit(struct ftpc_session_s *session,
FAR const char *path,
uint8_t xfrmode, off_t offset)
{
int ret;
/* Reset transfer related variables */
ftpc_xfrreset(session);
ret = ftpc_xfrinit(session);
if (ret != OK)
{
return ERROR;
}
/* Configure the transfer: Initial file offset and transfer mode */
session->offset = 0;
ftpc_xfrmode(session, xfrmode);
/* Handle the resume offset (caller is responsible for fseeking in the
* file)
*/
if (offset > 0)
{
/* Send the REST command. This command sets the offset where the
* transfer should start. This must come after PORT or PASV commands.
*/
ret = ftpc_cmd(session, "REST %ld", offset);
if (ret < 0)
{
nwarn("WARNING: REST command failed: %d\n", errno);
return ERROR;
}
session->size = offset;
}
/* Send the RETR (Retrieve a remote file) command. Normally the server
* responds with a mark using code 150:
*
* - "150 File status okay; about to open data connection"
*
* It then stops accepting new connections, attempts to send the contents
* of the file over the data connection, and closes the data connection.
* Finally it either accepts the RETR request with:
*
* - "226 Closing data connection" if the entire file was successfully
* written to the server's TCP buffers
*
* Or rejects the RETR request with:
*
* - "425 Can't open data connection" if no TCP connection was established
* - "426 Connection closed; transfer aborted" if the TCP connection was
* established but then broken by the client or by network failure
* - "451 Requested action aborted: local error in processing" or
* "551 Requested action aborted: page type unknown" if the server had
* trouble reading the file from disk.
*/
ret = ftpc_cmd(session, "RETR %s", path);
if (ret < 0)
{
nwarn("WARNING: RETR command failed: %d\n", errno);
return ERROR;
}
/* In active mode, we need to accept a connection on the data socket
* (in passive mode, we have already connected the data channel to
* the FTP server).
*/
if (!FTPC_IS_PASSIVE(session))
{
ret = ftpc_sockaccept(&session->dacceptor, &session->data);
if (ret != OK)
{
nerr("ERROR: Data connection not accepted\n");
}
}
return ret;
}
/****************************************************************************
* Name: ftpc_recvbinary
*
* Description:
* Receive a binary file.
*
****************************************************************************/
static int ftpc_recvbinary(FAR struct ftpc_session_s *session,
FAR FILE *rinstream, FAR FILE *loutstream)
{
ssize_t nread;
ssize_t nwritten;
/* Loop until the entire file is received */
for (; ; )
{
/* Read the data from the socket */
nread = fread(session->buffer, sizeof(char), CONFIG_FTP_BUFSIZE,
rinstream);
if (nread <= 0)
{
/* nread < 0 is an error */
if (nread < 0)
{
/* errno should already be set by fread */
ftpc_xfrabort(session, rinstream);
return ERROR;
}
/* nread == 0 means end of file. Return success */
return OK;
}
/* Write the data to the file */
nwritten = fwrite(session->buffer, sizeof(char), nread, loutstream);
if (nwritten != nread)
{
ftpc_xfrabort(session, loutstream);
/* If nwritten < 0 errno should already be set by fwrite.
* What would a short write mean?
*/
return ERROR;
}
/* Increment the size of the file written */
session->size += nwritten;
}
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_getfile
*
* Description:
* Get a file from the remote host.
*
****************************************************************************/
int ftpc_getfile(SESSION handle, FAR const char *rname,
FAR const char *lname,
uint8_t how, uint8_t xfrmode)
{
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;
/* Don't call this with a NULL remote file name */
DEBUGASSERT(rname);
/* If the local name is not specified, then it is assumed to the same as
* the remote file name.
*/
if (!lname)
{
lname = rname;
}
/* Get the full path to the local file */
abslpath = ftpc_abslpath(session, lname);
if (!abslpath)
{
nwarn("WARNING: ftpc_abslpath(%s) failed: %d\n", lname, errno);
goto errout;
}
/* Get information about the local file */
ret = stat(abslpath, &statbuf);
if (ret == 0)
{
/* It already exists. Is it a directory? */
if (S_ISDIR(statbuf.st_mode))
{
nwarn("WARNING: '%s' is a directory\n", abslpath);
goto errout_with_abspath;
}
}
/* Is it write-able? */
#ifdef S_IWRITE
if (!(statbuf.st_mode & S_IWRITE))
{
nwarn("WARNING: '%s' permission denied\n", abslpath);
goto errout_with_abspath;
}
#endif
/* Are we resuming the transfers? Is so then the starting offset is the
* size of the existing, partial file.
*/
if (how == FTPC_GET_RESUME)
{
offset = statbuf.st_size;
}
else
{
offset = 0;
}
/* Setup to receive the file */
ret = ftpc_recvinit(session, rname, xfrmode, offset);
if (ret != OK)
{
nerr("ERROR: ftpc_recvinit failed\n");
goto errout_with_abspath;
}
loutstream = fopen(abslpath,
(offset > 0 || (how == FTPC_GET_APPEND)) ? "a" : "w");
if (!loutstream)
{
nerr("ERROR: fopen failed: %d\n", errno);
goto errout_with_abspath;
}
/* If the offset is non-zero, then seek to that offset in the file */
if (offset > 0)
{
ret = fseek(loutstream, offset, SEEK_SET);
if (ret != OK)
{
nerr("ERROR: fseek failed: %d\n", errno);
goto errout_with_outstream;
}
}
/* And receive the new file data */
if (xfrmode == FTPC_XFRMODE_ASCII)
{
ret = ftpc_recvtext(session, session->data.instream, loutstream);
}
else
{
ret = ftpc_recvbinary(session, session->data.instream, loutstream);
}
ftpc_sockclose(&session->data);
if (ret == 0)
{
fptc_getreply(session);
}
/* Check for success */
if (ret == OK && !FTPC_INTERRUPTED(session))
{
fclose(loutstream);
free(abslpath);
return OK;
}
/* Various error exits */
errout_with_outstream:
fclose(loutstream);
errout_with_abspath:
free(abslpath);
session->offset = 0;
errout:
return ERROR;
}
/****************************************************************************
* Name: ftpc_recvtext
*
* Description:
* Receive a text file.
*
****************************************************************************/
int ftpc_recvtext(FAR struct ftpc_session_s *session,
FAR FILE *rinstream, FAR FILE *loutstream)
{
int ch;
/* Read the next character from the incoming data stream */
while ((ch = fgetc(rinstream)) != EOF)
{
/* Is it a carriage return? Compress \r\n to \n */
if (ch == '\r')
{
/* Get the next character */
ch = fgetc(rinstream);
if (ch == EOF)
{
/* Ooops... */
ftpc_xfrabort(session, rinstream);
return ERROR;
}
/* If its not a newline, then keep the carriage return */
if (ch != '\n')
{
ungetc(ch, rinstream);
ch = '\r';
}
}
/* Then write the character to the output file */
if (fputc(ch, loutstream) == EOF)
{
ftpc_xfrabort(session, loutstream);
return ERROR;
}
/* Increase the actual size of the file by one */
session->size++;
}
return OK;
}
@@ -0,0 +1,271 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_getreply.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include <debug.h>
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_gets
****************************************************************************/
static int ftpc_gets(struct ftpc_session_s *session)
{
int ch;
int ndx = 0;
/* Start with an empty response string */
session->reply[0] = '\0';
/* Verify that the command channel is still connected */
if (!ftpc_sockconnected(&session->cmd))
{
nwarn("WARNING: Cmd channel disconnected\n");
return ERROR;
}
/* Loop until the full line is obtained */
for (; ; )
{
/* Get the next character from incoming command stream */
ch = ftpc_sockgetc(&session->cmd);
/* Check if the command stream was closed */
if (ch == EOF)
{
nwarn("WARNING: EOF: Server closed command stream\n");
ftpc_reset(session);
return ERROR;
}
/* Handle embedded Telnet stuff */
else if (ch == TELNET_IAC)
{
/* Handle TELNET commands */
switch (ch = ftpc_sockgetc(&session->cmd))
{
case TELNET_WILL:
case TELNET_WONT:
ch = ftpc_sockgetc(&session->cmd);
ftpc_sockprintf(&session->cmd, "%c%c%c",
TELNET_IAC, TELNET_DONT, ch);
ftpc_sockflush(&session->cmd);
break;
case TELNET_DO:
case TELNET_DONT:
ch = ftpc_sockgetc(&session->cmd);
ftpc_sockprintf(&session->cmd, "%c%c%c",
TELNET_IAC, TELNET_WONT, ch);
ftpc_sockflush(&session->cmd);
break;
default:
break;
}
continue;
}
/* Deal with carriage returns */
else if (ch == ISO_CR)
{
/* What follows the carriage return? */
ch = ftpc_sockgetc(&session->cmd);
if (ch == '\0')
{
/* If it is followed by a NUL then keep it */
ch = ISO_CR;
}
/* If it is followed by a newline then break out of the loop. */
else if (ch == ISO_NL)
{
/* Newline terminates the reply */
break;
}
/* If we did not lose the connection, then push the character
* following the carriage back on the "stack" and continue to
* examine it from scratch (if could be part of the Telnet
* protocol).
*/
else if (ch != EOF)
{
ungetc(ch, session->cmd.instream);
continue;
}
}
else if (ch == ISO_NL)
{
/* The ISO newline character terminates the string. Just break
* out of the loop.
*/
break;
}
/* Put the character into the response buffer. Is there space for
* another character in the reply buffer?
*/
if (ndx < CONFIG_FTP_MAXREPLY)
{
/* Yes.. put the character in the reply buffer */
session->reply[ndx++] = (char)ch;
}
else
{
nwarn("WARNING: Reply truncated\n");
}
}
session->reply[ndx] = '\0';
session->code = atoi(session->reply);
return session->code;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_getreply
****************************************************************************/
int fptc_getreply(struct ftpc_session_s *session)
{
char tmp[5] = "xxx ";
int ret;
/* Set up a timeout */
if (session->replytimeo)
{
ret = wd_start(&session->wdog, session->replytimeo,
ftpc_timeout, (wdparm_t)session);
}
/* Get the next line from the server */
ret = ftpc_gets(session);
/* Do we still have a connection? */
if (!ftpc_sockconnected(&session->cmd))
{
/* No.. cancel the timer and return an error */
wd_cancel(&session->wdog);
ninfo("Lost connection\n");
return ERROR;
}
/* Did an error occur? */
if (ret < 0)
{
/* No.. cancel the timer and return an error */
wd_cancel(&session->wdog);
ninfo("ftpc_gets failed\n");
return ERROR;
}
ninfo("Reply: %s\n", session->reply);
if (session->reply[3] == '-')
{
/* Multi-line response */
strncpy(tmp, session->reply, 3);
do
{
if (ftpc_gets(session) == -1)
{
break;
}
ninfo("Reply: %s\n", session->reply);
}
while (strncmp(tmp, session->reply, 4) != 0);
}
wd_cancel(&session->wdog);
return ret;
}
@@ -0,0 +1,100 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_help.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_help
*
* Description:
* Request a list of available help commands. This implementation is
* fragementary and no ready for any real use at this time.
*
****************************************************************************/
int ftpc_help(SESSION handle, FAR const char *arg)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret;
/* Send the HELP command with or without an argument */
if (arg)
{
ret = ftpc_cmd(session, "HELP %s", arg);
}
else
{
ret = ftpc_cmd(session, "HELP");
}
/* Logic is missing here to return the help string to the caller. The caller
* needs to call ftpc_getreply.
*/
return ret;
}
@@ -0,0 +1,122 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_idle.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_idle
*
* Description:
* This command will change the FTP server's idle time limit with the site
* idle ftp command. This is useful if the default time limit is too short
* for the transmission of files).
*
****************************************************************************/
int ftpc_idle(SESSION handle, unsigned int idletime)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret = OK;
/* Check if the server supports the SITE IDLE command */
if (!FTPC_HAS_IDLE(session))
{
nwarn("WARNING: Server does not support SITE IDLE\n");
return ERROR;
}
/* Did the caller provide an IDLE time? Or is this just a query for the
* current IDLE time setting?
*/
if (idletime)
{
ret = ftpc_cmd(session, "SITE IDLE %u", idletime);
}
else
{
ret = ftpc_cmd(session, "SITE IDLE");
}
/* Check for "502 Command not implemented" or 500 "Unknown SITE command" */
if (session->code == 500 || session->code == 502)
{
/* Server does not support SITE IDLE */
nwarn("WARNING: Server does not support SITE IDLE\n");
FTPC_CLR_IDLE(session);
}
return ret;
}
@@ -0,0 +1,289 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_internal.h
*
* Copyright (C) 2011, 2014 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#ifndef __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H
#define __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <sys/types.h>
#include <sys/socket.h>
#include <stdio.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <nuttx/wdog.h>
#include <netinet/in.h>
#include "netutils/ftpc.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/* MISC definitions *********************************************************/
#define ISO_NL 0x0a
#define ISO_CR 0x0d
/* Telnet-related definitions */
#define TELNET_DM 242
#define TELNET_IP 244
#define TELNET_IAC 255
#define TELNET_WILL 251
#define TELNET_WONT 252
#define TELNET_DO 253
#define TELNET_DONT 254
/* Session flag bits ********************************************************/
#define FTPC_FLAG_PASSIVE (1 << 0) /* Passive mode requested */
#define FTPC_SESSION_FLAGS (0x0001) /* Persist throughout the session */
#define FTPC_FLAG_CONNECTED (1 << 1) /* Connected to host */
#define FTPC_FLAG_LOGGEDIN (1 << 2) /* Logged in to host */
#define FTPC_STATE_FLAGS (0x0006) /* State of connection */
#define FTPC_FLAG_MDTM (1 << 3) /* Host supports MDTM command */
#define FTPC_FLAG_SIZE (1 << 4) /* Host supports SIZE command */
#define FTPC_FLAG_PASV (1 << 5) /* Host supports PASV command */
#define FTPC_FLAG_STOU (1 << 6) /* Host supports STOU command */
#define FTPC_FLAG_CHMOD (1 << 7) /* Host supports SITE CHMOD command */
#define FTPC_FLAG_IDLE (1 << 8) /* Host supports SITE IDLE command */
#define FTPC_HOSTCAP_FLAGS (0x01f8) /* Host capabilities */
#define FTPC_FLAG_INTERRUPT (1 << 9) /* Transfer interrupted */
#define FTPC_FLAG_PUT (1 << 10) /* Transfer is a PUT operation (upload) */
#define FTPC_XFER_FLAGS (0x0600) /* Transfer related */
/* These are the bits to be set/cleared when the flags are reset */
#define FTPC_FLAGS_CLEAR (FTPC_STATE_FLAGS | FTPC_XFER_FLAGS)
#define FTPC_FLAGS_SET FTPC_HOSTCAP_FLAGS
/* Macros to set bits */
#define FTPC_SET_CONNECTED(s) do { (s)->flags |= FTPC_FLAG_CONNECTED; } while (0)
#define FTPC_SET_LOGGEDIN(s) do { (s)->flags |= FTPC_FLAG_LOGGEDIN; } while (0)
#define FTPC_SET_MDTM(s) do { (s)->flags |= FTPC_FLAG_MDTM; } while (0)
#define FTPC_SET_SIZE(s) do { (s)->flags |= FTPC_FLAG_SIZE; } while (0)
#define FTPC_SET_PASV(s) do { (s)->flags |= FTPC_FLAG_PASV; } while (0)
#define FTPC_SET_STOU(s) do { (s)->flags |= FTPC_FLAG_STOU; } while (0)
#define FTPC_SET_CHMOD(s) do { (s)->flags |= FTPC_FLAG_CHMOD; } while (0)
#define FTPC_SET_IDLE(s) do { (s)->flags |= FTPC_FLAG_IDLE; } while (0)
#define FTPC_SET_INTERRUPT(s) do { (s)->flags |= FTPC_FLAG_INTERRUPT; } while (0)
#define FTPC_SET_PUT(s) do { (s)->flags |= FTPC_FLAG_PUT; } while (0)
#define FTPC_SET_PASSIVE(s) do { (s)->flags |= FTPC_FLAG_PASSIVE; } while (0)
/* Macros to clear bits */
#define FTPC_CLR_CONNECTED(s) do { (s)->flags &= ~FTPC_FLAG_CONNECTED; } while (0)
#define FTPC_CLR_LOGGEDIN(s) do { (s)->flags &= ~FTPC_FLAG_LOGGEDIN; } while (0)
#define FTPC_CLR_MDTM(s) do { (s)->flags &= ~FTPC_FLAG_MDTM; } while (0)
#define FTPC_CLR_SIZE(s) do { (s)->flags &= ~FTPC_FLAG_SIZE; } while (0)
#define FTPC_CLR_PASV(s) do { (s)->flags &= ~FTPC_FLAG_PASV; } while (0)
#define FTPC_CLR_STOU(s) do { (s)->flags &= ~FTPC_FLAG_STOU; } while (0)
#define FTPC_CLR_CHMOD(s) do { (s)->flags &= ~FTPC_FLAG_CHMOD; } while (0)
#define FTPC_CLR_IDLE(s) do { (s)->flags &= ~FTPC_FLAG_IDLE; } while (0)
#define FTPC_CLR_INTERRUPT(s) do { (s)->flags &= ~FTPC_FLAG_INTERRUPT; } while (0)
#define FTPC_CLR_PUT(s) do { (s)->flags &= ~FTPC_FLAG_PUT; } while (0)
#define FTPC_CLR_PASSIVE(s) do { (s)->flags &= ~FTPC_FLAG_PASSIVE; } while (0)
/* Macros to test bits */
#define FTPC_IS_CONNECTED(s) (((s)->flags & FTPC_FLAG_CONNECTED) != 0)
#define FTPC_IS_LOGGEDIN(s) (((s)->flags & FTPC_FLAG_LOGGEDIN) != 0)
#define FTPC_HAS_MDTM(s) (((s)->flags & FTPC_FLAG_MDTM) != 0)
#define FTPC_HAS_SIZE(s) (((s)->flags & FTPC_FLAG_SIZE) != 0)
#define FTPC_HAS_PASV(s) (((s)->flags & FTPC_FLAG_PASV) != 0)
#define FTPC_HAS_STOU(s) (((s)->flags & FTPC_FLAG_STOU) != 0)
#define FTPC_HAS_CHMOD(s) (((s)->flags & FTPC_FLAG_CHMOD) != 0)
#define FTPC_HAS_IDLE(s) (((s)->flags & FTPC_FLAG_IDLE) != 0)
#define FTPC_INTERRUPTED(s) (((s)->flags & FTPC_FLAG_INTERRUPT) != 0)
#define FTPC_IS_PUT(s) (((s)->flags & FTPC_FLAG_PUT) != 0)
#define FTPC_IS_PASSIVE(s) (((s)->flags & FTPC_FLAG_PASSIVE) != 0)
/****************************************************************************
* Public Types
****************************************************************************/
/* This structure represents the state of one socket connection */
struct ftpc_socket_s
{
int sd; /* Socket descriptor */
FILE *instream; /* Incoming stream */
FILE *outstream; /* Outgoing stream */
union ftpc_sockaddr_u laddr; /* Local Address */
bool connected; /* True: socket is connected */
};
/* This structure represents the state of an FTP connection */
struct ftpc_session_s
{
union ftpc_sockaddr_u server; /* Server/proxy socket address */
struct ftpc_socket_s cmd; /* FTP command channel */
struct ftpc_socket_s data; /* FTP data channel */
struct ftpc_socket_s dacceptor; /* FTP data listener (accepts data connection in active mode) */
struct wdog_s wdog; /* Timer */
FAR char *uname; /* Login uname */
FAR char *pwd; /* Login pwd */
FAR char *initrdir; /* Initial remote directory */
FAR char *homerdir; /* Remote home directory (currdir on startup) */
FAR char *currdir; /* Remote current directory */
FAR char *homeldir; /* Local home directory (PWD on startup) */
pid_t pid; /* Task ID of FTP client */
uint8_t xfrmode; /* Previous data transfer type (See FTPC_XFRMODE_* defines) */
uint16_t flags; /* Connection flags (see FTPC_FLAGS_* defines) */
uint16_t code; /* Last 3-digit reply code */
uint32_t replytimeo; /* Server reply timeout (ticks) */
uint32_t conntimeo; /* Connection timeout (ticks) */
off_t offset; /* Transfer file offset */
off_t size; /* Number of bytes transferred */
char reply[CONFIG_FTP_MAXREPLY + 1]; /* Last reply string from server */
char buffer[CONFIG_FTP_BUFSIZE]; /* Used to buffer file data during transfers */
};
/* 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
****************************************************************************/
#ifdef __cplusplus
#define EXTERN extern "C"
extern "C"
{
#else
#define EXTERN extern
#endif
/****************************************************************************
* Inline Functions/Function-like Macros
****************************************************************************/
#define ftpc_sockconnected(s) \
((s) && (s)->connected)
#define ftpc_connected(s) \
(FTPC_IS_CONNECTED(session) && ftpc_sockconnected(&session->cmd))
#define ftpc_loggedin(s) \
(ftpc_connected(s) && FTPC_IS_LOGGEDIN(s))
#define ftpc_sockgetc(s) \
fgetc((s)->instream)
#define ftpc_sockflush(s) \
fflush((s)->outstream)
#define ftpc_sockvprintf(s,f,ap) \
vfprintf((s)->outstream,f,ap)
/****************************************************************************
* Public Function Prototypes
****************************************************************************/
/* Low-level string management */
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 FAR const char *ftpc_lpwd(void);
EXTERN int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode);
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 */
EXTERN int ftpc_sockinit(FAR struct ftpc_socket_s *sock, sa_family_t family);
EXTERN void ftpc_sockclose(FAR struct ftpc_socket_s *sock);
EXTERN int ftpc_sockconnect(FAR struct ftpc_socket_s *sock,
FAR struct sockaddr *addr);
EXTERN int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock,
FAR union ftpc_sockaddr_u *addr);
EXTERN int ftpc_sockaccept(FAR struct ftpc_socket_s *acceptor,
FAR struct ftpc_socket_s *sock);
EXTERN int ftpc_socklisten(FAR struct ftpc_socket_s *sock);
EXTERN void ftpc_sockcopy(FAR struct ftpc_socket_s *dest,
FAR const struct ftpc_socket_s *src);
/* Socket I/O helpers */
EXTERN int ftpc_sockprintf(FAR struct ftpc_socket_s *sock,
const char *fmt, ...);
EXTERN void ftpc_timeout(wdparm_t arg);
/* Transfer helpers */
EXTERN int ftpc_xfrinit(FAR struct ftpc_session_s *session);
EXTERN int ftpc_recvtext(FAR struct ftpc_session_s *session,
FAR FILE *rinstream, FAR FILE *loutstream);
EXTERN int ftpc_waitdata(FAR struct ftpc_session_s *session,
FAR FILE *stream, bool rdwait);
EXTERN void ftpc_xfrreset(struct ftpc_session_s *session);
EXTERN int ftpc_xfrabort(FAR struct ftpc_session_s *session,
FAR FILE *stream);
#undef EXTERN
#ifdef __cplusplus
}
#endif
#endif /* __APPS_NETUTILS_FTPC_FTPC_INTERNAL_H */
@@ -0,0 +1,420 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_listdir.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Private Types
****************************************************************************/
typedef void (*callback_t)(FAR const char *name, FAR void *arg);
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_dircount
*
* Description:
* This callback simply counts the number of names in the directory.
*
****************************************************************************/
static void ftpc_dircount(FAR const char *name, FAR void *arg)
{
FAR unsigned int *dircount = (FAR unsigned int *)arg;
(*dircount)++;
}
/****************************************************************************
* Name: ftpc_addname
*
* Description:
* This callback adds a name to the directory listing.
*
****************************************************************************/
static void ftpc_addname(FAR const char *name, FAR void *arg)
{
FAR struct ftpc_dirlist_s *dirlist = (FAR struct ftpc_dirlist_s *)arg;
unsigned int nnames = dirlist->nnames;
dirlist->name[nnames] = strdup(name);
dirlist->nnames = nnames + 1;
}
/****************************************************************************
* Name: ftpc_nlstparse
*
* Description:
* Parse the NLST directory response. The NLST response consists of a
* sequence of pathnames. Each pathname is terminated by \r\n.
*
* If a pathname starts with a slash, it represents the pathname. If a
* pathname does not start with a slash, it represents the pathname
* obtained by concatenating the pathname of the directory and the
* pathname.
*
* IF NLST of directory /pub produces foo\r\nbar\r\n, it refers to the
* pathnames /pub/foo and /pub/bar.
*
****************************************************************************/
static void ftpc_nlstparse(FAR FILE *instream, callback_t callback,
FAR void *arg)
{
char buffer[CONFIG_FTP_MAXPATH + 1];
/* Read every filename from the temporary file */
for (; ; )
{
/* Read the next line from the file */
if (!fgets(buffer, CONFIG_FTP_MAXPATH, instream))
{
break;
}
/* Remove any trailing CR-LF from the line */
ftpc_stripcrlf(buffer);
/* Check for empty file names */
if (buffer[0] == '\0')
{
break;
}
ninfo("File: %s\n", buffer);
/* Perform the callback operation */
callback(buffer, arg);
}
}
/****************************************************************************
* Name: ftpc_recvdir
*
* Description:
* Get the directory listing.
*
****************************************************************************/
static int ftpc_recvdir(FAR struct ftpc_session_s *session,
FAR FILE *outstream)
{
int ret;
/* Verify that we are still connected to the server */
if (!ftpc_connected(session))
{
nerr("ERROR: Not connected to server\n");
return ERROR;
}
/* Setup for the transfer */
ftpc_xfrreset(session);
ret = ftpc_xfrinit(session);
if (ret != OK)
{
return ERROR;
}
/* Send the "NLST" command. Normally the server responds with a mark
* using code 150:
*
* - "150 File status okay; about to open data connection"
*
* It then stops accepting new connections, attempts to
* send the contents of the directory over the data connection, and
* closes the data connection.
*/
ret = ftpc_cmd(session, "NLST");
if (ret != OK)
{
return ERROR;
}
/* In active mode, we need to accept a connection on the data socket
* (in passive mode, we have already connected the data channel to
* the FTP server).
*/
if (!FTPC_IS_PASSIVE(session))
{
ret = ftpc_sockaccept(&session->dacceptor, &session->data);
if (ret != OK)
{
nerr("ERROR: ftpc_sockaccept() failed: %d\n", errno);
return ERROR;
}
}
/* Receive the NLST directory list */
ret = ftpc_recvtext(session, session->data.instream, outstream);
ftpc_sockclose(&session->data);
if (ret != OK)
{
return ERROR;
}
/* Get the server reply. After closing the data connection, the should
* accept the request with:
*
* - "226 Closing data connection" if the entire directory was
* successfully transmitted;
*
* Or reject it with:
*
* - "425 Can't open data connection" if no TCP connection was established
* - "426 - Connection closed; transfer aborted" if the TCP connection was
* established but then broken by the client or by network failure
* - "451 - Requested action aborted: local error in processing" if the
* server had trouble reading the directory from disk.
*
* The server may reject the LIST or NLST request (with code 450 or 550)
* without first responding with a mark. In this case the server does not
* touch the data connection.
*/
fptc_getreply(session);
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_listdir
*
* Description:
* Get a simple directory listing using NLST:
*
* NLST [<SP> <pathname>] <CRLF>
*
* We could do much, much more here using the LIST or MLST/MLSD commands,
* but the parsing is a bitch. See http://cr.yp.to/ftpparse.html
*
* NOTE: We expect to receive only well structured directory paths. Tilde
* expansion "~/xyz" and relative paths (abc/def) because we do have
* special knowledge about the home and current directories. But otherwise
* the paths are expected to be pre-sanitized: No . or .. in paths,
* no multiple consecutive '/' in paths, etc.
*
****************************************************************************/
FAR struct ftpc_dirlist_s *ftpc_listdir(SESSION handle,
FAR const char *dirpath)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
struct ftpc_dirlist_s *dirlist;
FILE *filestream;
FAR char *absrpath;
FAR char *tmpfname;
bool iscurrdir;
unsigned int nnames;
int allocsize;
int ret;
/* If no remote current directory, we are not logged in. */
if (!session->currdir)
{
return NULL;
}
/* Get the absolute path to the directory */
absrpath = ftpc_absrpath(session, dirpath);
if (!absrpath)
{
return NULL;
}
ftpc_stripslash(absrpath);
/* Is the directory also the remote current working directory? */
iscurrdir = (strcmp(absrpath, session->currdir) == 0);
/* Create a temporary file to hold the directory listing */
ret = asprintf(&tmpfname, "%s/TMP%d.dat", CONFIG_FTP_TMPDIR, getpid());
if (ret < 0)
{
free(absrpath);
return NULL;
}
filestream = fopen(tmpfname, "w+");
if (!filestream)
{
nerr("ERROR: Failed to create %s: %d\n", tmpfname, errno);
free(absrpath);
free(tmpfname);
return NULL;
}
/* "CWD" first so that we get the directory contents, not the
* directory itself.
*/
if (!iscurrdir)
{
ret = ftpc_cmd(session, "CWD %s", absrpath);
if (ret != OK)
{
nerr("ERROR: CWD to %s failed\n", absrpath);
}
}
/* Send the NLST command with no arguments to get the entire contents of
* the directory.
*/
ret = ftpc_recvdir(session, filestream);
/* Go back to the correct current working directory */
if (!iscurrdir)
{
int tmpret = ftpc_cmd(session, "CWD %s", session->currdir);
if (tmpret != OK)
{
nerr("ERROR: CWD back to %s failed\n", session->currdir);
}
}
/* Did we successfully receive the directory listing? */
dirlist = NULL;
if (ret == OK)
{
/* Count the number of names in the temporary file */
rewind(filestream);
nnames = 0;
ftpc_nlstparse(filestream, ftpc_dircount, &nnames);
if (!nnames)
{
nwarn("WARNING: Nothing found in directory\n");
goto errout;
}
ninfo("nnames: %d\n", nnames);
/* Allocate and initialize a directory container */
allocsize = SIZEOF_FTPC_DIRLIST(nnames);
dirlist = (struct ftpc_dirlist_s *)malloc(allocsize);
if (!dirlist)
{
nerr("ERROR: Failed to allocate dirlist\n");
goto errout;
}
/* Then copy all of the directory strings into the container */
rewind(filestream);
dirlist->nnames = 0;
ftpc_nlstparse(filestream, ftpc_addname, dirlist);
DEBUGASSERT(nnames == dirlist->nnames);
}
errout:
fclose(filestream);
free(absrpath);
unlink(tmpfname);
free(tmpfname);
return dirlist;
}
/****************************************************************************
* Name: ftpc_dirfree
*
* Description:
* Release the allocated directory listing.
*
****************************************************************************/
void ftpc_dirfree(FAR struct ftpc_dirlist_s *dirlist)
{
int i;
if (dirlist)
{
/* Free each directory name in the directory container */
for (i = 0; i < dirlist->nnames; i++)
{
/* NULL means that the caller stole the string */
if (dirlist->name[i])
{
free(dirlist->name[i]);
}
}
/* Then free the container itself */
free(dirlist);
}
}
@@ -0,0 +1,185 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_login.c
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership. The
* ASF licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the
* License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <string.h>
#include <errno.h>
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_login
*
* Description:
* Log into the server
*
****************************************************************************/
int ftpc_login(SESSION handle, FAR struct ftpc_login_s *login)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int errcode;
int ret;
/* Verify that we are connected to a server */
if (!ftpc_connected(session))
{
nerr("ERROR: Not connected\n");
errcode = ENOTCONN;
goto errout_with_err;
}
/* Verify that we are not already logged in to the server */
if (ftpc_loggedin(session))
{
nerr("ERROR: Already logged in\n");
errcode = EINVAL;
goto errout_with_err;
}
/* Save the login parameter */
session->uname = ftpc_dequote(login->uname);
session->pwd = ftpc_dequote(login->pwd);
session->initrdir = ftpc_dequote(login->rdir);
/* Is passive mode requested? */
FTPC_CLR_PASSIVE(session);
if (login->pasv)
{
ninfo("Setting passive mode\n");
FTPC_SET_PASSIVE(session);
}
/* The (Re-)login to the server */
ret = ftpc_relogin(session);
if (ret != OK)
{
nerr("ERROR: login failed: %d\n", errno);
goto errout;
}
return OK;
errout_with_err:
errno = errcode;
errout:
return ERROR;
}
/****************************************************************************
* Name: ftpc_relogin
*
* Description:
* Log in again after a loss of connection
*
****************************************************************************/
int ftpc_relogin(FAR struct ftpc_session_s *session)
{
int ret;
/* Log into the server. First send the USER command. The server may
* accept USER with:
*
* - "230 User logged in, proceed" meaning that the client has permission
* access files under that username
* - "331 "User name okay, need password" or "332 Need account for login"
* meaning that permission might be granted after a PASS request.
*
* Or the server may reject USER with:
*
* - "530 Not logged in" meaning that the username is unacceptable.
*/
FTPC_CLR_LOGGEDIN(session);
ret = ftpc_cmd(session, "USER %s", session->uname);
if (ret != OK)
{
nerr("ERROR: USER %s cmd failed: %d\n", session->uname, errno);
return ERROR;
}
if (session->code == 331)
{
/* Send the PASS command with the passed. The server may accept PASS
* with:
*
* - "230 User logged in, proceed" meaning that the client has
* permission to access files under that username
* - "202 Command not implemented, superfluous at this site" meaning
* that permission was already granted in response to USER
* - "332 Need account for login" meaning that permission might be
* granted after an ACCT request.
*
* The server may reject PASS with:
*
* - "503 Bad sequence of commands" if the previous request was not
* USER.
* - "530 - Not logged in" if this username and password are
* unacceptable.
*/
ret = ftpc_cmd(session, "PASS %s", session->pwd);
if (ret != OK)
{
nerr("ERROR: PASS %s cmd failed: %d\n", session->pwd, errno);
return ret;
}
}
/* We are logged in.. the current working directory on login is our "home"
* directory.
*/
FTPC_SET_LOGGEDIN(session);
session->homerdir = ftpc_rpwd((SESSION)session);
if (session->homerdir != NULL)
{
session->currdir = strdup(session->homerdir);
}
/* If the user has requested a special start up directory, then change to
* that directory now.
*/
if (session->initrdir)
{
ftpc_chdir((SESSION)session, session->initrdir);
}
return OK;
}
@@ -0,0 +1,90 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_mkdir.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_mkdir
*
* Description:
* Creates the named directory on the remote server.
*
****************************************************************************/
int ftpc_mkdir(SESSION handle, FAR const char *path)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
char *ptr;
int ret;
ptr = strdup(path);
if (!ptr)
{
return ERROR;
}
ftpc_stripslash(ptr);
/* Send the MKD request. The MKD request asks the server to create a new
* directory. The server accepts the MKD with either:
*
* - "257 PATHNAME created" that includes the pathname of the directory
* - "250 - Requested file action okay, completed" if the directory was
* successfully created.
*
* The server reject MKD with:
*
* - "550 Requested action not taken" if the creation failed.
*/
ret = ftpc_cmd(session, "MKD %s", ptr);
free(ptr);
return ret;
}
@@ -0,0 +1,85 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_noop.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_noop
*
* Description:
* No operation command. Using NOOP allows us to make sure that commands
* are passed over the control connection without changing the status of
* any data transaction or server status. This is useful for (1)
* maintaining connections during long IDLE times and (2) It can also be
* used as a harmless way of detecting timeouts.
*
****************************************************************************/
int ftpc_noop(SESSION handle)
{
return ftpc_cmd((FAR struct ftpc_session_s *)handle, "NOOP");
}
@@ -0,0 +1,483 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_putfile.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <libgen.h>
#include <errno.h>
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_sendbinary
*
* Description:
* Send a binary file to the remote host.
*
****************************************************************************/
static int ftpc_sendbinary(FAR struct ftpc_session_s *session,
FAR FILE *linstream, FILE *routstream)
{
ssize_t nread;
ssize_t nwritten;
/* Loop until the entire file is sent */
for (; ; )
{
/* Read data from the file */
nread = fread(session->buffer, sizeof(char), CONFIG_FTP_BUFSIZE,
linstream);
if (nread <= 0)
{
/* nread == 0 is just EOF */
if (nread < 0)
{
ftpc_xfrabort(session, linstream);
return ERROR;
}
/* Return success */
return OK;
}
/* Send the data */
nwritten = fwrite(session->buffer, sizeof(char), nread, routstream);
if (nwritten != nread)
{
ftpc_xfrabort(session, routstream);
/* Return failure */
return ERROR;
}
/* Increment the size of the file sent */
session->size += nread;
}
}
/****************************************************************************
* Name: ftpc_sendtext
*
* Description:
* Send a text file to the remote host.
*
****************************************************************************/
static int ftpc_sendtext(FAR struct ftpc_session_s *session,
FAR FILE *linstream, FAR FILE *routstream)
{
int ch;
int ret = OK;
/* Write characters one at a time. */
while ((ch = fgetc(linstream)) != EOF)
{
/* If it is a newline, send a carriage return too */
if (ch == '\n')
{
if (fputc('\r', routstream) == EOF)
{
ftpc_xfrabort(session, routstream);
ret = ERROR;
break;
}
/* Increment the size of the file sent */
session->size++;
}
/* Send the character */
if (fputc(ch, routstream) == EOF)
{
ftpc_xfrabort(session, routstream);
ret = ERROR;
break;
}
/* Increment the size of the file sent */
session->size++;
}
return ret;
}
/****************************************************************************
* Name: ftpc_sendfile
*
* Description:
* Send the file to the remote host.
*
****************************************************************************/
static int ftpc_sendfile(struct ftpc_session_s *session, const char *path,
FILE *stream, uint8_t how, uint8_t xfrmode)
{
long offset = session->offset;
#ifdef CONFIG_DEBUG_FEATURES
FAR char *rname;
FAR char *str;
int len;
#endif
int ret;
session->offset = 0;
/* Were we asked to store a file uniquely? Does the host support the STOU
* command?
*/
if (how == FTPC_PUT_UNIQUE && !FTPC_HAS_STOU(session))
{
/* We cannot store a file uniquely */
return ERROR;
}
ftpc_xfrreset(session);
FTPC_SET_PUT(session);
/* Initialize for the transfer */
ret = ftpc_xfrinit(session);
if (ret != OK)
{
return ERROR;
}
ftpc_xfrmode(session, xfrmode);
/* The REST command sets the start position in the file. Some servers
* allow REST immediately before STOR for binary files.
*/
if (offset > 0)
{
ret = ftpc_cmd(session, "REST %ld", offset);
session->size = offset;
}
/* Send the file using STOR, STOU, or APPE:
*
* - STOR request asks the server to receive the contents of a file from
* the data connection already established by the client.
* - APPE is just like STOR except that, if the file already exists, the
* server appends the client's data to the file.
* - STOU is just like STOR except that it asks the server to create a
* file under a new pathname selected by the server. If the server
* accepts STOU, it provides the pathname in a human-readable format in
* the text of its response.
*/
switch (how)
{
case FTPC_PUT_UNIQUE:
{
ret = ftpc_cmd(session, "STOU %s", path);
/* Check for "502 Command not implemented" */
if (session->code == 502)
{
/* The host does not support the STOU command */
FTPC_CLR_STOU(session);
return ERROR;
}
/* Get the remote filename from the response */
#ifdef CONFIG_DEBUG_FEATURES
str = strstr(session->reply, " for ");
if (str)
{
str += 5;
len = strlen(str);
if (len)
{
if (*str == '\'')
{
rname = strndup(str + 1, len - 3);
}
else
{
rname = strndup(str, len - 1);
ninfo("Unique filename is: %s\n", rname);
}
free(rname);
}
}
#endif
}
break;
case FTPC_PUT_APPEND:
ret = ftpc_cmd(session, "APPE %s", path);
break;
case FTPC_PUT_NORMAL:
default:
ret = ftpc_cmd(session, "STOR %s", path);
break;
}
/* If the server is willing to create a new file under that name, or
* replace an existing file under that name, it responds with a mark
* using code 150:
*
* - "150 File status okay; about to open data connection"
*
* It then attempts to read the contents of the file from the data
* connection, and closes the data connection. Finally it accepts the STOR
* with:
*
* - "226 Closing data connection" if the entire file was successfully
* received and stored
*
* Or rejects the STOR with:
*
* - "425 Can't open data connection" if no TCP connection was established
* - "426 Connection closed; transfer aborted" if the TCP connection was
* established but then broken by the client or by network failure
* - "451 Requested action aborted: local error in processing",
* "452 - Requested action not taken", or "552 Requested file action
* aborted" if the server had trouble saving the file to disk.
*
* The server may reject the STOR request with:
*
* - "450 Requested file action not taken", "452 - Requested action not
* taken" or "553 Requested action not taken" without first responding
* with a mark.
*/
/* In active mode, we need to accept a connection on the data socket
* (in passive mode, we have already connected the data channel to
* the FTP server).
*/
if (!FTPC_IS_PASSIVE(session))
{
ret = ftpc_sockaccept(&session->dacceptor, &session->data);
if (ret != OK)
{
nerr("ERROR: Data connection not accepted\n");
return ERROR;
}
}
/* Then perform the data transfer */
if (xfrmode == FTPC_XFRMODE_ASCII)
{
ret = ftpc_sendtext(session, stream, session->data.outstream);
}
else
{
ret = ftpc_sendbinary(session, stream, session->data.outstream);
}
ftpc_sockflush(&session->data);
ftpc_sockclose(&session->data);
if (ret == 0)
{
fptc_getreply(session);
}
return OK;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_putfile
*
* Description:
* Put a file on the remote host.
*
****************************************************************************/
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;
/* Don't call this with a NULL local file name */
DEBUGASSERT(lname);
/* If the remote name is not specified, then it is assumed to the same as
* the local file name.
*/
if (!rname)
{
rname = lname;
}
/* Get the full path to the local file */
abslpath = ftpc_abslpath(session, lname);
if (!abslpath)
{
nwarn("WARNING: ftpc_abslpath(%s) failed: %d\n", lname, errno);
goto errout;
}
/* Make sure that the local file exists */
ret = stat(abslpath, &statbuf);
if (ret != OK)
{
nwarn("WARNING: stat(%s) failed: %d\n", abslpath, errno);
goto errout_with_abspath;
}
/* Make sure that the local name does not refer to a directory */
if (S_ISDIR(statbuf.st_mode))
{
nwarn("WARNING: %s is a directory\n", abslpath);
goto errout_with_abspath;
}
/* Open the local file for reading */
finstream = fopen(abslpath, "r");
if (!finstream)
{
nwarn("WARNING: fopen() failed: %d\n", errno);
goto errout_with_abspath;
}
/* Are we resuming a transfer? */
session->offset = 0;
if (how == FTPC_PUT_RESUME)
{
/* Yes... Get the size of the file. This will only work if the
* server supports the SIZE command.
*/
session->offset = ftpc_filesize(session, rname);
if (session->offset == (off_t)ERROR)
{
nwarn("WARNING: Failed to get size of remote file: %s\n", rname);
goto errout_with_instream;
}
else
{
/* Seek to the offset in the file corresponding to the size
* that we have already sent.
*/
ret = fseek(finstream, session->offset, SEEK_SET);
if (ret != OK)
{
nerr("ERROR: fseek failed: %d\n", errno);
goto errout_with_instream;
}
}
}
/* Send the file */
ret = ftpc_sendfile(session, rname, finstream, how, xfrmode);
if (ret == OK)
{
fclose(finstream);
free(abslpath);
return OK;
}
/* Various error exits */
errout_with_instream:
fclose(finstream);
errout_with_abspath:
free(abslpath);
errout:
return ERROR;
}
@@ -0,0 +1,92 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_quit.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <time.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_quit
*
* Description:
* Ends the FTP session with the remote computer and exits ftp
*
****************************************************************************/
int ftpc_quit(SESSION handle)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret = OK;
if (ftpc_connected(session))
{
session->replytimeo = 10 * CLOCKS_PER_SEC;
ret = ftpc_cmd(session, "QUIT");
}
ftpc_disconnect(handle);
return ret;
}
@@ -0,0 +1,125 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_rename.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_rename
*
* Description:
* Rename a file on the remote server.
*
****************************************************************************/
int ftpc_rename(SESSION handle, FAR const char *oldname,
FAR const char *newname)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
char *oldcopy;
char *newcopy;
int ret;
oldcopy = strdup(oldname);
if (!oldcopy)
{
return ERROR;
}
ftpc_stripslash(oldcopy);
/* A RNFR request asks the server to begin renaming a file. A typical
* server accepts RNFR with:
*
* - "350 Requested file action pending further information" if the file
* exists
*
* Or rejects RNFR with:
*
* - "450 Requested file action not taken"
* - "550 Requested action not taken"
*/
ret = ftpc_cmd(session, "RNFR %s", oldcopy);
if (ret != OK)
{
free(oldcopy);
return ERROR;
}
free(oldcopy);
newcopy = strdup(newname);
if (!newcopy)
{
return ERROR;
}
ftpc_stripslash(newcopy);
/* A RNTO request asks the server to finish renaming a file. RNTO must
* come immediately after RNFR; otherwise the server may reject RNTO with:
*
* - "503 Bad sequence of commands"
*
* A typical server accepts RNTO with:
*
* - "250 Requested file action okay, completed" if the file was renamed
* successfully
*
* Or rejects RMD with:
*
* - "550 Requested action not taken"
* - "553 Requested action not taken"
*/
ret = ftpc_cmd(session, "RNTO %s", newcopy);
free(newcopy);
return ret;
}
@@ -0,0 +1,84 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_response.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <string.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_response
*
* Description:
* Return the response string from the last command. This is allocated
* memory that must be freed using free() when it is no longer needed.
*
****************************************************************************/
FAR char *ftpc_response(SESSION handle)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
return strndup(session->reply, CONFIG_FTP_MAXREPLY);
}
@@ -0,0 +1,88 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_rmdir.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_rmdir
*
* Description:
* Deletes the named directory on the remote server.
*
****************************************************************************/
int ftpc_rmdir(SESSION handle, FAR const char *path)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
char *ptr;
int ret;
ptr = strdup(path);
if (!ptr)
{
return ERROR;
}
ftpc_stripslash(ptr);
/* An RMD request asks the server to remove a directory. A typical server
* accepts RMD with:
*
* - "250 Requested file action okay, completed" if the directory was
* successfully removed
*
* Or rejects RMD with:
*
* - "550 Requested action not taken" if the removal failed.
*/
ret = ftpc_cmd(session, "RMD %s", ptr);
free(ptr);
return ret;
}
@@ -0,0 +1,132 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_rpwd.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include <debug.h>
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_rpwd
*
* Description:
* Returns the current working directory on the remote server.
*
****************************************************************************/
FAR char *ftpc_rpwd(SESSION handle)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
FAR char *start;
FAR char *end;
FAR char *pwd;
FAR char *ptr;
int len;
/* Send the PWD command */
ftpc_cmd(session, "PWD");
/* Response is like: 257 "/home/gnutt" (from vsftpd).
*
* Extract the quoted path name into allocated memory.
*/
start = strchr(session->reply, '\"');
if (!start)
{
nwarn("WARNING: Opening quote not found\n");
return NULL;
}
start++;
end = strchr(start, '\"');
if (!end)
{
nwarn("WARNING: Closing quote not found\n");
return NULL;
}
/* Allocate memory for the path name:
*
* Reply: 257 "/home/gnutt"
* ^start ^end
*
* len = end - start + 1 = 11 (+ NUL terminator)
*/
len = end - start + 1;
pwd = (char *)malloc(len + 1);
if (!pwd)
{
nerr("ERROR: Failed to allocate string\n");
return NULL;
}
/* Copy the string into the allocated memory */
memcpy(pwd, start, len);
pwd[len] = '\0';
/* Remove any trailing slash that the server may have added */
ftpc_stripslash(pwd);
/* Change DOS style directory separator ('\') to UNIX style ('/') */
for (ptr = pwd; *ptr; ptr++)
{
if (*ptr == '\\')
{
*ptr = '/';
}
}
return pwd;
}
@@ -0,0 +1,415 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_socket.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <sys/socket.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <debug.h>
#include <errno.h>
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_sockinit
*
* Description:
* Initialize a socket. Create the socket and "wrap" it as C standard
* incoming and outgoing streams.
*
****************************************************************************/
int ftpc_sockinit(FAR struct ftpc_socket_s *sock, sa_family_t family)
{
/* Initialize the socket structure */
memset(sock, 0, sizeof(struct ftpc_socket_s));
DEBUGASSERT(family == AF_INET || family == AF_INET6);
sock->laddr.sa.sa_family = family;
/* Create a socket descriptor */
sock->sd = socket(family, SOCK_STREAM, IPPROTO_TCP);
if (sock->sd < 0)
{
nerr("ERROR: socket() failed: %d\n", errno);
goto errout;
}
/* Call fdopen to "wrap" the socket descriptor as an input stream using C
* buffered I/O.
*/
sock->instream = fdopen(sock->sd, "r");
if (!sock->instream)
{
nerr("ERROR: fdopen() failed: %d\n", errno);
goto errout_with_sd;
}
/* Call fdopen to "wrap" the socket descriptor as an output stream using C
* buffered I/O.
*/
sock->outstream = fdopen(sock->sd, "w");
if (!sock->outstream)
{
nerr("ERROR: fdopen() failed: %d\n", errno);
goto errout_with_instream;
}
return OK;
/* Close the instream. NOTE: Since the underlying socket descriptor is
* *not* dup'ed, the following close should fail harmlessly.
*/
errout_with_instream:
fclose(sock->instream);
sock->instream = NULL;
errout_with_sd:
close(sock->sd);
sock->sd = -1;
errout:
return ERROR;
}
/****************************************************************************
* Name: ftpc_sockclose
*
* Description:
* Close a socket
*
****************************************************************************/
void ftpc_sockclose(FAR struct ftpc_socket_s *sock)
{
/* Note that the same underlying socket descriptor is used for both streams.
* There should be harmless failures on the second fclose and the close.
*/
fclose(sock->instream);
fclose(sock->outstream);
close(sock->sd);
memset(sock, 0, sizeof(struct ftpc_socket_s));
sock->sd = -1;
}
/****************************************************************************
* Name: ftpc_sockconnect
*
* Description:
* Connect the socket to the host. On a failure, the caller should call.
* ftpc_sockclose() to clean up.
*
****************************************************************************/
int ftpc_sockconnect(FAR struct ftpc_socket_s *sock, FAR struct sockaddr *addr)
{
int ret;
/* Connect to the server */
#ifdef CONFIG_NET_IPv6
if (addr->sa_family == AF_INET6)
{
ret = connect(sock->sd, (struct sockaddr *)addr, sizeof(struct sockaddr_in6));
}
else
#endif
#ifdef CONFIG_NET_IPv4
if (addr->sa_family == AF_INET)
{
ret = connect(sock->sd, (struct sockaddr *)addr, sizeof(struct sockaddr_in));
}
else
#endif
{
nerr("ERROR: Unsupported address family\n");
return ERROR;
}
if (ret < 0)
{
nerr("ERROR: connect() failed: %d\n", errno);
return ERROR;
}
/* Get the local address of the socket */
ret = ftpc_sockgetsockname(sock, &sock->laddr);
if (ret < 0)
{
nerr("ERROR: ftpc_sockgetsockname() failed: %d\n", errno);
return ERROR;
}
sock->connected = true;
return OK;
}
/****************************************************************************
* Name: ftpc_sockcopy
*
* Description:
* Copy the socket state from one location to another.
*
****************************************************************************/
void ftpc_sockcopy(FAR struct ftpc_socket_s *dest,
FAR const struct ftpc_socket_s *src)
{
memcpy(&dest->laddr, &src->laddr, sizeof(dest->laddr));
dest->connected = ftpc_sockconnected(src);
}
/****************************************************************************
* Name: ftpc_sockaccept
*
* Description:
* Accept a connection on the data socket. This function is only used
* in active mode.
*
* In active mode FTP the client connects from a random port (N>1023) to the
* FTP server's command port, port 21. Then, the client starts listening to
* port N+1 and sends the FTP command PORT N+1 to the FTP server. The server
* will then connect back to the client's specified data port from its local
* data port, which is port 20. In passive mode FTP the client initiates
* both connections to the server, solving the problem of firewalls filtering
* the incoming data port connection to the client from the server. When
* opening an FTP connection, the client opens two random ports locally
* (N>1023 and N+1). The first port contacts the server on port 21, but
* instead of then issuing a PORT command and allowing the server to connect
* back to its data port, the client will issue the PASV command. The result
* of this is that the server then opens a random unprivileged port (P >
* 1023) and sends the PORT P command back to the client. The client then
* initiates the connection from port N+1 to port P on the server to transfer
* data.
*
****************************************************************************/
int ftpc_sockaccept(FAR struct ftpc_socket_s *acceptor,
FAR struct ftpc_socket_s *sock)
{
union ftpc_sockaddr_u addr;
socklen_t addrlen;
/* Any previous socket should have been uninitialized (0) or explicitly
* closed (-1). But the path to this function may include a call to
* ftpc_sockinit(). If so... close that socket and call accept to
* get a new one.
*/
if (sock->sd > 0)
{
ftpc_sockclose(sock);
}
addrlen = sizeof(addr);
sock->sd = accept(acceptor->sd, (struct sockaddr *)&addr, &addrlen);
if (sock->sd == -1)
{
nerr("ERROR: accept() failed: %d\n", errno);
return ERROR;
}
memcpy(&sock->laddr, &addr, sizeof(union ftpc_sockaddr_u));
/* Create in/out C buffer I/O streams on the data channel. First,
* create the incoming buffered stream.
*/
sock->instream = fdopen(sock->sd, "r");
if (!sock->instream)
{
nerr("ERROR: fdopen() failed: %d\n", errno);
goto errout_with_sd;
}
/* Create the outgoing stream */
sock->outstream = fdopen(sock->sd, "w");
if (!sock->outstream)
{
nerr("ERROR: fdopen() failed: %d\n", errno);
goto errout_with_instream;
}
return OK;
/* Close the instream. NOTE: Since the underlying socket descriptor is
* *not* dup'ed, the following close should fail harmlessly.
*/
errout_with_instream:
fclose(sock->instream);
sock->instream = NULL;
errout_with_sd:
close(sock->sd);
sock->sd = -1;
return ERROR;
}
/****************************************************************************
* Name: ftpc_socklisten
*
* Description:
* Bind the socket to local address and wait for connection from the server.
*
****************************************************************************/
int ftpc_socklisten(FAR struct ftpc_socket_s *sock)
{
int ret;
/* Bind the local socket to the local address */
#ifdef CONFIG_NET_IPv6
if (sock->laddr.sa.sa_family == AF_INET6)
{
sock->laddr.in6.sin6_port = 0;
ret = bind(sock->sd, (struct sockaddr *)&sock->laddr,
sizeof(struct sockaddr_in6));
}
else
#endif
#ifdef CONFIG_NET_IPv4
if (sock->laddr.sa.sa_family == AF_INET)
{
sock->laddr.in4.sin_port = 0;
ret = bind(sock->sd, (struct sockaddr *)&sock->laddr,
sizeof(struct sockaddr_in));
}
else
#endif
{
nerr("ERROR: unsupported family\n");
return ERROR;
}
if (ret < 0)
{
nerr("ERROR: bind() failed: %d\n", errno);
return ERROR;
}
/* Wait for the connection to the server */
if (listen(sock->sd, 1) == -1)
{
return ERROR;
}
/* Then get the local address selected by NuttX */
ret = ftpc_sockgetsockname(sock, &sock->laddr);
return ret;
}
/****************************************************************************
* Name: ftpc_sockprintf
*
* Description:
* printf to a socket stream
*
****************************************************************************/
int ftpc_sockprintf(FAR struct ftpc_socket_s *sock, FAR const char *fmt, ...)
{
va_list ap;
int r;
va_start(ap, fmt);
r = vfprintf(sock->outstream, fmt, ap);
va_end(ap);
return r;
}
/****************************************************************************
* Name: ftpc_sockgetsockname
*
* Description:
* Get the address of the local socket
*
****************************************************************************/
int ftpc_sockgetsockname(FAR struct ftpc_socket_s *sock,
FAR union ftpc_sockaddr_u *addr)
{
socklen_t len;
int ret;
len = sizeof(union ftpc_sockaddr_u);
ret = getsockname(sock->sd, (FAR struct sockaddr *)addr, &len);
if (ret < 0)
{
nerr("ERROR: getsockname failed: %d\n", errno);
return ERROR;
}
return OK;
}
@@ -0,0 +1,691 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_transfer.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <poll.h>
#include <ctype.h>
#include <errno.h>
#include <assert.h>
#include <debug.h>
#include <arpa/inet.h>
#include "netutils/ftpc.h"
#include "netutils/netlib.h"
#include "ftpc_internal.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftp_cmd_epsv
*
* Description:
* Enter passive mode using EPSV command.
*
* In active mode FTP the client connects from a random port (N>1023) to
* the FTP server's command port, port 21. Then the client starts listening
* to port N+1 and sends the FTP command PORT N+1 to the FTP server. The
* server will then connect back to the client's specified data port from
* its local data port, which is port 20. In passive mode FTP the client
* initiates both connections to the server, solving the problem of
* firewalls filtering the incoming data port connection to the client from
* the server. When opening an FTP connection, the client opens two random
* ports locally (N>1023 and N+1). The first port contacts the server on
* port 21, but instead of then issuing a PORT command and allowing the
* server to connect back to its data port, the client will issue the PASV
* command. The result of this is that the server then opens a random
* unprivileged port (P > 1023) and sends the PORT P command back to the
* client. The client then initiates the connection from port N+1 to port
* P on the server to transfer data.
*
****************************************************************************/
#ifndef CONFIG_FTPC_DISABLE_EPSV
static int ftp_cmd_epsv(FAR struct ftpc_session_s *session,
FAR union ftpc_sockaddr_u *addr)
{
char *ptr;
int nscan;
int ret;
uint16_t tmp;
/* Request passive mode. The server normally accepts EPSV with code 227.
* Its response is a single line showing the IP address of the server and
* the TCP port number where the server is accepting connections.
*/
ret = ftpc_cmd(session, "EPSV");
if (ret < 0 || !ftpc_connected(session))
{
return ERROR;
}
/* Skip over any leading stuff before important data begins */
ptr = session->reply + 4;
while (*ptr != '(')
{
ptr++;
if (ptr > (session->reply + sizeof(session->reply) - 1))
{
nwarn("WARNING: Error parsing EPSV reply: '%s'\n", session->reply);
return ERROR;
}
}
ptr++;
/* The response is then just the port number. None of the other fields
* are supplied.
*/
nscan = sscanf(ptr, "|||%hu|", &tmp);
if (nscan != 1)
{
nwarn("WARNING: Error parsing EPSV reply: '%s'\n", session->reply);
return ERROR;
}
#ifdef CONFIG_NET_IPv4
if (addr->sa.sa_family == AF_INET)
{
addr->in4.sin_port = HTONS(tmp);
}
#endif
#ifdef CONFIG_NET_IPv6
if (addr->sa.sa_family == AF_INET6)
{
addr->in6.sin6_port = HTONS(tmp);
}
#endif
return OK;
}
#endif
/****************************************************************************
* Name: ftp_cmd_pasv
*
* Description:
* Enter passive mode using PASV command.
*
* In active mode FTP the client connects from a random port (N>1023) to
* the FTP server's command port, port 21. Then the client starts listening
* to port N+1 and sends the FTP command PORT N+1 to the FTP server. The
* server will then connect back to the client's specified data port from
* its local data port, which is port 20. In passive mode FTP the client
* initiates both connections to the server, solving the problem of
* firewalls filtering the incoming data port connection to the client from
* the server. When opening an FTP connection, the client opens two random
* ports locally (N>1023 and N+1). The first port contacts the server on
* port 21, but instead of then issuing a PORT command and allowing the
* server to connect back to its data port, the client will issue the PASV
* of this is that the server then opens a random unprivileged port (P >
* command. The result 1023) and sends the PORT P command back to the
* client. The client then initiates the connection from port N+1 to port P
* on the server to transfer data.
*
****************************************************************************/
#ifdef CONFIG_FTPC_DISABLE_EPSV
static int ftp_cmd_pasv(FAR struct ftpc_session_s *session,
FAR union ftpc_sockaddr_u *addr)
{
int tmpap[6];
char *ptr;
int nscan;
int ret;
/* Request passive mode. The server normally accepts PASV with code 227.
* Its response is a single line showing the IP address of the server and
* the TCP port number where the server is accepting connections.
*/
ret = ftpc_cmd(session, "PASV");
if (ret < 0 || !ftpc_connected(session))
{
return ERROR;
}
/* Skip over any leading stuff before important data begins */
ptr = session->reply + 4;
while (*ptr != '\0' && !isdigit((int)*ptr))
{
ptr++;
}
/* The response is then 6 integer values: four representing the
* IP address and two representing the port number.
*/
nscan = sscanf(ptr, "%d,%d,%d,%d,%d,%d",
&tmpap[0], &tmpap[1], &tmpap[2],
&tmpap[3], &tmpap[4], &tmpap[5]);
if (nscan != 6)
{
nwarn("WARNING: Error parsing PASV reply: '%s'\n", session->reply);
return ERROR;
}
/* Then copy the sscanf'ed values as bytes */
memcpy(&addr->in4.sin_addr, tmpap, sizeof(addr->in4.sin_addr));
memcpy(&addr->in4.sin_port, &tmpap[4], sizeof(addr->in4.sin_port));
return OK;
}
#endif
/****************************************************************************
* 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;
/* 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] == '/')
{
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)
{
asprintf(&ptr, "%s%s", curdir, relpath + 1);
}
/* Check for an absolute path */
else if (relpath[0] == '/')
{
ptr = strdup(relpath);
}
/* Assume it a relative path */
else
{
asprintf(&ptr, "%s/%s", curdir, relpath);
}
return ptr;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_xfrinit
*
* Description:
* Perform common transfer setup logic.
*
****************************************************************************/
int ftpc_xfrinit(FAR struct ftpc_session_s *session)
{
union ftpc_sockaddr_u addr;
int ret;
#ifdef CONFIG_FTPC_DISABLE_EPRT
uint8_t *paddr;
uint8_t *pport;
#else
char ipstr[48];
#endif
/* We must be connected to initiate a transfer */
if (!ftpc_connected(session))
{
nerr("ERROR: Not connected\n");
goto errout;
}
/* Should we enter passive mode? */
if (FTPC_IS_PASSIVE(session))
{
/* Initialize the data channel */
ret = ftpc_sockinit(&session->data, session->server.sa.sa_family);
if (ret != OK)
{
nerr("ERROR: ftpc_sockinit() failed: %d\n", errno);
goto errout;
}
/* Does this host support the PASV command */
if (!FTPC_HAS_PASV(session))
{
nerr("ERROR: Host doesn't support passive mode\n");
goto errout_with_data;
}
/* Configure the address to be the server address. If EPSV is used, the
* port will be populated by parsing the reply of the EPSV command. If
* the PASV command is used, the address and port will be overwritten.
*/
memcpy(&addr, &session->server, sizeof(union ftpc_sockaddr_u));
/* Yes.. going passive. */
#ifdef CONFIG_FTPC_DISABLE_EPSV
ret = ftp_cmd_pasv(session, &addr);
if (ret < 0)
{
nerr("ERROR: ftp_cmd_pasv() failed: %d\n", errno);
goto errout_with_data;
}
#else
ret = ftp_cmd_epsv(session, &addr);
if (ret < 0)
{
nerr("ERROR: ftp_cmd_epsv() failed: %d\n", errno);
goto errout_with_data;
}
#endif
/* Connect the data socket */
ret = ftpc_sockconnect(&session->data, (FAR struct sockaddr *)&addr);
if (ret < 0)
{
nerr("ERROR: ftpc_sockconnect() failed: %d\n", errno);
goto errout_with_data;
}
}
else
{
/* Initialize the data listener socket that allows us to accept new
* data connections from the server
*/
ret = ftpc_sockinit(&session->dacceptor, session->server.sa.sa_family);
if (ret != OK)
{
nerr("ERROR: ftpc_sockinit() failed: %d\n", errno);
goto errout;
}
/* Use the server IP address to find the network interface, and
* subsequent local IP address used to establish the active
* connection. We must send the IP and port to the server so that
* it knows how to connect.
*/
#ifdef CONFIG_NET_IPv6
if (session->server.sa.sa_family == AF_INET6)
{
ret = netlib_ipv6adaptor(&session->server.in6.sin6_addr,
&session->dacceptor.laddr.in6.sin6_addr);
if (ret < 0)
{
nerr("ERROR: netlib_ipv6adaptor() failed: %d\n", ret);
goto errout_with_data;
}
}
else
#endif
#ifdef CONFIG_NET_IPv4
if (session->server.sa.sa_family == AF_INET)
{
ret = netlib_ipv4adaptor(session->server.in4.sin_addr.s_addr,
&session->dacceptor.laddr.in4.sin_addr.s_addr);
if (ret < 0)
{
nerr("ERROR: netlib_ipv4adaptor() failed: %d\n", ret);
goto errout_with_data;
}
}
else
#endif
{
nerr("ERROR: unsupported address family\n");
goto errout_with_data;
}
/* Wait for the connection to be established */
ftpc_socklisten(&session->dacceptor);
#ifdef CONFIG_FTPC_DISABLE_EPRT
/* Then send our local data channel address to the server */
paddr = (uint8_t *)&session->dacceptor.laddr.in4.sin_addr;
pport = (uint8_t *)&session->dacceptor.laddr.in4.sin_port;
ret = ftpc_cmd(session, "PORT %d,%d,%d,%d,%d,%d",
paddr[0], paddr[1], paddr[2],
paddr[3], pport[0], pport[1]);
#else
#ifdef CONFIG_NET_IPv6
if (session->dacceptor.laddr.sa.sa_family == AF_INET6)
{
if (!inet_ntop(AF_INET6, &session->dacceptor.laddr.in6.sin6_addr,
ipstr, 48))
{
nerr("ERROR: inet_ntop failed: %d\n", errno);
goto errout_with_data;
}
ret = ftpc_cmd(session, "EPRT |2|%s|%d|", ipstr,
session->dacceptor.laddr.in6.sin6_port);
}
else
#endif /* CONFIG_NET_IPv6 */
#ifdef CONFIG_NET_IPv4
if (session->dacceptor.laddr.sa.sa_family == AF_INET)
{
if (!inet_ntop(AF_INET, &session->dacceptor.laddr.in4.sin_addr,
ipstr, 48))
{
nerr("ERROR: inet_ntop failed: %d\n", errno);
goto errout_with_data;
}
ret = ftpc_cmd(session, "EPRT |1|%s|%d|", ipstr,
session->dacceptor.laddr.in4.sin_port);
}
else
#endif /* CONFIG_NET_IPv4 */
#endif /* CONFIG_FTPC_DISABLE_EPRT */
if (ret < 0)
{
nerr("ERROR: ftpc_cmd() failed: %d\n", errno);
goto errout_with_data;
}
}
return OK;
errout_with_data:
ftpc_sockclose(&session->data);
ftpc_sockclose(&session->dacceptor);
errout:
return ERROR;
}
/****************************************************************************
* Name: ftpc_xfrreset
*
* Description:
* Reset transfer variables
*
****************************************************************************/
void ftpc_xfrreset(struct ftpc_session_s *session)
{
session->size = 0;
session->flags &= ~FTPC_XFER_FLAGS;
}
/****************************************************************************
* Name: ftpc_xfrmode
*
* Description:
* Select ASCII or Binary transfer mode
*
****************************************************************************/
int ftpc_xfrmode(struct ftpc_session_s *session, uint8_t xfrmode)
{
int ret;
/* Check if we have already selected the requested mode */
DEBUGASSERT(xfrmode != FTPC_XFRMODE_UNKNOWN);
if (session->xfrmode != xfrmode)
{
/* Send the TYPE request to control the binary flag.
* Parameters for the TYPE request include:
*
* A: Turn the binary flag off.
* A N: Turn the binary flag off.
* I: Turn the binary flag on.
* L 8: Turn the binary flag on.
*
* The server accepts the TYPE request with code 200.
*/
ret = ftpc_cmd(session, "TYPE %c",
xfrmode == FTPC_XFRMODE_ASCII ? 'A' : 'I');
if (ret < 0)
{
return ERROR;
}
session->xfrmode = xfrmode;
}
return OK;
}
/****************************************************************************
* Name: ftpc_xfrabort
*
* Description:
* Abort a transfer in progress
*
****************************************************************************/
int ftpc_xfrabort(FAR struct ftpc_session_s *session, FAR FILE *stream)
{
FAR struct pollfd fds;
int ret;
/* Make sure that we are still connected */
if (!ftpc_connected(session))
{
return ERROR;
}
/* Check if there is data waiting to be read from the cmd channel */
fds.fd = session->cmd.sd;
fds.events = POLLIN;
ret = poll(&fds, 1, 0);
if (ret > 0)
{
/* Read data from command channel */
ninfo("Flush cmd channel data\n");
while (stream &&
fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);
return OK;
}
FTPC_SET_INTERRUPT(session);
/* Send the Telnet interrupt sequence to abort the transfer:
* <IAC IP><IAC DM>ABORT<CR><LF>
*/
ninfo("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 */
ftpc_sockflush(&session->cmd);
/* Read remaining bytes from connection */
while (stream &&
fread(session->buffer, 1, CONFIG_FTP_BUFSIZE, stream) > 0);
/* Get the ABORt reply */
fptc_getreply(session);
/* Expected replies are: "226 Closing data connection" or
* "426 Connection closed; transfer aborted"
*/
if (session->code != 226 && session->code != 426)
{
ninfo("Expected 226 or 426 reply\n");
}
else
{
/* Get the next reply */
fptc_getreply(session);
/* Expected replies are: "226 Closing data connection" or
* "225 Data connection open; no transfer in progress"
*/
if (session->code != 226 && session->code != 225)
{
ninfo("Expected 225 or 226 reply\n");
}
}
return ERROR;
}
/****************************************************************************
* Name: ftpc_timeout
*
* Description:
* A timeout occurred -- either on a specific command or while waiting
* for a reply.
*
* NOTE:
* This function executes in the context of a timer interrupt handler.
*
****************************************************************************/
void ftpc_timeout(wdparm_t arg)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)arg;
nerr("ERROR: Timeout!\n");
DEBUGASSERT(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);
ninfo("%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);
ninfo("%s -> %s\n", relpath, abslpath);
return abslpath;
}
@@ -0,0 +1,96 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_unlink.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include "netutils/ftpc.h"
#include "ftpc_internal.h"
/****************************************************************************
* Pre-processor Definitions
****************************************************************************/
/****************************************************************************
* Private Types
****************************************************************************/
/****************************************************************************
* Private Data
****************************************************************************/
/****************************************************************************
* Public Data
****************************************************************************/
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_unlink
*
* Description:
* Delete the given file from the remote server.
*
****************************************************************************/
int ftpc_unlink(SESSION handle, FAR const char *path)
{
FAR struct ftpc_session_s *session = (FAR struct ftpc_session_s *)handle;
int ret;
/* A DELE request asks the server to remove a regular file. A typical server
* accepts DELE with:
*
* - "250 Requested file action okay, completed" if the file was
* successfully removed
*
* Or rejects RMD with:
*
* - "550 Requested action not taken" f the removal failed.
*/
ret = ftpc_cmd(session, "DELE %s", path);
return ret;
}
@@ -0,0 +1,256 @@
/****************************************************************************
* apps/netutils/ftpc/ftpc_utils.c
*
* Copyright (C) 2011 Gregory Nutt. All rights reserved.
* Author: Gregory Nutt <gnutt@nuttx.org>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name NuttX nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
/****************************************************************************
* Included Files
****************************************************************************/
#include "ftpc_config.h"
#include <stdlib.h>
#include <string.h>
#include "ftpc_internal.h"
/****************************************************************************
* Private Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_nibble
*
* Description:
* Convert a ASCII hex 'digit' to binary
*
****************************************************************************/
int ftpc_nibble(char ch)
{
if (ch >= '0' && ch <= '9')
{
return (unsigned int)ch - '0';
}
else if (ch >= 'A' && ch <= 'F')
{
return (unsigned int)ch - 'A' + 10;
}
else if (ch >= 'a' && ch <= 'f')
{
return (unsigned int)ch - 'a' + 10;
}
return ERROR;
}
/****************************************************************************
* Public Functions
****************************************************************************/
/****************************************************************************
* Name: ftpc_reset
*
* Description:
* Reset the FTP session.
*
****************************************************************************/
void ftpc_reset(struct ftpc_session_s *session)
{
ftpc_sockclose(&session->data);
ftpc_sockclose(&session->cmd);
free(session->uname);
session->uname = NULL;
free(session->pwd);
session->pwd = NULL;
free(session->initrdir);
session->initrdir = NULL;
session->flags &= ~FTPC_FLAGS_CLEAR;
session->flags |= FTPC_FLAGS_SET;
session->xfrmode = FTPC_XFRMODE_UNKNOWN;
session->code = 0;
session->replytimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
session->conntimeo = CONFIG_FTP_DEFTIMEO * CLOCKS_PER_SEC;
}
/****************************************************************************
* 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
}
/****************************************************************************
* Name: ftpc_stripcrlf
*
* Description:
* Strip any trailing carriage returns or line feeds from a string (by
* overwriting them with NUL characters).
*
****************************************************************************/
void ftpc_stripcrlf(FAR char *str)
{
FAR char *ptr;
int len;
if (str)
{
len = strlen(str);
if (len > 0)
{
for (ptr = str + len - 1;
len > 0 && (*ptr == '\r' || *ptr == '\n');
ptr--, len--)
{
*ptr = '\0';
}
}
}
}
/****************************************************************************
* Name: ftpc_stripslash
*
* Description:
* Strip single trailing slash from a string (by overwriting it with NUL
* character).
*
****************************************************************************/
void ftpc_stripslash(FAR char *str)
{
FAR char *ptr;
int len;
if (str)
{
len = strlen(str);
if (len > 1)
{
ptr = str + len - 1;
if (*ptr == '/')
{
*ptr = '\0';
}
}
}
}
/****************************************************************************
* Name: ftpc_dequote
*
* Description:
* Convert quoted hexadecimal constants to binary values.
*
****************************************************************************/
FAR char *ftpc_dequote(FAR const char *str)
{
FAR char *allocstr = NULL;
FAR char *ptr;
int ms;
int ls;
int len;
if (str)
{
/* Allocate space for a modifiable copy of the string */
len = strlen(str);
allocstr = (FAR char *)malloc(len + 1);
if (allocstr)
{
/* Search the string */
ptr = allocstr;
while (*str != '\0')
{
/* Check for a quoted hex value (make sure that there are
* least 3 characters remaining in the string.
*/
if (len > 2 && str[0] == '%')
{
/* Extract the hex value */
ms = ftpc_nibble(str[1]);
if (ms >= 0)
{
ls = ftpc_nibble(str[2]);
if (ls >= 0)
{
/* Save the binary value and skip ahead by 3 */
*ptr++ = (char)(ms << 4 | ls);
str += 3;
len -= 3;
continue;
}
}
}
/* Just transfer the character */
*ptr++ = *str++;
len--;
}
/* NUL terminate */
*ptr = '\0';
}
}
return allocstr;
}