Changeset 8916bdc7 in rtems


Ignore:
Timestamp:
Mar 26, 2009, 2:11:53 PM (11 years ago)
Author:
Thomas Doerfler <Thomas.Doerfler@…>
Branches:
4.10, 4.11, master
Children:
8a775c27
Parents:
d785ce4a
Message:
  • libmisc/shell/shell.h: Pointer to oparations table for mount command is now const.
  • libnetworking/lib/ftpfs.c, libnetworking/rtems/ftpfs.h: Rewrite of the FTP file system which implements now the trivial command state machines of RFC 959. For the data transfer passive (= default) and active (= fallback) modes are now supported.
  • libmisc/shell/main_mount_ftp.c: Update for FTP file system changes.
Location:
cpukit
Files:
5 edited

Legend:

Unmodified
Added
Removed
  • cpukit/ChangeLog

    rd785ce4a r8916bdc7  
     12009-03-26      Sebastian Huber <sebastian.huber@embedded-brains.de>
     2
     3        * libmisc/shell/shell.h: Pointer to
     4        oparations table for mount command is now const.
     5        * libnetworking/lib/ftpfs.c, libnetworking/rtems/ftpfs.h: Rewrite of
     6        the FTP file system which implements now the trivial command state
     7        machines of RFC 959.  For the data transfer passive (= default) and
     8        active (= fallback) modes are now supported.
     9        * libmisc/shell/main_mount_ftp.c: Update for FTP file system changes.
     10
    1112009-03-12      Santosh G Vattam <vattam.santosh@gmail.com>
    212
  • cpukit/libmisc/shell/main_mount_ftp.c

    rd785ce4a r8916bdc7  
    3333  name:          "ftp",
    3434  driver_needed: 1,
    35   fs_ops:        &rtems_ftp_ops,
     35  fs_ops:        &rtems_ftpfs_ops,
    3636  mounter:       rtems_shell_libc_mounter
    3737};
  • cpukit/libmisc/shell/shell.h

    rd785ce4a r8916bdc7  
    223223
    224224struct rtems_shell_filesystems_tt {
    225   const char*                        name;
    226   int                                driver_needed;
    227   rtems_filesystem_operations_table* fs_ops;
    228   rtems_shell_filesystems_mounter_t  mounter;
     225  const char                              *name;
     226  int                                      driver_needed;
     227  const rtems_filesystem_operations_table *fs_ops;
     228  rtems_shell_filesystems_mounter_t        mounter;
    229229};
    230230
  • cpukit/libnetworking/lib/ftpfs.c

    rd785ce4a r8916bdc7  
     1/**
     2 * @file
     3 *
     4 * @brief File Transfer Protocol file system (FTP client).
     5 */
     6
    17/*
    2  * File Transfer Protocol client
    3  *
    4  * Transfer file to/from remote host
    5  *
    6  * This driver can be added to the RTEMS file system with a call to
    7  * "rtems_bsdnet_initialize_ftp_filesystem () ".
    8  * From then on, you can open, read and close files on a remote FTP server
    9  * using the following syntax:
    10  * To open a file "myfile.txt" in the directory "mydir" (relative to home
    11  * directory) on a server named "myserver" using the user id
    12  * "myuserid" and the password "my_very_secret_password" you must
    13  * specify the following path:
    14  *
    15  * /FTP/myuserid:my_very_secret_password/@myserver/mydirectory/myfile.txt
    16  *
    17  * If the server is the default server specified in BOOTP, it can be ommitted:
    18  *
    19  * /FTP/myuserid:my_very_secret_password/mydirectory/myfile.txt
    20  *
    21  * WARNING: write accesses have not yet been tested.
    22  *
     8 * Copyright (c) 2009
     9 * embedded brains GmbH
     10 * Obere Lagerstr. 30
     11 * D-82178 Puchheim
     12 * Germany
     13 * <rtems@embedded-brains.de>
    2314 *
    2415 * (c) Copyright 2002
     
    2617 * IMD Ingenieurbuero fuer Microcomputertechnik
    2718 * Herbststr. 8
    28  * 82178 Puchheim, Germany 
     19 * 82178 Puchheim, Germany
    2920 * <Thomas.Doerfler@imd-systems.de>
    3021 *
    31  * This code has been created after closly inspecting
    32  * "tftpdriver.c" from Eric Norum.
    33  *
    34  *  $Id$
     22 * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
     23 *
     24 * This code has been created after closly inspecting "tftpdriver.c" from Eric
     25 * Norum.
     26 *
     27 * The license and distribution terms for this file may be
     28 * found in the file LICENSE in this distribution or at
     29 * http://www.rtems.com/license/LICENSE.
     30 *
     31 * $Id$
    3532 */
    3633
     34#include <ctype.h>
     35#include <errno.h>
     36#include <fcntl.h>
     37#include <inttypes.h>
     38#include <malloc.h>
     39#include <netdb.h>
     40#include <stdarg.h>
    3741#include <stdio.h>
    38 #include <errno.h>
    39 #include <malloc.h>
     42#include <stdlib.h>
    4043#include <string.h>
    41 #include <stdlib.h>
    42 #include <fcntl.h>
    4344#include <unistd.h>
    44 #include <inttypes.h>
    45 #include <ctype.h>
     45#include <arpa/inet.h>
     46#include <netinet/in.h>
     47#include <sys/socket.h>
     48#include <sys/types.h>
     49
    4650#include <rtems.h>
     51#include <rtems/ftpfs.h>
     52#include <rtems/imfs.h>
    4753#include <rtems/libio.h>
    4854#include <rtems/rtems_bsdnet.h>
    49 #include <sys/types.h>
    50 #include <sys/socket.h>
    51 #include <netinet/in.h>
    52 #include <arpa/inet.h>
    53 #include <netdb.h>
    54 #include <rtems/ftpfs.h>
    55 
    56 
    57 #ifndef set_errno_and_return_minus_one
    58 #define set_errno_and_return_minus_one( _error ) \
    59   do { errno = (_error); return -1; } while(0)
     55#include <rtems/seterr.h>
     56
     57#ifdef DEBUG
     58  #define DEBUG_PRINTF( ...) printf( __VA_ARGS__)
     59#else
     60  #define DEBUG_PRINTF( ...)
    6061#endif
    6162
    62 /* #define DEBUG_OUT */
    63 
    64 /*
    65  * Well-known port for FTP
     63/**
     64 * @brief Connection entry for each open file stream.
    6665 */
    67 #define FTP_PORT_NUM    21
    68 
    69 /*
    70  * Pathname prefix
    71  */
    72 #define FTP_PATHNAME_PREFIX     "/FTP/"
    73 /*
    74  * reply codes
    75  */
    76 #define FTP_REPLY_CONNECT 220  /* Connection established       */
    77 #define FTP_REPLY_PASSREQ 331  /* user ok, password required   */
    78 #define FTP_REPLY_LOGIN   230  /* login finished               */
    79 #define FTP_REPLY_SUCCESS 200  /* xxx successful               */
    80 #define FTP_REPLY_OPENCONN 150 /* opening connection for tfer  */
    81 #define FTP_REPLY_TFERCMPL 226 /* transfer complete            */
    82 
    83 extern rtems_filesystem_operations_table  rtems_ftp_ops; 
    84 extern rtems_filesystem_file_handlers_r rtems_ftp_handlers;
    85 
    86 /*
    87  * FTP command strings
    88  */
    89 #define FTP_USER_CMD   "USER "
    90 #define FTP_PASS_CMD   "PASS "
    91 #define FTP_BINARY_CMD "TYPE I"
    92 #define FTP_PORT_CMD   "PORT "
    93 #define FTP_STOR_CMD   "STOR "
    94 #define FTP_RETR_CMD   "RETR "
    95 #define FTP_QUIT_CMD   "QUIT"
    96 
    97 /*
    98  * State of each FTP stream
    99  */
    100 struct ftpStream {
    101   /*
    102    * Control connection socket
     66typedef struct {
     67  /**
     68   * @brief Control connection socket.
    10369   */
    10470  int ctrl_socket;
    105   struct sockaddr_in    myCtrlAddress;
    106   struct sockaddr_in    farCtrlAddress;
     71
     72  /**
     73   * @brief Data transfer socket.
     74   */
     75  int data_socket;
     76
     77  /**
     78   * @brief End of file flag.
     79   */
     80  bool eof;
     81} rtems_ftpfs_entry;
     82
     83static bool rtems_ftpfs_verbose = false;
     84
     85rtems_status_code rtems_ftpfs_mount( const char *mount_point)
     86{
     87  int rv = 0;
     88
     89  if (mount_point == NULL) {
     90    mount_point = RTEMS_FTPFS_MOUNT_POINT_DEFAULT;
     91  }
     92
     93  rv = mkdir( mount_point, S_IRWXU | S_IRWXG | S_IRWXO);
     94  if (rv != 0) {
     95    return RTEMS_IO_ERROR;
     96  }
     97
     98  rv = mount(
     99    NULL,
     100    &rtems_ftpfs_ops,
     101    RTEMS_FILESYSTEM_READ_WRITE,
     102    NULL,
     103    mount_point
     104  );
     105  if (rv != 0) {
     106    return RTEMS_IO_ERROR;
     107  }
     108
     109  return RTEMS_SUCCESSFUL;
     110}
     111
     112rtems_status_code rtems_ftpfs_set_verbose( bool verbose)
     113{
     114  rtems_ftpfs_verbose = verbose;
     115
     116  return RTEMS_SUCCESSFUL;
     117}
     118
     119rtems_status_code rtems_ftpfs_get_verbose( bool *verbose)
     120{
     121  if (verbose == NULL) {
     122    return RTEMS_INVALID_ADDRESS;
     123  }
     124
     125  *verbose = rtems_ftpfs_verbose;
     126
     127  return RTEMS_SUCCESSFUL;
     128}
     129
     130int rtems_bsdnet_initialize_ftp_filesystem( void)
     131{
     132  rtems_status_code sc = RTEMS_SUCCESSFUL;
     133
     134  sc = rtems_ftpfs_mount( NULL);
     135
     136  if (sc == RTEMS_SUCCESSFUL) {
     137    return 0;
     138  } else {
     139    return -1;
     140  }
     141}
     142
     143typedef void (*rtems_ftpfs_reply_parser)(
     144  const char * /* reply fragment */,
     145  size_t /* reply fragment length */,
     146  void * /* parser argument */
     147);
     148
     149typedef enum {
     150  RTEMS_FTPFS_REPLY_START,
     151  RTEMS_FTPFS_REPLY_SINGLE_LINE,
     152  RTEMS_FTPFS_REPLY_SINGLE_LINE_DONE,
     153  RTEMS_FTPFS_REPLY_MULTI_LINE,
     154  RTEMS_FTPFS_REPLY_NEW_LINE,
     155  RTEMS_FTPFS_REPLY_NEW_LINE_START
     156} rtems_ftpfs_reply_state;
     157
     158typedef enum {
     159  RTEMS_FTPFS_REPLY_ERROR = 0,
     160  RTEMS_FTPFS_REPLY_1 = '1',
     161  RTEMS_FTPFS_REPLY_2 = '2',
     162  RTEMS_FTPFS_REPLY_3 = '3',
     163  RTEMS_FTPFS_REPLY_4 = '4',
     164  RTEMS_FTPFS_REPLY_5 = '5'
     165} rtems_ftpfs_reply;
     166
     167#define RTEMS_FTPFS_REPLY_SIZE 3
     168
     169static rtems_ftpfs_reply rtems_ftpfs_get_reply(
     170  int socket,
     171  rtems_ftpfs_reply_parser parser,
     172  void *parser_arg
     173)
     174{
     175  rtems_ftpfs_reply_state state = RTEMS_FTPFS_REPLY_START;
     176  bool verbose = rtems_ftpfs_verbose;
     177  char reply_first [RTEMS_FTPFS_REPLY_SIZE] = { 'a', 'a', 'a' };
     178  char reply_last [RTEMS_FTPFS_REPLY_SIZE] = { 'b', 'b', 'b' };
     179  size_t reply_first_index = 0;
     180  size_t reply_last_index = 0;
     181  char buf [128];
     182
     183  while (true) {
     184    /* Receive reply fragment from socket */
     185    ssize_t i = 0;
     186    ssize_t rv = recv( socket, buf, sizeof( buf), 0);
     187
     188    if (rv <= 0) {
     189      return RTEMS_FTPFS_REPLY_ERROR;
     190    }
     191
     192    /* Be verbose if necessary */
     193    if (verbose) {
     194      write( STDERR_FILENO, buf, (size_t) rv);
     195    }
     196
     197    /* Invoke parser if necessary */
     198    if (parser != NULL) {
     199      parser( buf, (size_t) rv, parser_arg);
     200    }
     201
     202    /* Parse reply fragment */
     203    for (i = 0; i < rv; ++i) {
     204      char c = buf [i];
     205
     206      switch (state) {
     207        case RTEMS_FTPFS_REPLY_START:
     208          if (reply_first_index < RTEMS_FTPFS_REPLY_SIZE) {
     209            reply_first [reply_first_index] = c;
     210            ++reply_first_index;
     211          } else if (c == '-') {
     212            state = RTEMS_FTPFS_REPLY_MULTI_LINE;
     213          } else {
     214            state = RTEMS_FTPFS_REPLY_SINGLE_LINE;
     215          }
     216          break;
     217        case RTEMS_FTPFS_REPLY_SINGLE_LINE:
     218          if (c == '\n') {
     219            state = RTEMS_FTPFS_REPLY_SINGLE_LINE_DONE;
     220          }
     221          break;
     222        case RTEMS_FTPFS_REPLY_MULTI_LINE:
     223          if (c == '\n') {
     224            state = RTEMS_FTPFS_REPLY_NEW_LINE_START;
     225            reply_last_index = 0;
     226          }
     227          break;
     228        case RTEMS_FTPFS_REPLY_NEW_LINE:
     229        case RTEMS_FTPFS_REPLY_NEW_LINE_START:
     230          if (reply_last_index < RTEMS_FTPFS_REPLY_SIZE) {
     231            state = RTEMS_FTPFS_REPLY_NEW_LINE;
     232            reply_last [reply_last_index] = c;
     233            ++reply_last_index;
     234          } else {
     235            state = RTEMS_FTPFS_REPLY_MULTI_LINE;
     236          }
     237          break;
     238        default:
     239          return RTEMS_FTPFS_REPLY_ERROR;
     240      }
     241    }
     242
     243    /* Check reply */
     244    if (state == RTEMS_FTPFS_REPLY_SINGLE_LINE_DONE) {
     245      if (
     246        isdigit( reply_first [0])
     247          && isdigit( reply_first [1])
     248          && isdigit( reply_first [2])
     249      ) {
     250        break;
     251      } else {
     252        return RTEMS_FTPFS_REPLY_ERROR;
     253      }
     254    } else if (state == RTEMS_FTPFS_REPLY_NEW_LINE_START) {
     255      bool ok = true;
     256
     257      for (i = 0; i < RTEMS_FTPFS_REPLY_SIZE; ++i) {
     258        ok = ok
     259          && reply_first [i] == reply_last [i]
     260          && isdigit( reply_first [i]);
     261      }
     262
     263      if (ok) {
     264        break;
     265      }
     266    }
     267  }
     268
     269  return reply_first [0];
     270}
     271
     272static rtems_ftpfs_reply rtems_ftpfs_send_command_with_parser(
     273  int socket,
     274  const char *cmd,
     275  const char *arg,
     276  rtems_ftpfs_reply_parser parser,
     277  void *parser_arg
     278)
     279{
     280  const char *const eol = "\r\n";
     281  bool verbose = rtems_ftpfs_verbose;
     282  int rv = 0;
     283
     284  /* Send command */
     285  rv = send( socket, cmd, strlen( cmd), 0);
     286  if (rv < 0) {
     287    return RTEMS_FTPFS_REPLY_ERROR;
     288  }
     289  if (verbose) {
     290    write( STDERR_FILENO, cmd, strlen( cmd));
     291  }
     292
     293  /* Send command argument if necessary */
     294  if (arg != NULL) {
     295          rv = send( socket, arg, strlen( arg), 0);
     296          if (rv < 0) {
     297            return RTEMS_FTPFS_REPLY_ERROR;
     298          }
     299    if (verbose) {
     300      write( STDERR_FILENO, arg, strlen( arg));
     301    }
     302  }
     303
     304  /* Send end of line */
     305  rv = send( socket, eol, 2, 0);
     306  if (rv < 0) {
     307    return RTEMS_FTPFS_REPLY_ERROR;
     308  }
     309  if (verbose) {
     310    write( STDERR_FILENO, &eol [1], 1);
     311  }
     312
     313  /* Return reply */
     314  return rtems_ftpfs_get_reply( socket, parser, parser_arg);
     315}
     316
     317static rtems_ftpfs_reply rtems_ftpfs_send_command(
     318  int socket,
     319  const char *cmd,
     320  const char *arg
     321)
     322{
     323  return rtems_ftpfs_send_command_with_parser( socket, cmd, arg, NULL, NULL);
     324}
     325
     326typedef enum {
     327  STATE_USER_NAME,
     328  STATE_START_PASSWORD,
     329  STATE_START_HOST_NAME,
     330  STATE_START_HOST_NAME_OR_PATH,
     331  STATE_START_PATH,
     332  STATE_PASSWORD,
     333  STATE_HOST_NAME,
     334  STATE_DONE,
     335  STATE_INVALID
     336} split_state;
     337
     338static bool rtems_ftpfs_split_names (
     339  char *s,
     340  const char **user,
     341  const char **password,
     342  const char **hostname,
     343  const char **path
     344)
     345{
     346  split_state state = STATE_USER_NAME;
     347  size_t len = strlen( s);
     348  size_t i = 0;
     349
     350  *user = s;
     351  *password = NULL;
     352  *hostname = NULL;
     353  *path = NULL;
     354
     355  for (i = 0; i < len; ++i) {
     356    char c = s [i];
     357
     358    switch (state) {
     359      case STATE_USER_NAME:
     360        if (c == ':') {
     361          state = STATE_START_PASSWORD;
     362          s [i] = '\0';
     363        } else if (c == '@') {
     364          state = STATE_START_HOST_NAME;
     365          s [i] = '\0';
     366        } else if (c == '/') {
     367          state = STATE_START_HOST_NAME_OR_PATH;
     368          s [i] = '\0';
     369        }
     370        break;
     371      case STATE_START_PASSWORD:
     372        state = STATE_PASSWORD;
     373        *password = &s [i];
     374        --i;
     375        break;
     376      case STATE_START_HOST_NAME:
     377        state = STATE_HOST_NAME;
     378        *hostname = &s [i];
     379        --i;
     380        break;
     381      case STATE_START_HOST_NAME_OR_PATH:
     382        if (c == '@') {
     383          state = STATE_START_HOST_NAME;
     384        } else {
     385          state = STATE_DONE;
     386          *path = &s [i];
     387          goto done;
     388        }
     389        break;
     390      case STATE_START_PATH:
     391        state = STATE_DONE;
     392        *path = &s [i];
     393        goto done;
     394      case STATE_PASSWORD:
     395        if (c == '@') {
     396          state = STATE_START_HOST_NAME;
     397          s [i] = '\0';
     398        } else if (c == '/') {
     399          state = STATE_START_HOST_NAME_OR_PATH;
     400          s [i] = '\0';
     401        }
     402        break;
     403      case STATE_HOST_NAME:
     404        if (c == '/') {
     405          state = STATE_START_PATH;
     406          s [i] = '\0';
     407        }
     408        break;
     409      default:
     410        state = STATE_INVALID;
     411        goto done;
     412    }
     413  }
     414
     415done:
     416
     417  /* If we have no password use the user name */
     418  if (*password == NULL) {
     419    *password = *user;
     420  }
     421
     422  return state == STATE_DONE;
     423}
     424
     425static socklen_t rtems_ftpfs_create_address(
     426  struct sockaddr_in *sa,
     427  unsigned long address,
     428  unsigned short port
     429)
     430{
     431  memset( sa, sizeof( *sa), 0);
     432
     433  sa->sin_family = AF_INET;
     434  sa->sin_addr.s_addr = address;
     435  sa->sin_port = port;
     436  sa->sin_len = sizeof( *sa);
     437
     438  return sizeof( *sa);
     439}
     440
     441static void rtems_ftpfs_terminate( rtems_ftpfs_entry *e, rtems_libio_t *iop)
     442{
     443  if (e != NULL) {
     444    /* Close data connection if necessary */
     445    if (e->data_socket >= 0) {
     446      close( e->data_socket);
     447    }
     448
     449    /* Close control connection if necessary */
     450    if (e->ctrl_socket >= 0) {
     451      close( e->ctrl_socket);
     452    }
     453
     454    /* Free connection entry */
     455    free( e);
     456  }
     457
     458  /* Invalidate IO entry */
     459  iop->data1 = NULL;
     460}
     461
     462static int rtems_ftpfs_open_ctrl_connection(
     463  rtems_ftpfs_entry *e,
     464  const char *user,
     465  const char *password,
     466  const char *hostname,
     467  uint32_t *client_address
     468)
     469{
     470  int rv = 0;
     471  rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
     472  struct in_addr address = { .s_addr = 0 };
     473  struct sockaddr_in sa;
     474  socklen_t size = 0;
     475
     476  /* Create the socket for the control connection */
     477  e->ctrl_socket = socket( AF_INET, SOCK_STREAM, 0);
     478  if (e->ctrl_socket < 0) {
     479    return ENOMEM;
     480  }
     481
     482  /* Set up the server address from the hostname */
     483  if (hostname == NULL || strlen( hostname) == 0) {
     484    /* Default to BOOTP server address */
     485    address = rtems_bsdnet_bootp_server_address;
     486  } else if (inet_aton( hostname, &address) == 0) {
     487    /* Try to get the address by name */
     488    struct hostent *he = gethostbyname( hostname);
     489
     490    if (he != NULL) {
     491      memcpy( &address, he->h_addr, sizeof( address));
     492    } else {
     493      return ENOENT;
     494    }
     495  }
     496  rtems_ftpfs_create_address( &sa, address.s_addr, htons( RTEMS_FTPFS_CTRL_PORT));
     497  DEBUG_PRINTF( "server = %s\n", inet_ntoa( sa.sin_addr));
     498
     499  /* Open control connection */
     500  rv = connect(
     501    e->ctrl_socket,
     502    (struct sockaddr *) &sa,
     503    sizeof( sa)
     504  );
     505  if (rv != 0) {
     506    return ENOENT;
     507  }
     508
     509  /* Get client address */
     510  size = rtems_ftpfs_create_address( &sa, INADDR_ANY, 0);
     511  rv = getsockname(
     512    e->ctrl_socket,
     513    (struct sockaddr *) &sa,
     514    &size
     515  );
     516  if (rv != 0) {
     517    return ENOMEM;
     518  }
     519  *client_address = ntohl( sa.sin_addr.s_addr);
     520  DEBUG_PRINTF( "client = %s\n", inet_ntoa( sa.sin_addr));
     521
     522  /* Now we should get a welcome message from the server */
     523  reply = rtems_ftpfs_get_reply( e->ctrl_socket, NULL, NULL);
     524  if (reply != RTEMS_FTPFS_REPLY_2) {
     525    return ENOENT;
     526  }
     527
     528  /* Send USER command */
     529  reply = rtems_ftpfs_send_command( e->ctrl_socket, "USER ", user);
     530  if (reply == RTEMS_FTPFS_REPLY_3) {
     531    /* Send PASS command */
     532    reply = rtems_ftpfs_send_command( e->ctrl_socket, "PASS ", password);
     533    if (reply != RTEMS_FTPFS_REPLY_2) {
     534      return EACCES;
     535    }
     536
     537    /* TODO: Some server may require an account */
     538  } else if (reply != RTEMS_FTPFS_REPLY_2) {
     539    return EACCES;
     540  }
     541
     542  /* Send TYPE command to set binary mode for all data transfers */
     543  reply = rtems_ftpfs_send_command( e->ctrl_socket, "TYPE I", NULL);
     544  if (reply != RTEMS_FTPFS_REPLY_2) {
     545    return EIO;
     546  }
     547
     548  return 0;
     549}
     550
     551static int rtems_ftpfs_open_data_connection_active(
     552  rtems_ftpfs_entry *e,
     553  uint32_t client_address,
     554  const char *file_command,
     555  const char *filename
     556)
     557{
     558  int rv = 0;
     559  int eno = 0;
     560  rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
     561  struct in_addr address = { .s_addr = 0 };
     562  struct sockaddr_in sa;
     563  socklen_t size = 0;
     564  int port_socket = -1;
     565  char port_command [] = "PORT 000,000,000,000,000,000";
     566  uint16_t data_port = 0;
     567
     568  /* Create port socket to establish a data data connection */
     569  port_socket = socket( AF_INET, SOCK_STREAM, 0);
     570  if (port_socket < 0) {
     571    eno = ENOMEM;
     572    goto cleanup;
     573  }
     574
     575  /* Bind port socket */
     576  rtems_ftpfs_create_address( &sa, INADDR_ANY, 0);
     577  rv = bind(
     578    port_socket,
     579    (struct sockaddr *) &sa,
     580    sizeof( sa)
     581  );
     582  if (rv != 0) {
     583    eno = EBUSY;
     584    goto cleanup;
     585  }
     586
     587  /* Get port number for data socket */
     588  size = rtems_ftpfs_create_address( &sa, INADDR_ANY, 0);
     589  rv = getsockname(
     590    port_socket,
     591    (struct sockaddr *) &sa,
     592    &size
     593  );
     594  if (rv != 0) {
     595    eno = ENOMEM;
     596    goto cleanup;
     597  }
     598  data_port = ntohs( sa.sin_port);
     599
     600  /* Send PORT command to set data connection port for server */
     601  snprintf(
     602    port_command,
     603    sizeof( port_command),
     604    "PORT %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu16 ",%" PRIu16,
     605    (client_address >> 24) & 0xff,
     606    (client_address >> 16) & 0xff,
     607    (client_address >> 8) & 0xff,
     608    (client_address >> 0) & 0xff,
     609    (data_port >> 8) & 0xff,
     610    (data_port >> 0) & 0xff
     611  );
     612  reply = rtems_ftpfs_send_command( e->ctrl_socket, port_command, NULL);
     613  if (reply != RTEMS_FTPFS_REPLY_2) {
     614    eno = ENOTSUP;
     615    goto cleanup;
     616  }
     617
     618  /* Listen on port socket for incoming data connections */
     619  rv = listen( port_socket, 1);
     620  if (rv != 0) {
     621    eno = EBUSY;
     622    goto cleanup;
     623  }
     624
     625  /* Send RETR or STOR command with filename */
     626  reply = rtems_ftpfs_send_command( e->ctrl_socket, file_command, filename);
     627  if (reply != RTEMS_FTPFS_REPLY_1) {
     628    eno = EIO;
     629    goto cleanup;
     630  }
     631
    107632  /*
    108    * Data transfer socket
     633   * Wait for connect on data connection.
     634   *
     635   * FIXME: This should become a select instead with a timeout.
    109636   */
    110   int port_socket;
    111   int data_socket;
    112   struct sockaddr_in    myDataAddress;
    113   struct sockaddr_in    farDataAddress;
     637  size = sizeof( sa);
     638  e->data_socket = accept(
     639    port_socket,
     640    (struct sockaddr *) &sa,
     641    &size
     642  );
     643  if (e->data_socket < 0) {
     644    eno = EIO;
     645    goto cleanup;
     646  }
     647
     648  /* FIXME: Check, that server data address is really from our server  */
     649
     650cleanup:
     651
     652  /* Close port socket if necessary */
     653  if (port_socket >= 0) {
     654    close( port_socket);
     655  }
     656
     657  return eno;
     658}
     659
     660typedef enum {
     661  RTEMS_FTPFS_PASV_START = 0,
     662  RTEMS_FTPFS_PASV_JUNK,
     663  RTEMS_FTPFS_PASV_DATA,
     664  RTEMS_FTPFS_PASV_DONE
     665} rtems_ftpfs_pasv_state;
     666
     667typedef struct {
     668  rtems_ftpfs_pasv_state state;
     669  uint8_t data [6];
     670  size_t index;
     671} rtems_ftpfs_pasv_entry;
     672
     673static void rtems_ftpfs_pasv_parser(
     674  const char* buf,
     675  size_t len,
     676  void *arg
     677)
     678{
     679  rtems_ftpfs_pasv_entry *e = (rtems_ftpfs_pasv_entry *) arg;
     680  size_t i = 0;
     681
     682  for (i = 0; i < len; ++i) {
     683    char c = buf [i];
     684
     685    switch (e->state) {
     686      case RTEMS_FTPFS_PASV_START:
     687        if (!isdigit( c)) {
     688          e->state = RTEMS_FTPFS_PASV_JUNK;
     689          e->index = 0;
     690        }
     691        break;
     692      case RTEMS_FTPFS_PASV_JUNK:
     693        if (isdigit( c)) {
     694          e->state = RTEMS_FTPFS_PASV_DATA;
     695          e->data [e->index] = (uint8_t) (c - '0');
     696        }
     697        break;
     698      case RTEMS_FTPFS_PASV_DATA:
     699        if (isdigit( c)) {
     700          e->data [e->index] = (uint8_t) (e->data [e->index] * 10 + c - '0');
     701        } else if (c == ',') {
     702          ++e->index;
     703          if (e->index < sizeof( e->data)) {
     704            e->data [e->index] = 0;
     705          } else {
     706            e->state = RTEMS_FTPFS_PASV_DONE;
     707          }
     708        } else {
     709          e->state = RTEMS_FTPFS_PASV_DONE;
     710        }
     711        break;
     712      default:
     713        return;
     714    }
     715  }
     716}
     717
     718static int rtems_ftpfs_open_data_connection_passive(
     719  rtems_ftpfs_entry *e,
     720  uint32_t client_address,
     721  const char *file_command,
     722  const char *filename
     723)
     724{
     725  int rv = 0;
     726  rtems_ftpfs_reply reply = RTEMS_FTPFS_REPLY_ERROR;
     727  struct sockaddr_in sa;
     728  socklen_t size = 0;
     729  uint32_t data_address = 0;
     730  uint16_t data_port = 0;
     731
     732  rtems_ftpfs_pasv_entry pe = {
     733    .state = RTEMS_FTPFS_PASV_START
     734  };
     735
     736  /* Send PASV command */
     737  reply = rtems_ftpfs_send_command_with_parser(
     738    e->ctrl_socket,
     739    "PASV",
     740    NULL,
     741    rtems_ftpfs_pasv_parser,
     742    &pe
     743  );
     744  if (reply != RTEMS_FTPFS_REPLY_2) {
     745    return ENOTSUP;
     746  }
     747  data_address = (uint32_t) ((pe.data [0] << 24) + (pe.data [1] << 16)
     748    + (pe.data [2] << 8) + pe.data [3]);
     749  data_port = (uint16_t) ((pe.data [4] << 8) + pe.data [5]);
     750  rtems_ftpfs_create_address( &sa, htonl( data_address), htons( data_port));
     751  DEBUG_PRINTF(
     752    "server data = %s:%u\n",
     753    inet_ntoa( sa.sin_addr),
     754    (unsigned) ntohs( sa.sin_port)
     755  );
     756
     757  /* Create data socket */
     758  e->data_socket = socket( AF_INET, SOCK_STREAM, 0);
     759  if (e->data_socket < 0) {
     760    return ENOMEM;
     761  }
     762
     763  /* Open data connection */
     764  rv = connect(
     765    e->data_socket,
     766    (struct sockaddr *) &sa,
     767    sizeof( sa)
     768  );
     769  if (rv != 0) {
     770    return EIO;
     771  }
     772
     773  /* Send RETR or STOR command with filename */
     774  reply = rtems_ftpfs_send_command( e->ctrl_socket, file_command, filename);
     775  if (reply != RTEMS_FTPFS_REPLY_1) {
     776    return EIO;
     777  }
     778
     779  return 0;
     780}
     781
     782static int rtems_ftpfs_open(
     783  rtems_libio_t *iop,
     784  const char *path,
     785  uint32_t flags,
     786  uint32_t mode
     787)
     788{
     789  int rv = 0;
     790  int eno = 0;
     791  bool ok = false;
     792  rtems_ftpfs_entry *e = NULL;
     793  const char *user = NULL;
     794  const char *password = NULL;
     795  const char *hostname = NULL;
     796  const char *filename = NULL;
     797  const char *file_command = (iop->flags & LIBIO_FLAGS_WRITE) != 0
     798    ? "STOR "
     799    : "RETR ";
     800  uint32_t client_address = 0;
     801  char *location = strdup( (const char *) iop->file_info);
     802
     803  /* Check allocation */
     804  if (location == NULL) {
     805    return ENOMEM;
     806  }
     807
     808  /* Check for either read-only or write-only flags */
     809  if (
     810    (iop->flags & LIBIO_FLAGS_WRITE) != 0
     811      && (iop->flags & LIBIO_FLAGS_READ) != 0
     812  ) {
     813    eno = ENOTSUP;
     814    goto cleanup;
     815  }
     816
     817  /* Split location into parts */
     818  ok = rtems_ftpfs_split_names(
     819      location,
     820      &user,
     821      &password,
     822      &hostname,
     823      &filename
     824  );
     825  if (!ok) {
     826    eno = ENOENT;
     827    goto cleanup;
     828  }
     829  DEBUG_PRINTF(
     830    "user = '%s', password = '%s', filename = '%s'\n",
     831    user,
     832    password,
     833    filename
     834  );
     835
     836  /* Allocate connection entry */
     837  e = malloc( sizeof( *e));
     838  if (e == NULL) {
     839    eno = ENOMEM;
     840    goto cleanup;
     841  }
     842
     843  /* Initialize connection entry */
     844  e->ctrl_socket = -1;
     845  e->data_socket = -1;
     846  e->eof = false;
     847
     848  /* Open control connection */
     849  eno = rtems_ftpfs_open_ctrl_connection(
     850    e,
     851    user,
     852    password,
     853    hostname,
     854    &client_address
     855  );
     856  if (eno != 0) {
     857    goto cleanup;
     858  }
     859
     860  /* Open passive data connection */
     861  eno = rtems_ftpfs_open_data_connection_passive(
     862    e,
     863    client_address,
     864    file_command,
     865    filename
     866  );
     867  if (eno == ENOTSUP) {
     868    /* Open active data connection */
     869    eno = rtems_ftpfs_open_data_connection_active(
     870      e,
     871      client_address,
     872      file_command,
     873      filename
     874    );
     875  }
     876
     877cleanup:
     878
     879  /* Free location parts buffer */
     880  free( location);
     881
     882  if (eno == 0) {
     883    /* Save connection state */
     884    iop->data1 = e;
     885  } else {
     886    /* Free all resources if an error occured */
     887    rtems_ftpfs_terminate( e, iop);
     888  }
     889
     890  return eno;
     891}
     892
     893static ssize_t rtems_ftpfs_read(
     894  rtems_libio_t *iop,
     895  void *buffer,
     896  size_t count
     897)
     898{
     899  rtems_ftpfs_entry *e = (rtems_ftpfs_entry *) iop->data1;
     900  char *in = (char *) buffer;
     901  size_t todo = count;
     902
     903  if (e->eof) {
     904    return 0;
     905  }
     906
     907  while (todo > 0) {
     908    ssize_t rv = recv( e->data_socket, in, todo, 0);
     909
     910    if (rv <= 0) {
     911      if (rv == 0) {
     912        rtems_ftpfs_reply reply =
     913          rtems_ftpfs_get_reply( e->ctrl_socket, NULL, NULL);
     914
     915        if (reply == RTEMS_FTPFS_REPLY_2) {
     916          e->eof = true;
     917          break;
     918        }
     919      }
     920
     921      rtems_set_errno_and_return_minus_one( EIO);
     922    }
     923
     924    in += rv;
     925    todo -= (size_t) rv;
     926  }
     927
     928  return (ssize_t) (count - todo);
     929}
     930
     931static ssize_t rtems_ftpfs_write(
     932  rtems_libio_t *iop,
     933  const void *buffer,
     934  size_t count
     935)
     936{
     937  rtems_ftpfs_entry *e = (rtems_ftpfs_entry *) iop->data1;
     938  const char *out = (const char *) buffer;
     939  size_t todo = count;
     940
     941  if (e->eof) {
     942    return 0;
     943  }
     944
     945  while (todo > 0) {
     946    ssize_t rv = send( e->data_socket, out, todo, 0);
     947
     948    if (rv <= 0) {
     949      if (rv == 0) {
     950        rtems_ftpfs_reply reply =
     951          rtems_ftpfs_get_reply( e->ctrl_socket, NULL, NULL);
     952
     953        if (reply == RTEMS_FTPFS_REPLY_2) {
     954          e->eof = true;
     955          break;
     956        }
     957      }
     958
     959      rtems_set_errno_and_return_minus_one( EIO);
     960    }
     961
     962    out += rv;
     963    todo -= (size_t) rv;
     964  }
     965
     966  return (ssize_t) (count - todo);
     967}
     968
     969static int rtems_ftpfs_close( rtems_libio_t *iop)
     970{
     971  rtems_ftpfs_entry *e = (rtems_ftpfs_entry *) iop->data1;
     972
     973  rtems_ftpfs_terminate( e, iop);
     974
     975  return 0;
     976}
     977
     978/* Dummy version to let fopen( *,"w") work properly */
     979static int rtems_ftpfs_ftruncate( rtems_libio_t *iop, off_t count)
     980{
     981  return 0;
     982}
     983
     984static int rtems_ftpfs_eval_path(
     985  const char *pathname,
     986  int flags,
     987  rtems_filesystem_location_info_t *pathloc
     988)
     989{
    114990  /*
    115    * other stuff to remember
     991   * The caller of this routine has striped off the mount prefix from the path.
     992   * We need to store this path here or otherwise we would have to do this job
     993   * again.  It is not possible to allocate resources here since there is no
     994   * way to free them later in every case.  The path is used in
     995   * rtems_ftpfs_open() via iop->file_info.
     996   *
     997   * FIXME: Avoid to discard the const qualifier.
    116998   */
    117   bool eof_reached;
     999  pathloc->node_access = (void *) pathname;
     1000
     1001  return 0;
     1002}
     1003
     1004static int rtems_ftpfs_eval_for_make(
     1005  const char *pathname,
     1006  rtems_filesystem_location_info_t *pathloc,
     1007  const char **name
     1008)
     1009{
     1010  rtems_set_errno_and_return_minus_one( EIO);
     1011}
     1012
     1013static rtems_filesystem_node_types_t rtems_ftpfs_node_type(
     1014  rtems_filesystem_location_info_t *pathloc
     1015)
     1016{
     1017  return RTEMS_FILESYSTEM_MEMORY_FILE;
     1018}
     1019
     1020static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers;
     1021
     1022static int rtems_ftpfs_mount_me(
     1023  rtems_filesystem_mount_table_entry_t *e
     1024)
     1025{
     1026  /* Set handler and oparations table */
     1027  e->mt_fs_root.handlers = &rtems_ftpfs_handlers;
     1028  e->mt_fs_root.ops = &rtems_ftpfs_ops;
     1029
     1030  /* We have no FTP file system specific data to maintain */
     1031  e->fs_info = NULL;
     1032
     1033  /* We maintain no real file system nodes, so there is no real root */
     1034  e->mt_fs_root.node_access = NULL;
     1035
     1036  /* Just use the limits from IMFS */
     1037  e->pathconf_limits_and_options = IMFS_LIMITS_AND_OPTIONS;
     1038
     1039  return 0;
     1040}
     1041
     1042/*
     1043 * The stat() support is intended only for the cp shell command.  Each request
     1044 * will return that we have a regular file with read, write and execute
     1045 * permissions for every one.  The node index uses a global counter to support
     1046 * a remote to remote copy.  Is not a very sophisticated method.
     1047 */
     1048static int rtems_ftpfs_fstat(
     1049  rtems_filesystem_location_info_t *loc,
     1050  struct stat *st
     1051)
     1052{
     1053  static unsigned ino = 0;
     1054
     1055  memset( st, 0, sizeof( *st));
     1056
     1057  /* FIXME */
     1058  st->st_ino = ++ino;
     1059
     1060  st->st_mode = S_IFREG | S_IRWXU | S_IRWXG | S_IRWXO;
     1061
     1062  return 0;
     1063}
     1064
     1065const rtems_filesystem_operations_table rtems_ftpfs_ops = {
     1066  .evalpath_h = rtems_ftpfs_eval_path,
     1067  .evalformake_h = rtems_ftpfs_eval_for_make,
     1068  .link_h = NULL,
     1069  .unlink_h = NULL,
     1070  .node_type_h = rtems_ftpfs_node_type,
     1071  .mknod_h = NULL,
     1072  .chown_h = NULL,
     1073  .freenod_h = NULL,
     1074  .mount_h = NULL,
     1075  .fsmount_me_h = rtems_ftpfs_mount_me,
     1076  .unmount_h = NULL,
     1077  .fsunmount_me_h = NULL,
     1078  .utime_h = NULL,
     1079  .eval_link_h = NULL,
     1080  .symlink_h = NULL,
     1081  .readlink_h = NULL
    1181082};
    1191083
    120 /*
    121  * Number of streams open at the same time
    122  */
    123 static rtems_id ftp_mutex;
    124 static int nStreams;
    125 static struct ftpStream ** volatile ftpStreams;
    126 
    127 extern rtems_filesystem_operations_table  rtems_tftp_ops;
    128 extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;
    129 
    130 /*
    131  *  Direct copy from the IMFS/TFTP.  Look at this.
    132  */
    133 
    134 rtems_filesystem_limits_and_options_t rtems_ftp_limits_and_options = {
    135    5,   /* link_max */
    136    6,   /* max_canon */
    137    7,   /* max_input */
    138    255, /* name_max */
    139    255, /* path_max */
    140    2,   /* pipe_buf */
    141    1,   /* posix_async_io */
    142    2,   /* posix_chown_restrictions */
    143    3,   /* posix_no_trunc */
    144    4,   /* posix_prio_io */
    145    5,   /* posix_sync_io */
    146    6    /* posix_vdisable */
     1084static const rtems_filesystem_file_handlers_r rtems_ftpfs_handlers = {
     1085  .open_h = rtems_ftpfs_open,
     1086  .close_h = rtems_ftpfs_close,
     1087  .read_h = rtems_ftpfs_read,
     1088  .write_h = rtems_ftpfs_write,
     1089  .ioctl_h = NULL,
     1090  .lseek_h = NULL,
     1091  .fstat_h = rtems_ftpfs_fstat,
     1092  .fchmod_h = NULL,
     1093  .ftruncate_h = rtems_ftpfs_ftruncate,
     1094  .fpathconf_h = NULL,
     1095  .fsync_h = NULL,
     1096  .fdatasync_h = NULL,
     1097  .fcntl_h = NULL,
     1098  .rmnod_h = NULL
    1471099};
    148 
    149 int rtems_ftp_mount_me(
    150   rtems_filesystem_mount_table_entry_t *temp_mt_entry
    151 )
    152 {
    153   rtems_status_code  sc;
    154 
    155   temp_mt_entry->mt_fs_root.handlers = &rtems_ftp_handlers;
    156   temp_mt_entry->mt_fs_root.ops      = &rtems_ftp_ops;
    157 
    158   /*
    159    *   We have no ftp filesystem specific data to maintain.  This
    160    *   filesystem may only be mounted ONCE.
    161    *
    162    *   And we maintain no real filesystem nodes, so there is no real root.
    163    */
    164 
    165   temp_mt_entry->fs_info                = NULL;
    166   temp_mt_entry->mt_fs_root.node_access = NULL;
    167 
    168   /*
    169    *  These need to be looked at for full POSIX semantics.
    170    */
    171 
    172   temp_mt_entry->pathconf_limits_and_options = rtems_ftp_limits_and_options;
    173 
    174 
    175   /*
    176    *  Now allocate a semaphore for mutual exclusion.
    177    *
    178    *  NOTE:  This could be in an fsinfo for this filesystem type.
    179    */
    180  
    181   sc = rtems_semaphore_create (rtems_build_name('F','T','P',' '),
    182                                1,
    183                                RTEMS_FIFO |
    184                                RTEMS_BINARY_SEMAPHORE |
    185                                RTEMS_NO_INHERIT_PRIORITY |
    186                                RTEMS_NO_PRIORITY_CEILING |
    187                                RTEMS_LOCAL,
    188                                0,
    189                                &ftp_mutex);
    190 
    191   if (sc != RTEMS_SUCCESSFUL)
    192     set_errno_and_return_minus_one( ENOMEM );
    193 
    194   return 0;
    195 }
    196 
    197 /*
    198  * Initialize the FTP driver
    199  */
    200 
    201 int rtems_bsdnet_initialize_ftp_filesystem (void)
    202 {
    203  int                                   status;
    204  rtems_filesystem_mount_table_entry_t *entry;
    205 
    206  status = mkdir( FTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO );
    207  if ( status == -1 )
    208    return status;
    209 
    210   status = mount(
    211      &entry,
    212      &rtems_ftp_ops,
    213      RTEMS_FILESYSTEM_READ_WRITE,
    214      NULL,
    215      FTP_PATHNAME_PREFIX
    216   );
    217 
    218   if ( status )
    219     perror( "FTP mount failed" );
    220 
    221   return status;
    222 }
    223 
    224 /*
    225  * read and return message code from ftp control connection
    226  */
    227 int rtems_ftp_get_message
    228 (
    229   const struct ftpStream *fsp,  /* ptr to ftp control structure */
    230   int *msg_code                 /* ptr to return message code   */
    231 )
    232 {
    233   char rd_buffer[4];
    234   size_t rd_size;
    235   ssize_t tmp_size;
    236   int eno = 0;
    237   bool finished = false;
    238   do {
    239     /*
    240      * fetch (at least) 4 characters from control connection
    241      * FIXME: how about a timeout?
    242      */   
    243     rd_size = 0;
    244     while ((eno == 0) &&
    245            (rd_size < sizeof(rd_buffer))) {
    246       tmp_size = read(fsp->ctrl_socket,
    247                       (&rd_buffer)+rd_size,
    248                       sizeof(rd_buffer)-rd_size);
    249       if (tmp_size < 0) {
    250         eno = EIO;
    251       }
    252       else {
    253 #ifdef DEBUG_OUT
    254         write(1,(&rd_buffer)+rd_size,tmp_size);
    255 #endif
    256         rd_size += tmp_size;
    257       }
    258     }
    259     /*
    260      * check for 3 digits and space, otherwise not finished
    261      */   
    262     if ((eno == 0) &&
    263         (isdigit((unsigned int)rd_buffer[0])) &&
    264         (isdigit((unsigned int)rd_buffer[1])) &&
    265         (isdigit((unsigned int)rd_buffer[2])) &&
    266         (rd_buffer[3] == ' ')) {
    267       finished = true;
    268       rd_buffer[3] = '\0';
    269       *msg_code = atol(rd_buffer);
    270     }
    271     /*
    272      * skip rest until end-of-line
    273      */
    274     do {
    275       tmp_size = read(fsp->ctrl_socket,
    276                       &rd_buffer,
    277                       1);
    278       if (tmp_size < 0) {
    279         eno = EIO;
    280       }
    281 #ifdef DEBUG_OUT
    282       else {
    283         write(1,(&rd_buffer),tmp_size);
    284       }
    285 #endif
    286     } while ((eno == 0) &&
    287              (rd_buffer[0] != '\n'));
    288   } while ((eno == 0) && !finished);
    289   return eno;
    290 }
    291 
    292 /*
    293  * split a pseudo file name into host, user, password, filename
    294  * NOTE: this function will allocate space for these strings,
    295  * the calling function should free the space, when no longer needed
    296  * exception: when we return any error, we will also cleanup
    297  * the strings
    298  * valid forms:
    299  * /FTP/user:pass/filepath
    300  * /FTP/user:pass@hostname/filepath
    301 
    302  * /FTP/user:pass/filepath
    303  * /FTP/user:pass/@hostname/filepath
    304  * NOTE: /FTP is already stripped from the name
    305  */
    306 int rtems_ftp_split_names
    307 ( const char *pathname,         /* total path name (including prefix)     */
    308   char **usernamep,             /* ptr to ptr to user name                */
    309   char **passwordp,             /* ptr to ptr to password                 */
    310   char **hostnamep,             /* ptr to ptr to host name                */
    311   char **filenamep)             /* ptr to ptr to hostremaining file name  */
    312 {
    313   const char  *chunk_start;
    314   const char  *chunk_end;
    315   size_t chunk_len;
    316   int rc = 0;
    317 
    318   /*
    319    * ensure, that result pointers are NULL...
    320    */
    321   *usernamep = NULL;
    322   *passwordp = NULL;
    323   *hostnamep = NULL;
    324   *filenamep = NULL;
    325 
    326 #if 1
    327   chunk_start = pathname;
    328 #else /* no longer needed with IMFS */
    329   /*
    330    * check, that total path is long enough, skip prefix
    331    */
    332   if (rc == 0) {
    333     if (strlen (pathname) <= strlen (FTP_PATHNAME_PREFIX)) {
    334       rc = ENOENT;
    335     }
    336     else {
    337       chunk_start = pathname + strlen (FTP_PATHNAME_PREFIX);
    338     }
    339   }
    340 #endif
    341   /*
    342    * fetch user name: terminated with ":"
    343    */
    344   if (rc == 0) {
    345     chunk_end = strchr(chunk_start,':');
    346     if ((chunk_end == NULL) ||         /* No ':' found or                  */
    347         (chunk_end == chunk_start)) {  /* ':' is first character-> no name */
    348       rc = ENOENT;
    349     }
    350     else {
    351       chunk_len = chunk_end-chunk_start;
    352       *usernamep = malloc(chunk_len+1);
    353       if (*usernamep == NULL) {
    354         rc = ENOMEM;
    355       }
    356       else {
    357         memcpy(*usernamep,chunk_start,chunk_len);
    358         (*usernamep)[chunk_len] = '\0';
    359       }
    360     }
    361   }
    362   /*
    363    * fetch password: terminated with "/" or "@"
    364    */
    365   if (rc == 0) {
    366     chunk_start = chunk_end + 1; /* skip ":" after user name */
    367     chunk_end = strchr(chunk_start,'/');
    368     if ((chunk_end == NULL) ||         /* No '/' found or                  */
    369         (chunk_end == chunk_start)) {  /* '/' is first character-> no pwd  */
    370       rc = ENOENT;
    371     }
    372     else {
    373       /*
    374        * we have found a proper '/'
    375        * this is the end of the password
    376        */
    377       chunk_len = chunk_end-chunk_start;
    378       *passwordp = malloc(chunk_len+1);
    379       if (*passwordp == NULL) {
    380         rc = ENOMEM;
    381       }
    382       else {
    383         memcpy(*passwordp,chunk_start,chunk_len);
    384         (*passwordp)[chunk_len] = '\0';
    385       }
    386     }
    387   }
    388   /*
    389    * if first char after '/' is '@', then this is the hostname
    390    * fetch hostname terminated with "/"
    391    * if exists at all. otherwise take default server from bootp
    392    */
    393   if (rc == 0) {
    394     chunk_start = chunk_end+1;
    395     if (*chunk_start == '@') {
    396       /*
    397        * hostname follows
    398        */
    399       chunk_start = chunk_start + 1; /* skip "@" after password */
    400       chunk_end = strchr(chunk_start,'/');
    401       if ((chunk_end == NULL) ||         /* No '/' found or                  */
    402           (chunk_end == chunk_start)) {  /* '/' is first character-> no host */
    403         rc = ENOENT;
    404       }
    405       else {
    406         /*
    407          * we have found a proper '/'
    408          */
    409         chunk_len = chunk_end-chunk_start;
    410         *hostnamep = malloc(chunk_len+1);
    411         if (*hostnamep == NULL) {
    412           rc = ENOMEM;
    413         }
    414         else {
    415           memcpy(*hostnamep,chunk_start,chunk_len);
    416           (*hostnamep)[chunk_len] = '\0';
    417         }
    418       }
    419     }
    420     else { /* chunk_start != '@' */
    421       /*
    422        * no host name given, keep string empty
    423        */
    424       *hostnamep = malloc(1);
    425       if (*hostnamep == NULL) {
    426         rc = ENOMEM;
    427       }
    428       else {
    429         (*hostnamep)[0] = '\0';
    430       }
    431     }     
    432   }
    433   /*
    434    * fetch filename. This is all the rest...
    435    */
    436   if (rc == 0) {
    437     chunk_start = chunk_end+1;
    438     if (*chunk_start == '\0') {  /* nothing left for filename */
    439       rc = ENOENT;
    440     }
    441     else {
    442       chunk_len = strlen(chunk_start);
    443       *filenamep = malloc(chunk_len+1);
    444       if (*filenamep == NULL) {
    445         rc = ENOMEM;
    446       }
    447       else {
    448         memcpy(*filenamep,chunk_start,chunk_len);
    449         (*filenamep)[chunk_len] = '\0';
    450       }
    451     }
    452   }
    453  
    454   /*
    455    * cleanup anything, if error occured
    456    */
    457   if (rc != 0) {
    458     if (*hostnamep != NULL) {
    459       free(*hostnamep);
    460       *hostnamep = NULL;
    461     }
    462     if (*usernamep != NULL) {
    463       free(*usernamep);
    464       *usernamep = NULL;
    465     }
    466     if (*passwordp != NULL) {
    467       free(*passwordp);
    468       *passwordp = NULL;
    469     }
    470     if (*filenamep != NULL) {
    471       free(*filenamep);
    472       *filenamep = NULL;
    473     }
    474   }
    475   return rc;
    476 }
    477                                        
    478 int rtems_ftp_evaluate_for_make(
    479    const char                         *path,       /* IN     */
    480    rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */
    481    const char                        **name        /* OUT    */
    482 )
    483 
    484   set_errno_and_return_minus_one( EIO );   
    485 }
    486 
    487 /*
    488  * XXX - Fix return values.
    489  */
    490 
    491 int rtems_ftp_eval_path( 
    492   const char                        *pathname,     /* IN     */
    493   int                                flags,        /* IN     */
    494   rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */
    495 )
    496 {
    497 
    498   /*
    499    * Read-only for now
    500    */
    501    
    502   if ( ((flags & O_RDONLY) != O_RDONLY ) &&
    503        ((flags & O_WRONLY) != O_WRONLY )) {
    504     set_errno_and_return_minus_one( ENOENT );
    505   }
    506   /*
    507    * The File system is mounted at FTP_PATHNAME_PREFIX
    508    * the caller of this routine has striped off this part of the
    509    * name. Save the remainder of the name for use by the open routine.
    510    */
    511 
    512   pathloc->node_access = (void * ) pathname;
    513   pathloc->handlers    = &rtems_ftp_handlers;
    514 
    515   return 0;
    516 }
    517 
    518 /*
    519  * Open a FTP stream
    520  */
    521 int rtems_ftp_open(
    522   rtems_libio_t *iop,
    523   const char    *new_name,
    524   uint32_t       flag,
    525   uint32_t       mode
    526 )
    527 {
    528   int s = 0;
    529   char *filename  = NULL;
    530   char *uname     = NULL;
    531   char *upass     = NULL;
    532   char *hostname  = NULL;
    533   char port_buffer[sizeof(FTP_PORT_CMD)+6*4+1+1];
    534   uint32_t   my_ip;
    535   uint16_t   my_port;
    536   int eno = 0;
    537   rtems_status_code rc;
    538   bool is_write = false;
    539   bool sema_obtained = false;
    540   struct ftpStream *fsp = NULL;
    541   int msg_tmp = 0;
    542   socklen_t sockaddr_size;
    543   /*
    544    * check for R/O or W/O flags
    545    */
    546   if (eno == 0) {
    547     if ((0 != (iop->flags & LIBIO_FLAGS_WRITE)) &&
    548         (0 != (iop->flags & LIBIO_FLAGS_READ))) {
    549       eno = ENOTSUP;
    550     }
    551     else {
    552       is_write = (0 != (iop->flags & LIBIO_FLAGS_WRITE));
    553     }
    554   }
    555   /*
    556    * split pathname into parts
    557    */
    558   if (eno == 0) {
    559     eno = rtems_ftp_split_names(iop->file_info,
    560                                 &uname,
    561                                 &upass,
    562                                 &hostname,
    563                                 &filename);
    564   }
    565  
    566   /*
    567    * Find a free stream
    568    */
    569   if (eno == 0) {
    570     rc = rtems_semaphore_obtain (ftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    571     if (rc == RTEMS_SUCCESSFUL) {
    572       sema_obtained = true;
    573     }
    574     else {
    575       eno = EBUSY;
    576     }
    577   }
    578   if (eno == 0) {
    579     for (s = 0 ; s < nStreams ; s++) {
    580       if (ftpStreams[s] == NULL)
    581         break;
    582     }
    583     if (s == nStreams) {
    584       /*
    585        * Reallocate stream pointers
    586        * Guard against the case where realloc() returns NULL.
    587        */
    588       struct ftpStream **np;
    589      
    590       np = realloc (ftpStreams, ++nStreams * sizeof *ftpStreams);
    591       if (np == NULL) {
    592         eno = ENOMEM;
    593       }
    594       else {
    595         ftpStreams = np;
    596       }
    597     }
    598   }
    599   if (eno == 0) {
    600     fsp = ftpStreams[s] = malloc (sizeof (struct ftpStream));
    601     rtems_semaphore_release (ftp_mutex);
    602     sema_obtained = false;
    603     if (fsp == NULL) {
    604       eno = ENOMEM;
    605     }
    606     else {
    607       iop->data0 = s;
    608       iop->data1 = fsp;
    609       fsp->ctrl_socket = -1; /* mark, that sockets not yet created */
    610       fsp->port_socket = -1;
    611       fsp->data_socket = -1;
    612       fsp->eof_reached = false;
    613     }
    614   }
    615   if (eno == 0) { 
    616   /*
    617    * Create the socket for control connection
    618    */
    619     if ((fsp->ctrl_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
    620       eno = ENOMEM;
    621     }
    622   }
    623 
    624   if (eno == 0) {
    625     /*
    626      * Set the destination to the FTP server
    627      * port on the remote machine.
    628      */
    629     memset(&(fsp->farCtrlAddress),sizeof(fsp->farCtrlAddress),0);
    630     fsp->farCtrlAddress.sin_family = AF_INET;
    631     if (*hostname == '\0') {
    632       fsp->farCtrlAddress.sin_addr.s_addr = rtems_bsdnet_bootp_server_address.s_addr;
    633     }
    634     else if (1 != inet_aton(hostname,&(fsp->farCtrlAddress.sin_addr))) {
    635       struct hostent *hent;
    636      
    637       hent = gethostbyname(hostname);
    638       if (hent != NULL) {
    639         memcpy(&fsp->farCtrlAddress.sin_addr,
    640               hent->h_addr,
    641               sizeof(fsp->farCtrlAddress.sin_addr));
    642       }
    643       else {
    644         eno = ENOENT;
    645       }
    646     }
    647     if (eno == 0) {
    648       fsp->farCtrlAddress.sin_port = htons (FTP_PORT_NUM); 
    649       fsp->farCtrlAddress.sin_len  = sizeof(fsp->farCtrlAddress);   
    650       if (0 > connect(fsp->ctrl_socket,
    651                       (struct sockaddr *)&(fsp->farCtrlAddress),
    652                       sizeof(fsp->farCtrlAddress))) {
    653         eno = ENOENT;
    654       }
    655     }
    656     if (eno == 0) {
    657       /*
    658        * fetch IP address of interface used
    659        */
    660       memset(&(fsp->myCtrlAddress),sizeof(fsp->myCtrlAddress),0);
    661       fsp->myCtrlAddress.sin_family = AF_INET;
    662       fsp->myCtrlAddress.sin_addr.s_addr = INADDR_ANY;
    663       fsp->myCtrlAddress.sin_port   = 0;
    664       fsp->myCtrlAddress.sin_len  = sizeof(fsp->myDataAddress);
    665       sockaddr_size = sizeof(fsp->myCtrlAddress);
    666       if (0 > getsockname(fsp->ctrl_socket,
    667                           (struct sockaddr *)&(fsp->myCtrlAddress),
    668                           &sockaddr_size)) {
    669         eno = ENOMEM;
    670       }
    671     }
    672   }
    673   if (eno == 0) {
    674     /*
    675      * now we should get a connect message from the FTP server
    676      */
    677     eno = rtems_ftp_get_message(fsp,&msg_tmp);
    678     if ((eno == 0) &&
    679         (msg_tmp != FTP_REPLY_CONNECT)) {
    680       eno = ENOENT;
    681     }
    682   }
    683   if (eno == 0) {
    684     /*
    685      * send user ID to server
    686      * NOTE: the following lines will be executed in order
    687      * and will be aborted whenever an error occures... (see your ANSI C book)
    688      */
    689     if ((0 > send(fsp->ctrl_socket,FTP_USER_CMD,strlen(FTP_USER_CMD),0)) ||
    690         (0 > send(fsp->ctrl_socket,uname,       strlen(uname),       0)) ||
    691         (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
    692       eno = EIO;
    693     }
    694   }
    695   if (eno == 0) {
    696     /*
    697      * now we should get a request for the password or a login...
    698      */
    699     eno = rtems_ftp_get_message(fsp,&msg_tmp);
    700     if (eno == 0) {
    701       if (msg_tmp == FTP_REPLY_PASSREQ) {
    702         /*
    703          * send password to server
    704          */
    705 #ifdef DEBUG_OUT
    706         write(1,FTP_PASS_CMD,strlen(FTP_PASS_CMD));
    707         write(1,upass,       strlen(upass)       );
    708         write(1,"\n",        1                   );
    709 #endif   
    710         if ((0 > send(fsp->ctrl_socket,FTP_PASS_CMD,strlen(FTP_PASS_CMD),0)) ||
    711             (0 > send(fsp->ctrl_socket,upass,       strlen(upass),       0)) ||
    712             (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
    713           eno = EIO;
    714         }
    715         /*
    716          * at least now a login reply should come up...
    717          * this is checked some lines downwards the code
    718          */
    719         if (eno == 0) {
    720           eno = rtems_ftp_get_message(fsp,&msg_tmp);
    721         }
    722       }
    723     }
    724   }
    725   if (eno == 0) {
    726     /*
    727      * check for a login reply. this should be present now...
    728      */
    729     if (msg_tmp != FTP_REPLY_LOGIN) {
    730       eno = EACCES; /* pseudo for wrong user/pass */
    731     }
    732   }
    733   if (eno == 0) {
    734     /*
    735      * set binary mode for all transfers
    736      */
    737 #ifdef DEBUG_OUT
    738     write(1,FTP_BINARY_CMD,strlen(FTP_BINARY_CMD));
    739     write(1,"\n",        1                   );
    740 #endif   
    741     if ((0 > send(fsp->ctrl_socket,FTP_BINARY_CMD,strlen(FTP_BINARY_CMD),0)) ||
    742         (0 > send(fsp->ctrl_socket,"\n",          1,                     0))) {
    743       eno = EIO;
    744     }
    745     else {
    746       eno = rtems_ftp_get_message(fsp,&msg_tmp);
    747     }
    748   }
    749   if (eno == 0) {
    750     /*
    751      * check for a "BINARY TYPE command successful" reply
    752      */
    753     if (msg_tmp != FTP_REPLY_SUCCESS) {
    754       eno = EIO;
    755     }
    756   }
    757   if (eno == 0) {
    758     /*
    759      * create and bind socket for data connection
    760      */
    761     if ((fsp->port_socket = socket (AF_INET, SOCK_STREAM, 0)) < 0) {
    762       eno = ENOMEM;
    763     }
    764     else {
    765       memset(&(fsp->myDataAddress),sizeof(fsp->myDataAddress),0);
    766       fsp->myDataAddress.sin_family = AF_INET;
    767       fsp->myDataAddress.sin_addr.s_addr = INADDR_ANY;
    768       fsp->myDataAddress.sin_port   = 0; /* unique port will be assigned */
    769       fsp->myDataAddress.sin_len  = sizeof(fsp->myDataAddress);
    770       if (0 > bind(fsp->port_socket,
    771                    (struct sockaddr *)&(fsp->myDataAddress),
    772                    sizeof(fsp->myDataAddress))) {
    773         eno = EBUSY;
    774       }
    775       else {
    776         /*
    777          * fetch port number of data socket
    778          */
    779         memset(&(fsp->myDataAddress),sizeof(fsp->myDataAddress),0);
    780         fsp->myDataAddress.sin_family = AF_INET;
    781         fsp->myDataAddress.sin_addr.s_addr = INADDR_ANY;
    782         fsp->myDataAddress.sin_port   = 0;
    783         fsp->myDataAddress.sin_len  = sizeof(fsp->myDataAddress);
    784         sockaddr_size = sizeof(fsp->myDataAddress);
    785         if (0 > getsockname(fsp->port_socket,
    786                             (struct sockaddr *)&(fsp->myDataAddress),
    787                             &sockaddr_size)) {
    788           eno = ENOMEM;
    789         }
    790       }
    791     }
    792   }
    793   if (eno == 0) {
    794     /*
    795      * propagate data connection port to server
    796      */
    797     my_ip   = ntohl(fsp->myCtrlAddress.sin_addr.s_addr);
    798     my_port = ntohs(fsp->myDataAddress.sin_port);
    799     sprintf(port_buffer,"%s%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu16 ",%" PRIu16 "\n",
    800             FTP_PORT_CMD,
    801             (my_ip >> 24) & 0x00ff,
    802             (my_ip >> 16) & 0x00ff,
    803             (my_ip >>  8) & 0x00ff,
    804             (my_ip >>  0) & 0x00ff,
    805             (my_port>> 8) & 0x00ff,
    806             (my_port>> 0) & 0x00ff);
    807 #ifdef DEBUG_OUT
    808     write(1,port_buffer,strlen(port_buffer));
    809 #endif
    810     if (0 > send(fsp->ctrl_socket,port_buffer,strlen(port_buffer),0)) {
    811       eno = EIO;
    812     }   
    813     else {
    814       eno = rtems_ftp_get_message(fsp,&msg_tmp);
    815     }
    816   }
    817   if (eno == 0) {
    818     /*
    819      * check for a "PORT command successful" reply
    820      */
    821     if (msg_tmp != FTP_REPLY_SUCCESS) {
    822       eno = EBUSY;
    823     }
    824   }
    825   /*
    826    * prepare port socket to listen for incoming connections
    827    */
    828   if (eno == 0) {
    829     if (0 > listen(fsp->port_socket,1)) {
    830       eno = EBUSY;
    831     }
    832   }
    833   if (eno == 0) {
    834     /*
    835      * send retrive/store command with filename
    836      */
    837     if (is_write) {
    838 #ifdef DEBUG_OUT
    839     write(1,FTP_STOR_CMD,strlen(FTP_STOR_CMD));
    840     write(1,filename    ,strlen(filename)    );
    841     write(1,"\n",1);
    842 #endif
    843       if ((0 > send(fsp->ctrl_socket,FTP_STOR_CMD,strlen(FTP_STOR_CMD),0)) ||
    844           (0 > send(fsp->ctrl_socket,filename,    strlen(filename),    0)) ||
    845           (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
    846         eno = EIO;
    847       }
    848     }
    849     else {
    850 #ifdef DEBUG_OUT
    851     write(1,FTP_RETR_CMD,strlen(FTP_RETR_CMD));
    852     write(1,filename    ,strlen(filename)    );
    853     write(1,"\n",1);
    854 #endif
    855       if ((0 > send(fsp->ctrl_socket,FTP_RETR_CMD,strlen(FTP_RETR_CMD),0)) ||
    856           (0 > send(fsp->ctrl_socket,filename,    strlen(filename),    0)) ||
    857           (0 > send(fsp->ctrl_socket,"\n",        1,                   0))) {
    858         eno = EIO;
    859       }
    860     }     
    861   }
    862 #if 1
    863   if (eno == 0) {
    864     eno = rtems_ftp_get_message(fsp,&msg_tmp);
    865   }
    866   if (eno == 0) {
    867     /*
    868      * check for a "OPENING binary connection" reply
    869      */
    870     if (msg_tmp != FTP_REPLY_OPENCONN) {
    871       eno = EACCES;
    872     }
    873   }
    874 #endif
    875   /*
    876    * wait for connect on data connection
    877    * FIXME: this should become a select instead with a timeout
    878    */
    879   if (eno == 0) {
    880     sockaddr_size = sizeof(fsp->farDataAddress);
    881     fsp->data_socket = accept(fsp->port_socket,
    882                               (struct sockaddr *)&(fsp->farDataAddress),
    883                               &sockaddr_size);
    884     if (0 > fsp->data_socket) {
    885       eno = EIO;
    886     }
    887   }
    888   /*
    889    * FIXME: check, that fardataAddr is really from our ftp server
    890    */
    891  
    892   /*
    893    * clean up temp strings...
    894    */
    895   if (uname != NULL) {
    896     free(uname);
    897     uname = NULL;
    898   }
    899   if (upass != NULL) {
    900     free(upass);
    901     upass = NULL;
    902   }
    903   if (hostname != NULL) {
    904     free(hostname);
    905     hostname = NULL;
    906   }
    907   if (filename != NULL) {
    908     free(filename);
    909     filename = NULL;
    910   }
    911   /*
    912    * close part socket, no longer needed
    913    */
    914   if (fsp->port_socket != -1) {
    915     close(fsp->port_socket);
    916     fsp->port_socket = -1;
    917   }
    918   /*
    919    * if error, clean up everything
    920    */
    921   if (eno != 0) {
    922     if (fsp != NULL) {
    923       /*
    924        * check and close ctrl/data connection
    925        */
    926       if (fsp->data_socket != -1) {
    927         close(fsp->data_socket);
    928         fsp->data_socket = -1;
    929       }
    930       if (fsp->ctrl_socket != -1) {
    931         close(fsp->ctrl_socket);
    932         fsp->ctrl_socket = -1;
    933       }
    934       /*
    935        * free ftpStream structure
    936        */
    937       ftpStreams[s] = NULL;
    938       free(fsp);
    939       fsp = NULL;
    940     }
    941   }
    942   /*
    943    * return sema, if still occupied
    944    */
    945   if (sema_obtained) {
    946     rtems_semaphore_release (ftp_mutex);
    947     sema_obtained = false;
    948   }
    949 #if 0
    950   if (eno != 0) {
    951     set_errno_and_return_minus_one(eno);
    952   }
    953   return 0;
    954 #else
    955   return eno;
    956 #endif
    957 }
    958 
    959 /*
    960  * Read from a FTP stream
    961  */
    962 ssize_t rtems_ftp_read(
    963   rtems_libio_t *iop,
    964   void          *buffer,
    965   size_t         count
    966 )
    967 {
    968   int eno = 0;
    969   struct ftpStream *fsp;
    970   size_t want_cnt;
    971   ssize_t rd_cnt;
    972   int msg_tmp = 0;
    973 
    974   fsp = iop->data1;
    975   want_cnt = count;
    976   /*
    977    * check, that data connection present
    978    */
    979   if (eno == 0) {
    980     if ((fsp == NULL) ||
    981         (fsp->data_socket < 0)) {
    982       eno = EBADF;
    983     }
    984   } 
    985    
    986   /*
    987    * perform read from data socket
    988    * read multiple junks, if smaller than wanted
    989    */
    990   while ((eno == 0) &&
    991          (want_cnt > 0) &&
    992          !(fsp->eof_reached) ) {
    993     rd_cnt = read(fsp->data_socket,buffer,want_cnt);
    994     if (rd_cnt > 0) {
    995       buffer += rd_cnt;
    996       want_cnt -= rd_cnt;
    997     }
    998     else {
    999       eno = rtems_ftp_get_message(fsp,&msg_tmp);
    1000       fsp->eof_reached = true;
    1001       if ((eno == 0) &&
    1002           (msg_tmp != FTP_REPLY_TFERCMPL)) {
    1003         eno = EIO;
    1004       }
    1005       if (rd_cnt < 0) {
    1006         eno = EIO;
    1007       }
    1008     }
    1009   }
    1010   if (eno != 0) {
    1011     set_errno_and_return_minus_one(eno);
    1012   }
    1013   return count - want_cnt;
    1014 }
    1015 
    1016 ssize_t rtems_ftp_write(
    1017   rtems_libio_t *iop,
    1018   const void    *buffer,
    1019   size_t         count
    1020 )
    1021 {
    1022   int eno = 0;
    1023   struct ftpStream *fsp;
    1024   size_t want_cnt;
    1025   ssize_t wr_cnt;
    1026   int msg_tmp = 0;
    1027 
    1028   fsp = iop->data1;
    1029   want_cnt = count;
    1030   /*
    1031    * check, that data connection present
    1032    */
    1033   if (eno == 0) {
    1034     if ((fsp == NULL) ||
    1035         (fsp->data_socket < 0)) {
    1036       eno = EBADF;
    1037     }
    1038   } 
    1039    
    1040   /*
    1041    * perform write to data socket
    1042    */
    1043   if (eno == 0) {
    1044     wr_cnt = write(fsp->data_socket,buffer,want_cnt);
    1045     if (wr_cnt > 0) {
    1046       buffer += wr_cnt;
    1047       want_cnt -= wr_cnt;
    1048     }
    1049     else {
    1050       eno = rtems_ftp_get_message(fsp,&msg_tmp);
    1051       if ((eno == 0) &&
    1052           (msg_tmp != FTP_REPLY_TFERCMPL)) {
    1053         eno = EIO;
    1054       }
    1055       if (wr_cnt < 0) {
    1056         eno = EIO;
    1057       }
    1058     }
    1059   }
    1060   if (eno != 0) {
    1061     set_errno_and_return_minus_one(eno);
    1062   }
    1063   return count - want_cnt;
    1064 }
    1065 
    1066 /*
    1067  * Close a FTP stream
    1068  */
    1069 int rtems_ftp_close(
    1070   rtems_libio_t *iop
    1071 )
    1072 {
    1073   int s = iop->data0;
    1074   struct ftpStream *fsp = iop->data1;
    1075 
    1076   /*
    1077    * close ctrl/data connection, if needed
    1078    */
    1079   if (fsp->data_socket >= 0) {
    1080     close(fsp->data_socket);
    1081     fsp->data_socket = -1;
    1082   }
    1083   if (fsp->ctrl_socket >= 0) {
    1084     close(fsp->ctrl_socket);
    1085     fsp->ctrl_socket = -1;
    1086   }
    1087   /*
    1088    * free any used space...
    1089    */
    1090   rtems_semaphore_obtain (ftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
    1091   free (ftpStreams[s]);
    1092   ftpStreams[s] = NULL;
    1093   rtems_semaphore_release (ftp_mutex);
    1094 
    1095   return 0;
    1096 }
    1097 
    1098 rtems_device_driver rtems_ftp_control(
    1099   rtems_device_major_number major,
    1100   rtems_device_minor_number minor,
    1101   void *pargp
    1102 )
    1103 {
    1104   return RTEMS_NOT_CONFIGURED;
    1105 }
    1106 
    1107 /*
    1108  * Dummy version to let fopen(xxxx,"w") work properly.
    1109  */
    1110 static int rtems_ftp_ftruncate(
    1111     rtems_libio_t   *iop,
    1112     off_t           count
    1113 )
    1114 {
    1115     return 0;
    1116 }
    1117 
    1118 rtems_filesystem_node_types_t rtems_ftp_node_type(
    1119      rtems_filesystem_location_info_t        *pathloc                 /* IN */
    1120 )
    1121 {
    1122     return RTEMS_FILESYSTEM_MEMORY_FILE;
    1123 }
    1124 
    1125 rtems_filesystem_operations_table  rtems_ftp_ops = {
    1126     rtems_ftp_eval_path,             /* eval_path */
    1127     rtems_ftp_evaluate_for_make,     /* evaluate_for_make */
    1128     NULL,                            /* link */
    1129     NULL,                            /* unlink */
    1130     rtems_ftp_node_type,             /* node_type */
    1131     NULL,                            /* mknod */
    1132     NULL,                            /* chown */
    1133     NULL,                            /* freenodinfo */
    1134     NULL,                            /* mount */
    1135     rtems_ftp_mount_me,              /* initialize */
    1136     NULL,                            /* unmount */
    1137     NULL,                            /* fsunmount */
    1138     NULL,                            /* utime, */
    1139     NULL,                            /* evaluate_link */
    1140     NULL,                            /* symlink */
    1141     NULL,                            /* readlin */
    1142 };
    1143  
    1144 rtems_filesystem_file_handlers_r rtems_ftp_handlers = {
    1145     rtems_ftp_open,      /* open */     
    1146     rtems_ftp_close,     /* close */   
    1147     rtems_ftp_read,      /* read */     
    1148     rtems_ftp_write,     /* write */   
    1149     NULL,                /* ioctl */   
    1150     NULL,                /* lseek */   
    1151     NULL,                /* fstat */   
    1152     NULL,                /* fchmod */   
    1153     rtems_ftp_ftruncate, /* ftruncate */
    1154     NULL,                /* fpathconf */
    1155     NULL,                /* fsync */   
    1156     NULL,                /* fdatasync */
    1157     NULL,                /* fcntl */
    1158     NULL                 /* rmnod */
    1159 };
  • cpukit/libnetworking/rtems/ftpfs.h

    rd785ce4a r8916bdc7  
    11/**
    2  * @file rtems/ftpfs.h
     2 * @file
    33 *
    4  * File Transfer Protocol client declarations
    5  *
    6  * Transfer file to/from remote host
     4 * @brief File Transfer Protocol file system (FTP client).
    75 */
    86
    97/*
     8 * Copyright (c) 2009
     9 * embedded brains GmbH
     10 * Obere Lagerstr. 30
     11 * D-82178 Puchheim
     12 * Germany
     13 * <rtems@embedded-brains.de>
     14 *
    1015 * (c) Copyright 2002
    1116 * Thomas Doerfler
     
    1520 * <Thomas.Doerfler@imd-systems.de>
    1621 *
    17  * This code has been created after closly inspecting
    18  * "tftpdriver.c" from Eric Norum.
     22 * Modified by Sebastian Huber <sebastian.huber@embedded-brains.de>.
    1923 *
    20  *  $Id$
     24 * This code has been created after closly inspecting "tftpdriver.c" from Eric
     25 * Norum.
     26 *
     27 * The license and distribution terms for this file may be
     28 * found in the file LICENSE in this distribution or at
     29 * http://www.rtems.com/license/LICENSE.
     30 *
     31 * $Id$
    2132 */
    2233
     
    2435#define _RTEMS_FTPFS_H
    2536
     37#include <rtems/libio.h>
     38
    2639#ifdef __cplusplus
    2740extern "C" {
    2841#endif
    2942
    30 #include <rtems/libio.h>
     43/**
     44 * @defgroup rtems_ftpfs File Transfer Protocol File System
     45 *
     46 * The FTP file system (FTP client) can be used to transfer files from or to
     47 * remote hosts.
     48 *
     49 * You can mount the FTP file system with a call to rtems_ftpfs_mount().
     50 * Alternatively you can use mount() with the @ref rtems_ftpfs_ops operations
     51 * table.
     52 *
     53 * You can open files either read-only or write-only.  A seek is not allowed.
     54 * A close terminates the control and data connections.
     55 *
     56 * To open a file @c file.txt in the directory @c dir (relative to home
     57 * directory of the server) on a server named @c host using the user name
     58 * @c user and the password @c pw you must specify the following path:
     59 *
     60 * @c /FTP/user:pw@host/dir/file.txt
     61 *
     62 * If the server is the default server specified in BOOTP, it can be ommitted:
     63 *
     64 * @c /FTP/user:pw/dir/file.txt
     65 *
     66 * The user name will be used for the password if it is ommitted:
     67 *
     68 * @c /FTP/user@host/dir/file.txt
     69 *
     70 * For the data transfer passive (= default) and active (= fallback) mode are
     71 * supported.
     72 *
     73 * @{
     74 */
    3175
    32   /* create mount point and mount ftp file system */
    33 extern int rtems_bsdnet_initialize_ftp_filesystem (void);
     76/**
     77 * @brief Well-known port number for FTP control connection.
     78 */
     79#define RTEMS_FTPFS_CTRL_PORT 21
    3480
    35   /* FTP File sysem operations table. */
    36 extern rtems_filesystem_operations_table rtems_ftp_ops;
     81/**
     82 * @brief Default mount point for FTP file system.
     83 */
     84#define RTEMS_FTPFS_MOUNT_POINT_DEFAULT "/FTP"
     85
     86/**
     87 * @brief FTP file system operations table.
     88 */
     89extern const rtems_filesystem_operations_table rtems_ftpfs_ops;
     90
     91/**
     92 * @brief Creates the mount point @a mount_point and mounts the FTP file
     93 * system.
     94 *
     95 * If @a mount_point is @c NULL the default mount point
     96 * @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT will be used.
     97 *
     98 * It is mounted with read and write access.
     99 *
     100 * @note The parent directories of the mount point have to exist.
     101 */
     102rtems_status_code rtems_ftpfs_mount( const char *mount_point);
     103
     104/**
     105 * @brief Enables or disables the verbose mode if @a verbose is @c true or
     106 * @c false respectively.
     107 *
     108 * In the enabled verbose mode the commands and replies of the FTP control
     109 * connections will be printed to standard error.
     110 */
     111rtems_status_code rtems_ftpfs_set_verbose( bool verbose);
     112
     113/**
     114 * @brief Returns in @a verbose if the verbose mode is enabled or disabled.
     115 */
     116rtems_status_code rtems_ftpfs_get_verbose( bool *verbose);
     117
     118/** @} */
     119
     120/**
     121 * @brief Creates the default mount point @ref RTEMS_FTPFS_MOUNT_POINT_DEFAULT
     122 * and mounts the FTP file system.
     123 *
     124 * It is mounted with read and write access.
     125 *
     126 * On success, zero is returned.  On error, -1 is returned.
     127 *
     128 * @deprecated Use rtems_ftpfs_mount() instead.
     129 */
     130int rtems_bsdnet_initialize_ftp_filesystem( void);
    37131
    38132#ifdef __cplusplus
Note: See TracChangeset for help on using the changeset viewer.