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

📄 ftpd.c

📁 picoos源码。The RTOS and the TCP/IP stack will be built automatically.
💻 C
📖 第 1 页 / 共 4 页
字号:
{
  if (tran->filehandle >= 0)
  {
    tran->size = (u32_t) fsys_seek(tran->filehandle, 0, FSSEEK_END);

    if ((tran->upload == 0) || (tran->append == 0) ||
        (tran->owner->resumePos != 0))
    {
      fsys_seek(tran->filehandle, (sint_t) tran->owner->resumePos, FSSEEK_SET);
    }
  }
  else
  {
    tran->size = 0;
  }

  if (tran->state == TSTATE_GOTPASV)
  {
    tran->state = TSTATE_WAITONPASV;
  }
  else
  if (tran->state == TSTATE_GOTPORT)
  {
    tran->state = TSTATE_WAITFORPORT;
    connect(tran->sock, (struct sockaddr*)&tran->sin, sizeof(tran->sin));
    ft_addSendSocket(tran->sock);
  }
  tran->starttime = COUNTERVAR;
}


/* Do a directory listing.
 * If fulllist is set to 1, a ls -l is performed.
 */
static void ft_doListing(connection_t *conn, char *param, sint_t fulllist)
{
  transfer_t *tran = conn->transfer;
  char *fn, *c;
  sint_t i, ol;

  if ((tran == NULL) ||
      ((tran->state != TSTATE_GOTPASV) &&
       (tran->state != TSTATE_GOTPORT)))
  {
    ft_reply(conn, 425, "No data connection.");
    return;
  }

  fn = NULL;
  ol = 0;
  for (c = param; *c != 0; c++)
  {
    while (*c == ' ') c++;
    if (c[0] == '-')
    {
      if (((c[1] == 'l') || (c[1] == 'L')) &&
          ((c[2] == ' ') || (c[2] == 0)))
      {
        ol = 1;
        c++;
        continue;
      }
      while ((*c != ' ') && (*c != 0)) c++;
    }
    else
    {
      if (fn == NULL)
        fn = c;
    }
  }

  if (fn == NULL)
  {
    tran->filename[0] = '*';
    tran->filename[1] = 0;
  }
  else
  {
    sysStrcpy(tran->filename, fn);
    fn = tran->filename;
    for (i = 0; (fn[i] != ' ') && (fn[i] != 0); i++);
    if ((i > 0) && ((fn[i-1] == '/') || (fn[i-1] == '\\')))
      fn[i++] = '*';
    fn[i] = 0;
  }

  if (fulllist)
    ol = 1;

  if (tran->dirhandle >= 0)
    fsys_findclose(tran->dirhandle);
  tran->dirhandle = -1;
  tran->dirlisting = 1 + ol;
  tran->upload = 0;
  ft_prepTransfer(tran);
}


/* Get only the filename from the buffer
 * (remove the path name).
 */
static void ft_getFilename(connection_t *conn, char *param, char *dst)
{
#if FS_SUBDIRECTORIES 

  fsys_buildPathName(dst, conn->curpath, param);

#else /* FS_SUBDIRECTORIES */

  char *s = param;
  char *d = dst;

  (void) conn;

  while ((*s == '/') || (*s == '\\')) s++;
  while (*s != 0)
  {
    *d = (*s == '\\') ? '/' : *s;
    s++;
    if ((*d == '/') && (*s == 0))
    {
      d++;
      break;
    }
    d++;
  }
  *d = 0;

#endif /* FS_SUBDIRECTORIES */
}


/* Send a numeric and human readable reply to the client.
 */
static void ft_reply(connection_t *conn, u16_t num, const char *fmt, ...)
{
  va_list args;
  int l;

  sprintf(reply_buf_g, "%03u ", num);
  va_start(args, fmt);
  vsprintf(reply_buf_g+4, fmt, args);
  va_end(args);
  l = sysStrlen(reply_buf_g);
  reply_buf_g[l++] = '\r';
  reply_buf_g[l++] = '\n';
  conn->lastTrans = COUNTERVAR;
  if (send(conn->sock, reply_buf_g, l, 0) < 0)
  {
    if (sysGetErrno() == EPIPE)
    {
      ft_destroyConnection(conn);
    }
  }
}


/* Fill buffer with next line of directory listing
 */
static sint_t ft_getNextDirEntry(transfer_t *tran, char *buf)
{
  struct fsys_finddata finfo;
  sint_t rc;
  char   d;

  *buf = 0;

  if (tran->dirhandle == -2)
    return 0;

  if (tran->dirhandle < 0)
  {
#if FS_SUBDIRECTORIES
    if (fsys_buildPathName(fnamebuf_g, tran->owner->curpath, 
                           tran->filename) >= 0)
    {
      tran->dirhandle = fsys_findfirst(fnamebuf_g, &finfo);
    }
#else
    tran->dirhandle = fsys_findfirst(tran->filename, &finfo);
#endif
  }
  else
  {
    rc = fsys_findnext(tran->dirhandle, &finfo);
    if (rc < 0)
    {
      return 0;
    }
  }

  if (tran->dirhandle >= 0)
  {
    if (tran->dirlisting == 2)
    {
      /* long directory listing */
      d = (finfo.attrib & FSA_SUBDIR) ? 'd' : '-';
      if (finfo.attrib & FSA_RDONLY)
      {
        sprintf(buf + sysStrlen(buf),
                "%cr--r--r--   1 ftp      root     ", d);
      }
      else
      {
        sprintf(buf + sysStrlen(buf),
                "%crw-rw-rw-   1 ftp      root     ", d);
      }

      sprintf(buf + sysStrlen(buf), "%8lu ", (unsigned long) finfo.size);
#if 0
      sprintf(buf + sysStrlen(buf), "%s %2u %04u ",
              month_g[finfo.time.month], 
              (uint_t) finfo.time.day, (uint_t) finfo.time.year);
#else
      sprintf(buf + sysStrlen(buf), "%s %2u %02u:%02u ",
              month_g[finfo.time.month], 
              (uint_t) finfo.time.day,
              (uint_t) finfo.time.hour, (uint_t) finfo.time.min);
#endif

    }
    sysStrcat(buf, finfo.name);
    sysStrcat(buf, "\r\n");
  }
  else
  {
    tran->dirhandle = -2;
  }
  return sysStrlen(buf);
}




/*---------------------------------------------------------------------------
 *  CONNECTION HANDLING
 *-------------------------------------------------------------------------*/


/* Add a socket to the global socket send set.
 */
static sint_t ft_addSendSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalSocketSendSet);
    FD_SET(sock, &globalSocketSendSet);
    return 0;
  }
  return -1;
}


/* Add a socket to the global socket set.
 */
static sint_t ft_addSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalSocketSet);
    FD_SET(sock, &globalSocketSet);
    return 0;
  }
  return -1;
}


/* Remove socket from fdsets and close it.
 */
static void ft_delSocket(const int sock)
{
  if (sock >= 0)
  {
    FD_CLR(sock, &globalSocketSet);
    FD_CLR(sock, &globalSocketSendSet);
    closesocket(sock);
  }
}


/*-------------------------------------------------------------------------*/


/* Insert an element to the tail of a double linked list.
 */
static void ft_listAddTail(lelem_t *headelem, lelem_t *elem)
{
  elem->prev = headelem->prev;
  elem->next = headelem;
  headelem->prev->next = elem;
  headelem->prev = elem;
}


/* Insert an element to the head of a double linked list.
 */
static void ft_listAddHead(lelem_t *headelem, lelem_t *elem)
{
  elem->next = headelem->next;
  elem->prev = headelem;
  headelem->next->prev = elem;
  headelem->next = elem;
}


/* Remove an element from a double linked list
 * and free its memory.
 */
static void ft_listDel(lelem_t *elem)
{
  lelem_t *next = elem->next;
  lelem_t *prev = elem->prev;
  next->prev = prev;
  prev->next = next;
}


/*-------------------------------------------------------------------------*/


/* Create and initialize a new connection structure.
 * On success, the connection is established and a 220 status is sent.
 */
static sint_t ft_newConnection(int socket)
{
  unsigned long one = 1;
  connection_t *conn;

  if ((socket != -1) &&
      ((open_connections_g >= FTP_MAXCON) ||
       (open_connections_g >= FD_SETSIZE)))
  {
    /* too many connections opened */
    send(socket, "221 Maximum number of connections established, "
                 "try later again.\r\n", 65, 0);
    return -1;
  }

  conn = (connection_t *)(sysMemAlloc(sizeof(connection_t)));
  if (conn == NULL)
    return -1;

  conn->transfer    = NULL;
  conn->sock        = socket;
  conn->buflen      = 0;
  conn->auth        = 0;
  conn->resumePos   = 0;
  conn->renfrom[0]  = 0;
  conn->lastTrans   = COUNTERVAR;
#if FS_SUBDIRECTORIES
  conn->curpath[0]  = 0;
#endif

  /* set nonblocking mode */
  ioctlsocket(socket, FIONBIO, (void*)&one);

  /* add socket and connection to list of active connections */
  ft_addSocket(socket);
  ft_listAddTail(&connListRoot_g, (lelem_t*)(void*)conn);
  open_connections_g++;

  ft_reply(conn, 220, "Connection established, FTPD ready.");
  return 0;
}


/* Create and initialize a new filetransfer structure.
 */
static transfer_t *ft_newTransfer(int socket, connection_t *conn)
{
  transfer_t *tran;

  tran = (transfer_t *)(sysMemAlloc(sizeof(transfer_t)));
  if (tran == NULL)
    return NULL;

  tran->owner       = conn;
  tran->sock        = socket;
  tran->state       = TSTATE_NONE;
  tran->dlbufpos    = 0;
  tran->dlbufremain = 0;
  tran->filehandle  = -1;
  tran->dirhandle   = -1;
  tran->dirlisting  = 0;
  tran->wrDisabled  = 0;

  ft_listAddTail(&transfListRoot_g, (lelem_t*)(void*)tran);
  return tran;
}


/* Destroys a ctrl connection and
 * cleans up the connection structure.
 */
static void ft_destroyConnection(connection_t *conn)
{
  if (conn == NULL)
    return;

  if ((conn->sock >= 0) && (open_connections_g > 0))
  {
    open_connections_g--;
  }

  ft_delSocket(conn->sock);
  ft_destroyTransfer(conn->transfer);
  ft_listDel((lelem_t*)(void*)conn);
  sysMemFree(conn);
}


/* Destroys a data connection and
 * cleans up the connection structure.
 */
static void ft_destroyTransfer(transfer_t *tran)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
  unsigned long zero = 0;
#endif

  if (tran == NULL)
    return;

  if (tran->sock >= 0)
  {
#if defined(TCP_CORK) && defined(SOL_TCP)
    /* ensure that all data is flushed out when closing the socket */
    setsockopt(tran->sock, SOL_TCP, TCP_CORK, (void *)&zero, sizeof(zero));
#endif
    ft_delSocket(tran->sock);
  }
  if (tran->filehandle != -1)
  {
    fsys_close(tran->filehandle);
  }
  if (tran->dirhandle != -1)
  {
    fsys_findclose(tran->dirhandle);
  }
  if (tran->owner != NULL)
  {
    tran->owner->transfer = NULL;
  }
  if (tran->wrDisabled != 0)
  {
    blockedTrans_g--;
  }
  ft_listDel((lelem_t*)(void*)tran);
  sysMemFree(tran);
}


/*-------------------------------------------------------------------------*/


/* This function processes all open control connections.
 * If data was received over the connection, it is
 * passed to the command line parser.
 */
static sint_t ft_processCtrlConnections(fd_set *clientset, int fdcount)
{
  connection_t *conn, *next;
  sint_t checked;
  int   bytes;

  next = FIRST_LIST_ELEM(&connListRoot_g, connection_t*);
  checked = 0;

  /* process all connections in the list */
  while (!END_OF_LIST(&connListRoot_g, next) && (checked < fdcount))
  {
    conn = next;
    next = NEXT_LIST_ELEM(conn, connection_t*);

    if (!FD_ISSET(conn->sock, clientset))
    {
      continue;
    }

    checked++;

    bytes = recv(conn->sock, conn->rxbuffer + conn->buflen,
                 (FTP_INPBUFSIZE-1) - conn->buflen, 0);

    if (bytes <= 0)
    {
      /* If no bytes are available or -1 is returned,
       * the client must have closed the connection since
       * select told us that there was something with the socket.
       */
      ft_destroyConnection(conn);
      continue;
    }

    /* safety check: buffer overrun (should never happen) */
    if ((conn->buflen + (u16_t) bytes) >= (FTP_INPBUFSIZE-1))
    {
      ft_reply(conn, 500, "Buffer error, connection shut down.");
      ft_destroyConnection(conn);
      continue;
    }
    conn->buflen += (u16_t) bytes;
    conn->lastTrans = COUNTERVAR;

    ft_execCommand(conn);
  }
  return checked;
}


/* Do a data connection upload.
 */
static sint_t ft_handleUpload(transfer_t *tran)
{
  int size;

  tran->owner->lastTrans = COUNTERVAR;

  size = recv(tran->sock, upload_buf_g, UPLOADBUF_SIZE, 0);
  if (size > 0)
  {
    tran->pos += (u32_t) size;
    if (fsys_write(tran->filehandle, upload_buf_g, (sint_t) size) == size)
    {
      return 1;
    }
  }
  else
  if (size == 0)
  {
    return 0;
  }

  ft_abortTransfer(tran->owner);
  return 1;
} 


/* Do a data connection download.
 */
static sint_t ft_handleDownload(transfer_t *tran)
{
#if defined(TCP_CORK) && defined(SOL_TCP)
  unsigned long zero = 0;
#endif
  sint_t moreToSend = 0;
  int   bytes, size;

  /* fill buffer */
  if (tran->dlbufremain == 0)
  {
    tran->dlbufpos = 0;
    if (tran->dirlisting)
    {
      bytes = ft_getNextDirEntry(tran, tran->dlbuf);
    }
    else
    {
      bytes = fsys_read(tran->filehandle, tran->dlbuf, MAX_BLOCKSIZE);
    }

    if (bytes >= MAX_BLOCKSIZE)
    {
      moreToSend = 1;
    }

    if (bytes > 0)
    {
      if (bytes > MAX_BLOCKSIZE)
        bytes = MAX_BLOCKSIZE;
      tran->dlbufremain = (u16_t) bytes;
    }
  }

  /* send data */
  if (tran->dlbufremain != 0)
  {
#if defined(TCP_CORK) && defined(SOL_TCP)
    /* flush buffer if we believe we send the last block */
    if (moreToSend == 0)
    {
      setsockopt(tran->sock, SOL_TCP, TCP_CORK, (void*)&zero, sizeof(zero));
    }
#endif

    size = send(tran->sock, tran->dlbuf + tran->dlbufpos, 
                tran->dlbufremain, 0);

⌨️ 快捷键说明

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