⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ftpfs.c

📁 RTEMS (Real-Time Executive for Multiprocessor Systems) is a free open source real-time operating sys
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * File Transfer Protocol client * * Transfer file to/from remote host *  * This driver can be added to the RTEMS file system with a call to  * "rtems_bsdnet_initialize_ftp_filesystem () ". * From then on, you can open, read and close files on a remote FTP server  * using the following syntax: * To open a file "myfile.txt" in the directory "mydir" (relative to home  * directory) on a server named "myserver" using the user id * "myuserid" and the password "my_very_secret_password" you must  * specify the following path: *  * /FTP/myuserid:my_very_secret_password/@myserver/mydirectory/myfile.txt *  * If the server is the default server specified in BOOTP, it can be ommitted: *  * /FTP/myuserid:my_very_secret_password/mydirectory/myfile.txt * * WARNING: write accesses have not yet been tested. *  * * (c) Copyright 2002 * Thomas Doerfler * IMD Ingenieurbuero fuer Microcomputertechnik * Herbststr. 8 * 82178 Puchheim, Germany  * <Thomas.Doerfler@imd-systems.de> * * This code has been created after closly inspecting  * "tftpdriver.c" from Eric Norum. *  *  $Id: ftpfs.c,v 1.3 2003/02/05 21:25:55 joel Exp $ */#include <stdio.h>#include <errno.h>#include <malloc.h>#include <string.h>#include <stdlib.h>#include <fcntl.h>#include <unistd.h>#include <ctype.h>#include <rtems.h>#include <rtems/libio.h>#include <rtems/rtems_bsdnet.h>#include <sys/types.h>#include <sys/socket.h>#include <netinet/in.h>#include <arpa/inet.h>#include <netdb.h>#include <rtems/ftpfs.h>#ifndef set_errno_and_return_minus_one#define set_errno_and_return_minus_one( _error ) \  do { errno = (_error); return -1; } while(0)#endif/* #define DEBUG_OUT *//* * Well-known port for FTP */#define FTP_PORT_NUM	21/* * Pathname prefix */#define FTP_PATHNAME_PREFIX	"/FTP/"/* * reply codes */#define FTP_REPLY_CONNECT 220  /* Connection established       */#define FTP_REPLY_PASSREQ 331  /* user ok, password required   */#define FTP_REPLY_LOGIN   230  /* login finished               */#define FTP_REPLY_SUCCESS 200  /* xxx successful               */#define FTP_REPLY_OPENCONN 150 /* opening connection for tfer  */#define FTP_REPLY_TFERCMPL 226 /* transfer complete            */extern rtems_filesystem_operations_table  rtems_ftp_ops;  extern rtems_filesystem_file_handlers_r rtems_ftp_handlers;/* * FTP command strings */#define FTP_USER_CMD   "USER "#define FTP_PASS_CMD   "PASS "#define FTP_BINARY_CMD "TYPE I"#define FTP_PORT_CMD   "PORT "#define FTP_STOR_CMD   "STOR "#define FTP_RETR_CMD   "RETR "#define FTP_QUIT_CMD   "QUIT"/* * State of each FTP stream */struct ftpStream {  /*   * Control connection socket   */  int ctrl_socket;  struct sockaddr_in	myCtrlAddress;  struct sockaddr_in	farCtrlAddress;  /*   * Data transfer socket   */  int port_socket;  int data_socket;  struct sockaddr_in	myDataAddress;  struct sockaddr_in	farDataAddress;  /*   * other stuff to remember   */  boolean eof_reached;};/* * Number of streams open at the same time */static rtems_id ftp_mutex;static int nStreams;static struct ftpStream ** volatile ftpStreams;extern rtems_filesystem_operations_table  rtems_tftp_ops;extern rtems_filesystem_file_handlers_r   rtems_tftp_handlers;/* *  Direct copy from the IMFS/TFTP.  Look at this. */rtems_filesystem_limits_and_options_t rtems_ftp_limits_and_options = {   5,   /* link_max */   6,   /* max_canon */   7,   /* max_input */   255, /* name_max */   255, /* path_max */   2,   /* pipe_buf */   1,   /* posix_async_io */   2,   /* posix_chown_restrictions */   3,   /* posix_no_trunc */   4,   /* posix_prio_io */   5,   /* posix_sync_io */   6    /* posix_vdisable */};int rtems_ftp_mount_me(  rtems_filesystem_mount_table_entry_t *temp_mt_entry){  rtems_status_code  sc;  temp_mt_entry->mt_fs_root.handlers = &rtems_ftp_handlers;  temp_mt_entry->mt_fs_root.ops      = &rtems_ftp_ops;  /*   *   We have no ftp filesystem specific data to maintain.  This   *   filesystem may only be mounted ONCE.   *   *   And we maintain no real filesystem nodes, so there is no real root.   */  temp_mt_entry->fs_info                = NULL;  temp_mt_entry->mt_fs_root.node_access = NULL;  /*   *  These need to be looked at for full POSIX semantics.   */  temp_mt_entry->pathconf_limits_and_options = rtems_ftp_limits_and_options;   /*   *  Now allocate a semaphore for mutual exclusion.   *   *  NOTE:  This could be in an fsinfo for this filesystem type.   */    sc = rtems_semaphore_create (rtems_build_name('F','T','P',' '),			       1,			       RTEMS_FIFO |			       RTEMS_BINARY_SEMAPHORE |			       RTEMS_NO_INHERIT_PRIORITY |			       RTEMS_NO_PRIORITY_CEILING |			       RTEMS_LOCAL,			       0,			       &ftp_mutex);  if (sc != RTEMS_SUCCESSFUL)    set_errno_and_return_minus_one( ENOMEM );   return 0;}/* * Initialize the FTP driver */int rtems_bsdnet_initialize_ftp_filesystem () { int                                   status; rtems_filesystem_mount_table_entry_t *entry; status = mkdir( FTP_PATHNAME_PREFIX, S_IRWXU | S_IRWXG | S_IRWXO ); if ( status == -1 )   return status;   status = mount(      &entry,     &rtems_ftp_ops,     RTEMS_FILESYSTEM_READ_ONLY,      NULL,     FTP_PATHNAME_PREFIX  );  if ( status )    perror( "FTP mount failed" );  return status;}/* * read and return message code from ftp control connection */int rtems_ftp_get_message(  const struct ftpStream *fsp,  /* ptr to ftp control structure */  int *msg_code                 /* ptr to return message code   */){  char rd_buffer[4];  size_t rd_size;  size_t tmp_size;  int eno = 0;  rtems_boolean finished = FALSE;  do {    /*     * fetch (at least) 4 characters from control connection     * FIXME: how about a timeout?     */        rd_size = 0;    while ((eno == 0) &&	   (rd_size < sizeof(rd_buffer))) {      tmp_size = read(fsp->ctrl_socket,		      (&rd_buffer)+rd_size,		      sizeof(rd_buffer)-rd_size);      if (tmp_size < 0) {	eno = EIO;      }      else {#ifdef DEBUG_OUT	write(1,(&rd_buffer)+rd_size,tmp_size);#endif	rd_size += tmp_size;      }    }    /*     * check for 3 digits and space, otherwise not finished     */        if ((eno == 0) &&	(isdigit((unsigned int)rd_buffer[0])) &&	(isdigit((unsigned int)rd_buffer[1])) &&	(isdigit((unsigned int)rd_buffer[2])) &&	(rd_buffer[3] == ' ')) {      finished = TRUE;      rd_buffer[3] = '\0';      *msg_code = atol(rd_buffer);    }    /*     * skip rest until end-of-line     */    do {      tmp_size = read(fsp->ctrl_socket,		      &rd_buffer,		      1);      if (tmp_size < 0) {	eno = EIO;      }#ifdef DEBUG_OUT      else {	write(1,(&rd_buffer),tmp_size);      }#endif    } while ((eno == 0) &&	     (rd_buffer[0] != '\n'));  } while ((eno == 0) && !finished);  return eno;}/* * split a pseudo file name into host, user, password, filename * NOTE: this function will allocate space for these strings, * the calling function should free the space, when no longer needed * exception: when we return any error, we will also cleanup * the strings * valid forms: * /FTP/user:pass/filepath * /FTP/user:pass@hostname/filepath * /FTP/user:pass/filepath * /FTP/user:pass/@hostname/filepath * NOTE: /FTP is already stripped from the name */int rtems_ftp_split_names( const char *pathname,         /* total path name (including prefix)     */  char **usernamep,             /* ptr to ptr to user name                */  char **passwordp,             /* ptr to ptr to password                 */  char **hostnamep,             /* ptr to ptr to host name                */  char **filenamep)             /* ptr to ptr to hostremaining file name  */{  const char  *chunk_start;  const char  *chunk_end;  size_t chunk_len;  int rc = 0;  /*   * ensure, that result pointers are NULL...   */  *usernamep = NULL;  *passwordp = NULL;  *hostnamep = NULL;  *filenamep = NULL;#if 1  chunk_start = pathname;#else /* no longer needed with IMFS */  /*   * check, that total path is long enough, skip prefix   */  if (rc == 0) {    if (strlen (pathname) <= strlen (FTP_PATHNAME_PREFIX)) {      rc = ENOENT;    }    else {      chunk_start = pathname + strlen (FTP_PATHNAME_PREFIX);    }  }#endif  /*   * fetch user name: terminated with ":"   */  if (rc == 0) {    chunk_end = strchr(chunk_start,':');    if ((chunk_end == NULL) ||         /* No ':' found or                  */	(chunk_end == chunk_start)) {  /* ':' is first character-> no name */      rc = ENOENT;    }    else {      chunk_len = chunk_end-chunk_start;      *usernamep = malloc(chunk_len+1);      if (*usernamep == NULL) {	rc = ENOMEM;      }      else {	memcpy(*usernamep,chunk_start,chunk_len);	(*usernamep)[chunk_len] = '\0';      }    }  }  /*   * fetch password: terminated with "/" or "@"   */  if (rc == 0) {    chunk_start = chunk_end + 1; /* skip ":" after user name */    chunk_end = strchr(chunk_start,'/');    if ((chunk_end == NULL) ||         /* No '/' found or                  */	(chunk_end == chunk_start)) {  /* '/' is first character-> no pwd  */      rc = ENOENT;    }    else {      /*       * we have found a proper '/'       * this is the end of the password       */      chunk_len = chunk_end-chunk_start;      *passwordp = malloc(chunk_len+1);      if (*passwordp == NULL) {	rc = ENOMEM;      }      else {	memcpy(*passwordp,chunk_start,chunk_len);	(*passwordp)[chunk_len] = '\0';      }    }  }  /*   * if first char after '/' is '@', then this is the hostname   * fetch hostname terminated with "/"   * if exists at all. otherwise take default server from bootp   */  if (rc == 0) {    chunk_start = chunk_end+1;    if (*chunk_start == '@') {      /*        * hostname follows       */      chunk_start = chunk_start + 1; /* skip "@" after password */      chunk_end = strchr(chunk_start,'/');      if ((chunk_end == NULL) ||         /* No '/' found or                  */	  (chunk_end == chunk_start)) {  /* '/' is first character-> no host */	rc = ENOENT;      }      else {	/*	 * we have found a proper '/'	 */	chunk_len = chunk_end-chunk_start;	*hostnamep = malloc(chunk_len+1);	if (*hostnamep == NULL) {	  rc = ENOMEM;	}	else {	  memcpy(*hostnamep,chunk_start,chunk_len);	  (*hostnamep)[chunk_len] = '\0';	}      }    }    else { /* chunk_start != '@' */      /*       * no host name given, keep string empty       */      *hostnamep = malloc(1);      if (*hostnamep == NULL) {	rc = ENOMEM;      }      else {	(*hostnamep)[0] = '\0';      }    }        }  /*   * fetch filename. This is all the rest...   */  if (rc == 0) {    chunk_start = chunk_end+1;    if (*chunk_start == '\0') {  /* nothing left for filename */      rc = ENOENT;    }    else {      chunk_len = strlen(chunk_start);      *filenamep = malloc(chunk_len+1);      if (*filenamep == NULL) {	rc = ENOMEM;      }      else {	memcpy(*filenamep,chunk_start,chunk_len);	(*filenamep)[chunk_len] = '\0';      }    }  }    /*   * cleanup anything, if error occured   */  if (rc != 0) {    if (*hostnamep != NULL) {      free(*hostnamep);      *hostnamep = NULL;    }    if (*usernamep != NULL) {      free(*usernamep);      *usernamep = NULL;    }    if (*passwordp != NULL) {      free(*passwordp);      *passwordp = NULL;    }    if (*filenamep != NULL) {      free(*filenamep);      *filenamep = NULL;    }  }  return rc;}				       int rtems_ftp_evaluate_for_make(   const char                         *path,       /* IN     */   rtems_filesystem_location_info_t   *pathloc,    /* IN/OUT */   const char                        **name        /* OUT    */){    set_errno_and_return_minus_one( EIO );    }/* * XXX - Fix return values. */int rtems_ftp_eval_path(    const char                        *pathname,     /* IN     */  int                                flags,        /* IN     */  rtems_filesystem_location_info_t  *pathloc       /* IN/OUT */){  /*   * Read-only for now   */     if ( ((flags & O_RDONLY) != O_RDONLY ) &&        ((flags & O_WRONLY) != O_WRONLY )) {    set_errno_and_return_minus_one( ENOENT );  }  /*   * The File system is mounted at FTP_PATHNAME_PREFIX   * the caller of this routine has striped off this part of the   * name. Save the remainder of the name for use by the open routine.   */  pathloc->node_access = (void * ) pathname;  pathloc->handlers    = &rtems_ftp_handlers;  return 0;}/* * Open a FTP stream */int rtems_ftp_open(  rtems_libio_t *iop,  const char    *new_name,  unsigned32     flag,  unsigned32     mode){  int s = 0;  char *filename  = NULL;  char *uname     = NULL;  char *upass     = NULL;  char *hostname  = NULL;  char port_buffer[sizeof(FTP_PORT_CMD)+6*4+1+1];  rtems_unsigned32 my_ip;  rtems_unsigned16 my_port;  int eno = 0;  rtems_status_code rc;  rtems_boolean is_write = FALSE;  rtems_boolean sema_obtained = FALSE;  struct ftpStream *fsp = NULL;  int msg_tmp;  int sockaddr_size;  /*   * check for R/O or W/O flags   */  if (eno == 0) {    if ((0 != (iop->flags & LIBIO_FLAGS_WRITE)) && 	(0 != (iop->flags & LIBIO_FLAGS_READ))) {      eno = ENOTSUP;    }    else {      is_write = (0 != (iop->flags & LIBIO_FLAGS_WRITE));    }  }  /*   * split pathname into parts   */  if (eno == 0) {    eno = rtems_ftp_split_names(iop->file_info,				&uname,				&upass,				&hostname,				&filename);  }    /*   * Find a free stream   */  if (eno == 0) {    rc = rtems_semaphore_obtain (ftp_mutex, RTEMS_WAIT, RTEMS_NO_TIMEOUT);    if (rc == RTEMS_SUCCESSFUL) {      sema_obtained = TRUE;    }    else {      eno = EBUSY;    }  }  if (eno == 0) {    for (s = 0 ; s < nStreams ; s++) {      if (ftpStreams[s] == NULL)	break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -