荔园在线

荔园之美,在春之萌芽,在夏之绽放,在秋之收获,在冬之沉淀

[回到开始] [上一篇][下一篇]


发信人: jjk (UNIX+C+XML+?? 傻了?), 信区: Linux
标  题: 递归编历FTP目录的程序                  ysqcn (转寄)[转载]
发信站: 荔园晨风BBS站 (Thu Apr 25 10:25:39 2002), 转信

【 以下文字转载自 jjk 的信箱 】
【 原文由 jjk.bbs@apue.dhs.org 所发表 】
发信人: ysqcn (岁月无声), 信区: UNP
标  题: 递归编历FTP目录的程序
发信站: UNIX编程 (Tue Sep 18 23:29:46 2001) , 转信

下面的程序的目的是获取FTP上的目录列表,整理成树状结构。大部分是拷贝
netkit-ftp-0.17中的代码,自己到没有写什么。难保运行时不出什么错误,
网络通畅的时候,匿名从根目录递归ftp://csun.hust.edu.cn至底下五层子目
录还没有出什么问题。不知fion做的怎么样了,贴出来起个抛转引玉的作用。
原理就不多说了,就是对子目录递归CD然后LIST。程序中一个-b参数是为了编
历结果生成的文件方便的贴在BBS。


/*
buildftpfilelist.c:递归编历FTP目录,形成目录树
gcc -O6 -Wall -o buildftpfilelist buildftpfilelist.c
注:大部分代码来自于netkit-ftp-0.17,自己又剽窃了一回
实在对不住作者,这里只能对他们表示感谢,呵呵
*/

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <arpa/ftp.h>
#include <netdb.h>
#include <string.h>
#include <ctype.h>
#include <stdarg.h>
#include <getopt.h>

#define UC(b)   (((int)b)&0xff)
#define ESC     0X1B
#define YELLOW  "[1;33;40m"
#define GREEN   "[1;36;40m"
#define WHITE   "[1;37;40m"
void process_argument(int argc,char **argv);
void connectftp(char *host);
void loginftp(char *user,char *passwd);
void init_recurse(char * localfile);
void recurseftpdir(char * dirname,int level);
void finish_recurse(void);

int  cd(char *dir);
int  command(const char *fmt,...);
int  getreply(int expecteof);
int  recvrequest(const char *cmd,char *remote);
int  initconn(void);
FILE * dataconn(const char *lmode);

void prnvertline(int );
void gotoneitem(int level,int dir,int begin,char *name);
void usage(char * prgname);

char host[128],user[64],passwd[64],startdir[128],localfile[64];
int  level,bbs=0;
FILE *cin,*cout,*din,*fout;
FILE *lfp;   /*file to store the recursing result*/
int  code;

struct sockaddr_in localaddr;
int    datasock;
int    verbose=1;

#define  FTPDIR struct ftpdir
FTPDIR
{
  char dirname[256];
  FTPDIR *nextdir;
};

char buffline[1024];

int main(int argc,char *argv[])
{
  process_argument( argc,argv );
  connectftp( host );
  loginftp(user,passwd);
  init_recurse( localfile );
  recurseftpdir( startdir,1 );
  finish_recurse();

  return 0;
}

void process_argument(int argc,char **argv)
{
  char c,*prgname;

  strcpy(user,"anonymous");
  strcpy(passwd,"ysqcn@263.net");
  strcpy(startdir,"/");
  strcpy(localfile,"-");
  level = 5;

  prgname=*argv;
  opterr = 0;
  while (  ( c = getopt(argc,argv,"h:u:p:d:f:l:?b") ) != EOF )
    {
      switch ( c )
    {
    case 'u':
      strncpy( user,optarg,sizeof( user ) );
      break;
    case 'p':
      strncpy( passwd,optarg,sizeof( passwd ) );
      break;
    case 'd':
      strncpy( startdir,optarg,sizeof( startdir ) );
      break;
    case 'f':
      strncpy( localfile,optarg,sizeof( localfile ) );
      break;
    case 'l':
      level = atoi ( optarg );
      break;
    case 'b':
      bbs = 1;
      break;
    case ':':
    case '?':
    case 'h':
      usage(argv[0]);
      exit(0);
    }
    }
  argc -= optind;
  argv += optind;
  if ( argc == 0 )
    {
      usage(prgname);
      exit(-1);
    }
  strncpy(host,*argv,sizeof(host));

  return;
}

void init_recurse(char * localfile)
{
  if ( strcmp(localfile,"-") == 0 )
    lfp = stdout ;
  else
    if (  ( lfp = fopen( localfile,"w+" ) ) == NULL )
      {
    fprintf(stderr,"Open local file failed,output to stdout.\n");
    lfp = stdout;
      }

  if ( cd( startdir ) )
    {
      fprintf(stderr,"Can't cd directory %s.\n",startdir);
      exit(-1);
    }

  if ( command ("TYPE %s","A") != COMPLETE )
    fprintf(stderr,"Set ascii mode failed.\n");
  if ( bbs )
    {
      fprintf(lfp,"%c%c",ESC,ESC);
      fprintf(lfp,"%s",WHITE);
    }
  verbose = 0;
  fprintf(stdout,"\nBegin recursing ftp directory\n");

  return;
}

void connectftp(char *host)
{
  struct servent *sp;
  register struct hostent *hp = 0;
  struct sockaddr_in  servaddr;
  int s,len;

  bzero( &servaddr,sizeof( servaddr ) );
  servaddr.sin_family = AF_INET;
  if ( inet_pton( AF_INET,host, &servaddr.sin_addr ) != 1 )
    {
      hp = gethostbyname(host);
      if (hp == NULL)
    {
      fprintf(stderr,"Get ftp ip address failed,exit.\n");
      exit(-1);
    }
      servaddr.sin_family = hp->h_addrtype;
      if ( hp->h_length > (int)sizeof(servaddr.sin_addr) )
    hp->h_length = sizeof(servaddr.sin_addr);
      memcpy(&servaddr.sin_addr,hp->h_addr,hp->h_length);
    }

  sp = getservbyname("ftp", "tcp");
  if (sp == 0)
    {
      fprintf(stderr,"Get ftp service failed,exit.\n");
      exit(-1);
    }

  servaddr.sin_port=sp->s_port;

  if (  ( s = socket(AF_INET,SOCK_STREAM,0) ) == -1)
    {
      fprintf(stderr,"Create control socket faild,exit.\n");
      exit(-1);
    }

  if ( connect(s, (struct sockaddr *)&servaddr, sizeof (servaddr)) < 0)
    {
      fprintf(stderr,"Connect ftp server faild,exit.\n");
      exit(-1);
    }
  len = sizeof(localaddr);
  if ( getsockname( s,(struct sockaddr *)&localaddr,&len ) < 0 )
    {
      fprintf(stderr,"Get control socket name faild,exit.\n");
      exit(-1);
    }

  cin = fdopen(s, "r");
  cout = fdopen(s, "w");
  if (cin == NULL || cout == NULL)
    {
      fprintf(stderr,"Control socket fdopen faild,exit.\n");
      if (cin)
    (void) fclose(cin);
      if (cout)
    (void) fclose(cout);
      exit(-1);
    }

  /* read startup message from server */
  if (getreply(0) > 2)
    {
      if (cin)
    (void) fclose(cin);
      if (cout)
    (void) fclose(cout);
      fprintf(stderr,"Ftp server reply incorrectly,exit.\n");
      exit(-1);
    }
  return;
}

void loginftp(char *user,char *passwd)
{
  int n;

  n = command("USER %s", user);
  if (n == CONTINUE)
    n = command("PASS %s", passwd);

  if (n != COMPLETE)
    {
      fprintf(stderr, "Login ftp server failed,exit.\n");
      exit(0);
    }

  return;
}


void recurseftpdir(char * dirname,int level0)
{
  char mode[16],name[256],*pname,*tmpdir;
  FTPDIR *dirhd=NULL,*current=NULL,*tmp;

  if ( level0 > level )
    return;

  if ( lfp != stdout )
    fprintf(stdout,".");

  if ( ( fout = tmpfile() ) == NULL )
    {
      fprintf(stderr,"Open temp file failed,exit\n");
      exit(-1);
    }

  if ( recvrequest("LIST",".") )
    return;

  (void)fflush(fout);
  rewind(fout);

  while ( fgets(buffline,1024,fout) != NULL )
    {
      sscanf(buffline,"%s%*s%*s%*s%*s%*s%*s%*s%s",mode,name);

      if ( ( mode[0] != 'd' && mode[0] != '-' ) || !strcmp(name,".") || !strcmp(
name,"..") )
        continue;

      /* handle the name which includes space*/
      buffline[strlen(buffline)-1]='\0';
      pname = strstr(buffline,name);
      strncpy( name,pname,sizeof(name) );

      if ( mode[0] == 'd' )
        {
          tmp=(FTPDIR *) malloc( sizeof(FTPDIR) );
          strncpy( tmp->dirname,name,sizeof(tmp->dirname) );
          tmp->nextdir = NULL;
          if ( dirhd == NULL )
            dirhd = tmp;
          else
            current->nextdir = tmp;
          current = tmp ;
          continue;
        }
      gotoneitem(level0,0,0,name);
    }
  fclose(fout);
  current = dirhd;
  while ( current != NULL )
    {
      tmpdir = current->dirname;
      gotoneitem(level0,1,1,tmpdir);
      if  ( cd( tmpdir ) == 0 )
    {
      recurseftpdir(current->dirname,level0+1);
      if ( cd("..") )
        {
          fprintf(stderr,"Can't goto parent directory,exit.\n");
          exit(-1);
        }
    }
      gotoneitem(level0,1,0,tmpdir);

      dirhd = current->nextdir;
      free(current);
      current = dirhd;
    }
}

void finish_recurse(void)
{
  fprintf(stdout,"\nFinish recursing ftp directory\n\n");
  verbose=1;
  command("QUIT");
}

int command(const char *fmt,...)
{
  va_list ap;
  int r;

  va_start(ap, fmt);
  vfprintf(cout, fmt, ap);
  va_end(ap);
  fprintf(cout, "\r\n");
  (void) fflush(cout);

  r=getreply( !strcmp(fmt, "QUIT") );

  return r;
}

int  getreply(int expecteof)
{
  register int c, n;
  register int dig;
  int originalcode = 0, continuation = 0;
  char reply_string[BUFSIZ];
  char *cp;

  cp = reply_string;
  for (;;)
    {
      dig = n = code = 0;
      while ( ( c = getc( cin ) ) != '\n')
    {
      dig++;
      if ( c == EOF )
        {
          if (expecteof)
        {
          code = 221;
          return (0);
        }
          fprintf(stderr,"ftp server closed abnormally,exit.\n");
          exit(-1);
        }

      if ( verbose && c != '\r'  )
        (void) putchar(c);

      if ( dig < 4 && isdigit(c) )
        code = code * 10 + (c - '0');

      if ( dig == 4 && c == '-' )
        {
          if (continuation)
        code = 0;
          continuation++;
        }

          if ( cp < &reply_string[sizeof(reply_string)-1] )
        *cp++=c;

      if (n == 0)
        n = c;
    }/*end while*/

      if ( verbose )
    (void) putchar(c);
      (void) fflush (stdout);


      if ( continuation && code != originalcode )
    {
      if (originalcode == 0)
        originalcode = code;
      continue;
    }
      *cp='\0';
      return (n - '0');
    }/*end for*/
}

int recvrequest(const char *cmd,char *remote)
{
  int c,d,bytes=0,result;
  char buf[1024];

  if ( initconn() )
    {
      code=-1;
      return(-1);
    }

  if (remote)
    result = command("%s %s", cmd, remote);
  else
    result = command("%s", cmd);
  if ( result != PRELIM )
    return -1 ;

  if (  ( din = dataconn("r") )== NULL )
    {
      fprintf(stderr,"\nData connection failed,exit.\n");
      exit(-1);
    }

 loopin:
  while ( ( c = getc(din) ) != EOF )
    {
      while ( c == '\r' )
    {
      bytes++;
      if ( ( c = getc(din) ) != '\n' )
        {
          if ( ferror(fout) )
        goto loopout;
          (void) putc('\r', fout);
          if (c == '\0')
        {
          bytes++;
          goto loopin;
        }
          if (c == EOF)
        goto loopin;
        }
    }
      (void) putc(c, fout);
      bytes++;
    }
loopout:
  if ( din )
    fclose(din);
  if ( datasock >= 0 )
    {
      close(datasock);
      datasock = -1;
    }
  (void)getreply(0);
  return(0);
}

int  initconn(void)
{
  register char * a ,* p;
  socklen_t len;
  int on = 1,result;
  struct sockaddr_in dataaddr;

  if ( ( datasock = socket( AF_INET, SOCK_STREAM, 0 ) ) < 0 )
    {
      fprintf(stderr,"Data socket create faild,return.\n");
      return (-1);
    }
  if ( setsockopt( datasock,SOL_SOCKET,SO_REUSEADDR,(char *)&on,sizeof(on) ) < 0
)
    fprintf(stderr,"Data socket reuse failed.\n");

  dataaddr = localaddr;

  dataaddr.sin_port = 0;

  if (bind(datasock, (struct sockaddr *)&dataaddr, sizeof (dataaddr)) < 0)
    {
      fprintf(stderr,"Data socket bind faild,return.\n");
      return(-1);
    }

  len = sizeof (dataaddr);
  if (getsockname(datasock, (struct sockaddr *)&dataaddr, &len) < 0)
    {
      fprintf(stderr,"Data socket getsockname faild,return.\n");
      return(-1);
    }

  if (listen(datasock, 1) < 0)
    {
      fprintf(stderr,"Data socket listen faild,return.\n");
      return(-1);
    }

  a = (char *)&dataaddr.sin_addr;
  p = (char *)&dataaddr.sin_port;
  result = command("PORT %d,%d,%d,%d,%d,%d",UC(a[0]), UC(a[1]), UC(a[2]), UC(a[3
]),UC(p[0]), UC(p[1]));

  if ( result == ERROR )
    {
      fprintf(stderr,"Send PORT command faild,return.\n");
      return(-1);
    }

  return(0);
}


FILE * dataconn(const char *lmode)
{
  struct sockaddr_in from;
  int s;
  socklen_t fromlen = sizeof(from);

  s = accept(datasock, (struct sockaddr *) &from, &fromlen);
  if (s < 0)
    {
      fprintf(stderr,"Data socket accept failed,exit.\n");
      (void) close(datasock), datasock = -1;
     return (NULL);
    }
  (void) close(datasock);
  datasock = s;

  return (fdopen(datasock, lmode));
}


int cd(char *dir)
{
  if ( command("CWD %s", dir) == ERROR )
    {
      fprintf(stderr,"\nCan't cd directory %s\n",dir);
      return -1;
    }
  return 0;
}

void gotoneitem(int level,int dir,int begin,char *name)
{
  prnvertline(level);
  fprintf(lfp,"%s","--[");
  if ( bbs )
    fprintf(lfp,"%c%c",ESC,ESC);
  if ( dir )
    {
      if ( bbs )
    fprintf(lfp,"%s",YELLOW);
      if ( begin )
    fprintf(lfp,"%s","目录开始");
      else
    fprintf(lfp,"%s","目录结束");
    }
  else
    {
      if ( bbs )
    fprintf(lfp,"%s",GREEN);
      fprintf(lfp,"%s","文件");
    }
  if ( bbs )
    {
      fprintf(lfp,"%c%c",ESC,ESC);
      fprintf(lfp,"%s",WHITE);
    }
  fprintf(lfp,"%c%s\n",']',name);
}

void prnvertline(int level)
{
  int i;
  for ( i=1;i<=level;i++ )
    fprintf(lfp,"%*c",i==1?1:3,'|');
}

void usage(char *prgname)
{
  fprintf(stderr,"Usage:\t%s [-hupdflb] <host>\n",prgname);
  fprintf(stderr,"\t-h   print this help infomation\n");
  fprintf(stderr,"\t-u   ftp user name (default anonymous)\n");
  fprintf(stderr,"\t-p   ftp passwd (default ysqcn@263.net)\n");
  fprintf(stderr,"\t-d   start directory (default /)\n");
  fprintf(stderr,"\t-f   file name to save the result (default -)\n");
  fprintf(stderr,"\t-l   the depth of Subdirectory (default 5)\n");
  fprintf(stderr,"\t-b   output file will be pasted on bbs ? (default no)\n");
  fprintf(stderr,"\thost ftp server name\n");
}




--
※ 修改:·ysqcn 於 09月18日23:31:13 修改本文·[FROM: 211.69.197.81]
※ 来源:.UNIX编程WWW apue.dhs.org. [FROM: 211.69.197.81]
--
※ 修改:·ysqcn 於 09月18日23:38:23 修改本文·[FROM: 211.69.197.81]
※ 来源:·UNIX编程 www.tiaozhan.com/unixbbs/·[FROM: 211.69.197.81]
--
※ 转寄:·UNIX编程 apue.dhs.org·[FROM: 210.39.3.50]
--
※ 转载:·荔园晨风BBS站 bbs.szu.edu.cn·[FROM: 192.168.0.146]


[回到开始] [上一篇][下一篇]

荔园在线首页 友情链接:深圳大学 深大招生 荔园晨风BBS S-Term软件 网络书店