collect.c源码


#include "parker.h"
#include "collect.h"

char ReplyCode[4];
char Line[MAX];
char WorkDir[MAX];
union InAddr
{
  long addr;
  char bytes[SIZEOFINETADDR];
}
myaddr;  // @info union类型的地址?
struct filestatist
{
  int files;
  int rms;
  int mp3;
  int exefiles;
  int linuxfiles;
};
struct ftpsite site;  // 这个ftp变量定义在这里,是全局变量。parker不支持对多个ftp的并发操作?
char machine[MAX];

FILE *CtlIn, *CtlOut;   // @marble 分别作为输入通道和输出通道,具体什么作用? WaitCon等地方会用到。  这两个文件指针在哪里初始化的?
struct sockaddr_in sa;  // @info,是一个Socket连接相关的全局变量,这个是Linux里面的结构体吗?

// 这个Alarm函数有什么作用,退出的代码还是101?
void Alarm (void)
{
  printf ("\007'%s' received ALARM !\n", machine);
  exit (101);
}

// 创建临时文件,那个.fm文件就是用这个函数产生的吗?
char * TempFile (char *dir, char *prfx)
{
  int fd;
  static char fn[MAX];  // @concept 这个变量为什么定义为static?
  sprintf (fn, "%s/%sXXXXXX", dir, prfx); // 这个文件名中有斜杠? @debug
  if ((fd = mkstemp (fn)) == -1)  //  @linux mkstemp函数,创建临时文件
	  perror("mkstemp");  // 如果创建文件失败,会报错
  close(fd);                   // @linux 关闭文件描述符,不是使用C中的文件指针?
  return (fn);
}


// 获得密码后,等待返回码
// d中存放当前路径
int GetPwd (char *d)
{
  char *ptr;
  fprintf (CtlOut, "PWD\r\n");
  while (1)
    {
      fgets (Line, MAX, CtlIn);  // Line又是前面定义的一个全局数组
      if (feof (CtlIn))
	return (S_CLOSED);

#ifdef DEBUG
      printf ("%s", Line);

#endif /*  */
      if (Line[3] == '-')
	continue;
      if (!strncmp (Line, PWD, strlen (PWD)))
	{
	  ptr = Line;
	  while (ptr++)
	    if (*ptr == '\"')
	      break;

	    else if (*ptr == ':')
	      {
		ptr++;
		break;
	      }

	    else if (!*ptr)
	      return (S_ERROR);
	  strcpy (d, ptr + 1);
	  if ((ptr = strchr (d, '\"')))
	    *ptr = '\0';

	  else if ((ptr = strchr (d, ':')))
	    *(++ptr) = '\0';
	  DEB (d);
	  return (S_OK);
	}

      else if (*Line == NEGATIVE)
	return (S_ERROR);

      else if (*Line == PRENEGATIVE)
	return (S_ERROR);
    }
}


/* wait if success */
int
WaitSucc (void)
{
  while (1)
    {
      fgets (Line, MAX, CtlIn);
      if (feof (CtlIn))
	return (S_CLOSED);

#ifdef DEBUG
      printf ("%s", Line);

#endif /*  */
      if (Line[3] == '-')
	continue;
      if (!strncmp (Line, SUCCESS, strlen (SUCCESS)))
	return (S_OK);

      else if (*Line == PRENEGATIVE)
	return (S_ERROR);

      else if (*Line == NEGATIVE)
	return (S_ERROR);
    }
}


// 等待ftp服务器的响应
int WaitReply (void)
{
  bzero (ReplyCode, sizeof (ReplyCode)); // ReplyCode是前面定义的数组,bzero是什么函数?
  while (1)
    {
      fgets (Line, MAX, CtlIn);
      if (feof (CtlIn))
	return (S_CLOSED);

#ifdef DEBUG
      printf ("%s", Line);

#endif /*  */
      if (Line[3] == '-')
	continue;
      ReplyCode[0] = Line[0];
      ReplyCode[1] = Line[1];
      ReplyCode[2] = Line[2];
      if (*Line == POSITIVE)
	return (S_OK);		/* POSITIVE = 2 */
      if (*Line == PROCEED)
	return (S_OK);		/* PROCEED = 3 */
      if (*Line == PREPOSITIVE)
	return (S_PREOK);	/* PREPREPOSIVE = 4 */

      else if (*Line == NEGATIVE)
	return (S_ERROR);	/* NEGATIVE = 5 */
    }
}

// char* 指向数组的操作,collect.c里用的很多
int GetHostipStr (char *hostdns, char *hostip)
{
  int i;
  unsigned char IP[4]; // ip4个数字大小正好是0~255
  struct hostent *host;
  if (!(host = gethostbyname (hostdns))) // gethostbyname是Linux的API,返回hostent结构体。。。通过域名获取ip?
    {
      printf ("gethostbyname:%s!\n", hostdns);
      return (S_ERROR);
    }
  for (i = 0; i < 4; i++)
    IP[i] = (host->h_addr[i]);
  // sprintf用来干什么的?
  sprintf (hostip, "%d.%d.%d.%d", IP[0], IP[1], IP[2], IP[3]);
  return (S_OK);
}



// 连接ftp服务,Connect方法要用到这个方法,传入ftp地址
int WaitCon (char *m)
{
  int h, a, port;
  struct hostent *host;
  struct sockaddr_in own_addr;
  socklen_t own_addr_len = sizeof (own_addr);
  // @info 打开socket连接,h为获得的端口号。Socket网络通信是很基础的概念。
  if ((h = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
    {
      perror ("socket");
      return (S_ERROR);
    }
  sa.sin_family = AF_INET;

//  sa.sin_port=htons(FTPPORT);
  port = atoi (site.ftp_port);
  sa.sin_port = htons (port);
  if (!(host = gethostbyname (m)))  // 又获得host地址,如果获得为空,返回错误代码,
    {
      return (S_ERROR);  // S_ERROR在collect.h中定义为-1.
    }
  sa.sin_addr.s_addr = ((struct in_addr *) (host->h_addr))->s_addr;

/*  memcpy(&sa.sin_addr.s_addr,host->h_addr,SIZEOFINETADDR);*/
  if (connect (h, (void *) &sa, sizeof (sa)) < 0)
    {
      perror ("connect");
      return (S_ERROR);
    }
  if ((a = getsockname (h, (struct sockaddr *) &own_addr, &own_addr_len)))
    {
      perror ("getsockname");
      printf ("error here!return %i\n", a);
      return (S_ERROR);
    };
  myaddr.addr = own_addr.sin_addr.s_addr;

  if (CtlIn)
    fclose (CtlIn);
  if (CtlOut)
    fclose (CtlOut);
  if (!(CtlIn = fdopen (h, "r")))  // marble h是一个Socket端口号,可以当文件打开,在Windows中怎么做类似操作。也是把Socket作为文件打开吗? 读的方式打开
    {
      perror ("fdopen(CtlIn)");  // @info 文件打开失败,异常代码102,为什么使用这种异常代码?
      exit (102);
    }
  if (!(CtlOut = fdopen (h, "w")))  // @marble,同一个Socket端口,可以用两个文件指针打开? 不过这个是写操作。。。
    {
      perror ("fdopen(CtlOut)");
      exit (103);
    }
  setbuf (CtlIn, NULL);
  setbuf (CtlOut, NULL);
  return (S_OK);
}


// 替换字符串,把\全部替换成/,什么作用?
void ConvertBS (char *p)
{
  while (*p)
    {
      if (*p == '\\')
	*p = '/';
      p++;
    }
}


// 连接ftp服务器,p为ftp域名
int Connect (char *p)
{
  if (WaitCon (p) != S_OK)
    return (S_ERROR);
  if (WaitReply () != S_OK)
    return (S_ERROR);
  // 往Socket写东西?
  fprintf (CtlOut, "USER %s\r\n", site.ftp_user);
  if (WaitReply () != S_OK)
    return (S_ERROR);
  if (!strcmp (ReplyCode, "331"))
    {
      // 往Socket写密码?
      fprintf (CtlOut, "PASS %s\r\n", site.ftp_pass);
      // @process 检查ftp服务器的响应
      if (WaitReply () != S_OK)
	return (S_ERROR);
    }
  // @process 登录成功
  DEB ("Logged in");
  return (S_OK);
}


/* judge if the string is month */
int IsMonth (char *p)
{
  int i;
  static char *m[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug",
    "Sep", "Oct", "Nov", "Dec", NULL
  };  // 相当于一个二维数组?
  for (i = 0; i < 12; i++)
    if (!strncasecmp (p, m[i], 3))  // @linux 比较两个字符串的前n个字符,忽略大小写
      return (S_OK);
  return (S_ERROR);
}


// 替换字符/为\
void ConcStr (char *s, char *r)
{
  char *ptr, str[2];
  str[1] = 0;  // strcat时用到,一个字符一个字符地处理
  ptr = r;
  while (*ptr)
    {
      if (*ptr == '/')
	strcat (s, "\\");
      str[0] = *ptr;  // @ques 这里是否需要加一个else啊?这个方法没有被调用到?
      strcat (s, str);  
      ptr++;
    }
}


// 处理目录显示格式
int DoFormat (char *topdir, char *infile, char *outfile,
	  struct filestatist *files)
{
  FILE *fin, *fout;
  char *ppdate = NULL, *ppsize = NULL, *ppfilename = NULL;
  char *ptr, *ppt;
  char unifn[MAX];
  int i;
  int IsDir = 0;
  DEB (outfile);
  files->exefiles = 0;
  files->files = 0;
  files->linuxfiles = 0;
  files->mp3 = 0;
  files->rms = 0;
  if (!(fin = fopen (infile, "r")))
    {
      perror ("fopen in error in DoFormat");
      return (S_ERROR);
    }
  if (!(fout = fopen (outfile, "w")))
    {
      perror ("fopen out error in DoFormat");
      return (S_ERROR);
    }
  fprintf (fout, "%s\n", topdir);
  while (!feof (fin))
    {
      fgets (Line, MAX, fin);
      if ((ptr = strchr (Line, CR)) != NULL)
	*ptr = '\0';
      if ((ptr = strchr (Line, LF)) != NULL)
	*ptr = '\0';
      if (!strcmp (Line, ".:"))
	continue;
      if (!strncmp (Line, "total ", 6))
	continue;
      ptr = Line;
      if (*ptr == '/')
	ptr++;
      if (!strncmp (ptr, "./", 2))
	ptr = ptr + 2;
      i = strlen (ptr);
      ppt = ptr + i - 1;
      if (*ppt == ':')
	{
	  if (*ptr == '.' && *(ptr + 1) == '\\')
	    ptr = ptr + 2;
	  *ppt = '/';
	  *(ppt + 1) = '\0';
	  ConvertBS (ptr);
	  i = 0;
	  while (ptr && i < MAX)
	    {
	      if (*ptr == ' ')
		{
		  strcpy (&unifn[i], "%20");
		  i = i + 3;
		  ptr++;
		}
	      else
		{
		  unifn[i] = *ptr;
		  i++;
		  ptr++;
		}
	    }
	  unifn[i] = '\0';
	  fprintf (fout, "%s%s\n", topdir, unifn);
	  continue;
	}
      if (Line[0] == 'l' && (strstr (Line, " -> ")) != NULL)
	{

	  /* unix link file handler */
	  continue;
	}

      else if (*Line <= '9' && *Line >= '0')
	{

	  /* DOS dir list handler */
	  /* format :
	     06-14-00  09:42PM                 2394 1.htm
	     06-14-00  09:42PM        <DIR>         DESKTOP
	   */
	  ppdate = Line;
	  ptr = strchr (Line, ' ');
	  if (!ptr)
	    continue;
	  while (*ptr == ' ')
	    if (*ptr == '\0')
	      continue;

	    else
	      *ptr++ = '_';
	  ptr = strchr (ptr, ' ');
	  if (!ptr)
	    continue;
	  *ptr++ = '\0';
	  while (*ptr && *ptr == ' ')
	    ptr++;
	  if (*ptr == '\0')
	    continue;
	  if (!strncmp (ptr, "<DIR>", 5))
	    {
	      IsDir = 1;
	      ppsize = NULL;
	    }
	  else
	    {
	      IsDir = 0;
	      ppsize = ptr;
	    }
	  ptr = strchr (ptr + 1, ' ');
	  if (!ptr)
	    continue;
	  *ptr++ = '\0';
	  while (*ptr && *ptr == ' ')
	    ptr++;
	  if (*ptr == '\0')
	    continue;
	  ppfilename = ptr;
	}

      else if (*Line == 'd' || *Line == '-')
	{

	  /* unix dir list handler */
	  /* format :
	     -rwxrw-rw- 1 root  root   423421 Aug  7  1999 setup.exe
	     drwxrw-rw- 1 root  root        0 Aug 22 15:34 DIR
	   */
	  if (*Line == 'd')
	    IsDir = 1;

	  else
	    IsDir = 0;
	  ptr = Line;
	  for (i = 0; i < 4 && ptr; i++)
	    {
	      ptr = strchr (ptr, ' ');
	      if (!ptr)
		continue;
	      while (*ptr == ' ')
		*ptr++ = '\0';
	    }
	  if (!ptr)
	    continue;
	  ppsize = ptr;
	  ptr = strchr (ptr, ' ');
	  if (!ptr)
	    continue;
	  while (*ptr == ' ')
	    *ptr++ = '\0';
	  ppdate = ptr;
	  for (i = 0; i < 2 && ptr; i++)
	    {
	      ptr = strchr (ptr, ' ');
	      if (!ptr)
		continue;
	      while (*ptr == ' ')
		*ptr++ = '_';
	    }
	  ptr = strchr (ptr, ' ');
	  if (!ptr)
	    continue;
	  while (*ptr == ' ')
	    ptr++;
	  *(ptr - 1) = '\0';
	  ppfilename = ptr;
	  if ((ptr = strchr (ppfilename, '*')))
	    *ptr = '\0';
	}
      else
	continue;
      if (strstr (ppfilename, ".RM") || strstr (ppfilename, ".rm")
	  || strstr (ppfilename, ".mov")
	  || strstr (ppfilename, ".avi")
	  || strstr (ppfilename, ".AVI")
	  || strstr (ppfilename, ".mpg")
	  || strstr (ppfilename, ".wmv") || strstr (ppfilename, ".MOV"))
	files->rms++;

      else if (strstr (ppfilename, ".MP3")
	       || strstr (ppfilename, ".mp3")
	       || strstr (ppfilename, ".wma")
	       || strstr (ppfilename, ".WMA")
	       || strstr (ppfilename, ".mpga") || strstr (ppfilename, ".mid"))
	files->mp3++;

      else if (strstr (ppfilename, ".EXE")
	       || strstr (ppfilename, ".exe")
	       || strstr (ppfilename, ".zip")
	       || strstr (ppfilename, ".rar") || strstr (ppfilename, ".ZIP"))
	files->exefiles++;

      else if (strstr (ppfilename, ".rpm")
	       || strstr (ppfilename, ".deb")
	       || strstr (ppfilename, ".RPM")
	       || strstr (ppfilename, ".tar")
	       || strstr (ppfilename, ".bz2")
	       || strstr (ppfilename, ".tgz") || strstr (ppfilename, ".gz"))
	files->linuxfiles++;
      files->files++;
      i = 0;
      ptr = ppfilename;
      while (ptr && i < MAX)
	{
	  if (*ptr == ' ')
	    {
	      strcpy (&unifn[i], "%20");
	      i = i + 3;
	      ptr++;
	    }
	  else
	    {
	      unifn[i] = *ptr;
	      i++;
	      ptr++;
	    }
	  if (*ptr == '\0')
	    break;
	}
      if (IsDir != 0)
	{
	  unifn[i] = '/';
	  i++;
	}
      unifn[i] = '\0';
      if (IsDir)
	fprintf (fout, "%s 0 %s\n", unifn, ppdate);

      else
	fprintf (fout, "%s %s %s\n", unifn, ppsize, ppdate);
      continue;
    }
  fclose (fout);
  fclose (fin);
  return (files->files);
}


// DoLISTlR,DRecursive,DoDownload会调用这个方法
// 打开Socket,接收ftp数据。告诉ftp服务器端口,等待响应
/* = 0  LIST */
/* = 1  LIST -lR */
/* = 2  TYPE I, RETR *fn, to get list file *fn */
// 把数据写到outfile中
int QueryDir (char *outfile, char fetchType, char *outfilename)
{
  struct sockaddr_in da;
  int foo;
  int hh;
  int rc;
  int i, s, ns;
  int Port;
  FILE *in, *out;
  char *ptr;
  da = sa;
  da.sin_addr.s_addr = myaddr.addr;
  da.sin_port = 0;
  s = socket (AF_INET, SOCK_STREAM, 0);
  if (s < 0)
    {
      perror ("socket");
      return (S_ERROR);
    }
  foo = sizeof (da);
  while (bind (s, (struct sockaddr *) &da, foo) < 0)
    {
      perror ("bind");
      return (S_ERROR);
    }
  if (getsockname (s, (struct sockaddr *) &da, &foo) < 0)
    {
      perror ("ftp: getsockname");
      return (S_ERROR);
    }
  Port = ntohs (da.sin_port);
  if (listen (s, 1) < 0)
    {
      perror ("listen");
      return (S_ERROR);
    }
  fprintf (CtlOut, "PORT %u,%u,%u,%u,%u,%u\r\n",
	   (unsigned char) myaddr.bytes[0],
	   (unsigned char) myaddr.bytes[1],
	   (unsigned char) myaddr.bytes[2],
	   (unsigned char) myaddr.bytes[3], Port / 256,
	   Port - (unsigned int) (Port / 256) * 256);
  if ((rc = WaitReply ()) == S_OK)
    {
      switch (fetchType)
	{
	case 0:
	  fprintf (CtlOut, "LIST\r\n");
	  break;
	case 1:
	  fprintf (CtlOut, "LIST -lR\r\n");
	  break;
	case 2:
	  fprintf (CtlOut, "TYPE I\r\n");
	  WaitReply ();
	  fprintf (CtlOut, "RETR %s\r\n", outfilename);
	  break;
	default:
	  puts ("Wrong kind of `fetchType' argument in QueryDir");
	  return (S_ERROR);
	}
      if (WaitReply () != S_PREOK)
	return (S_ERROR_INFIMA);
      if ((hh = creat (outfile, MODE)) == -1)
	return (S_ERROR);
      foo = sizeof da;
      ns = accept (s, (struct sockaddr *) &da, &foo);
      if (ns < 0)
	{
	  perror ("accept");
	  return (S_ERROR);
	}
      close (s);
      if (fetchType == 2)
	while (1)
	  {
	    i = read (ns, Line, MAX);
	    if (!i)
	      break;
	    alarm (TIMEOUT);
	    write (hh, Line, i);
	  }

      else
	{
	  if (!(in = fdopen (ns, "r")))
	    {
	      perror ("fdopen in here");
	      exit (0);
	      return (S_ERROR);
	    }
	  if (!(out = fdopen (hh, "w")))
	    {
	      perror ("fdopen out");
	      return (S_ERROR);
	    }
	  while (1)
	    {
	      fgets (Line, MAX, in);
	      if (feof (in))
		break;
	      if ((ptr = strchr (Line, CR)) != NULL)
		*ptr = '\0';
	      if ((ptr = strchr (Line, LF)) != NULL)
		*ptr = '\0';
	      fprintf (out, "%s\n", Line);
	      alarm (TIMEOUT);
	    }
	  fclose (out);
	  fclose (in);
	}
      DEB ("Done with fetching the directory");
      close (ns);
      close (hh);
      rc = WaitSucc ();
    }
  return (rc);
}


/* use QueryDir(use LIST -lR) to get entire dir list */
int DoLISTlR (char *outfile)
{
  int rc;
  fprintf (CtlOut, "CWD %s\r\n", "/");
  rc = WaitReply ();
  if (rc == S_CLOSED)
    {
      DEB ("Connection closed!!!");
      return (S_ERROR);
    }
  rc = QueryDir (outfile, 1, NULL);
  DEB ("Done with List-lR");
  return (rc);
}


/* use recursive LIST to get the entire directory list */
int DoRecursive (char *topdir, FILE * res)
{
  char *ptr;
  char tmpfn[MAX], tmpstr[MAX];
  FILE *dirf;
  int rc, i;
  fprintf (CtlOut, "CWD %s\r\n", topdir);
  rc = WaitReply ();
  if (rc == S_CLOSED)
    {
      DEB ("Connection closed!!!");
      return (S_ERROR);
    }
  GetPwd (tmpstr);
  if (strcmp (topdir, tmpstr))
    return (S_ERROR);
  ConvertBS (topdir);
  strcpy (tmpfn, TempFile (WorkDir, "Dir"));
  rc = QueryDir (tmpfn, 0, NULL);
  if (rc != S_ERROR_INFIMA)
    printf ("%s:%s\n", machine, topdir);

  else
    {
      rc = S_OK;
      printf ("%s:%s - Major BBS Bug\n", machine, topdir);
    }
  if (!(dirf = fopen (tmpfn, "r")))
    {
      unlink (tmpfn);
      return (S_ERROR);
    }
  if (strcmp (topdir, "/"))
    fprintf (res, "%s:\n", topdir);
  while (1)
    {
      fgets (Line, MAX, dirf);
      if (feof (dirf))
	break;
      fputs (Line, res);
    }
  rewind (dirf);
  while (rc == S_OK)
    {
      fgets (Line, MAX, dirf);
      if (feof (dirf))
	{
	  rc = S_OK;
	  break;
	}
      if ((ptr = strchr (Line, CR)) != NULL)
	*ptr = '\0';
      if ((ptr = strchr (Line, LF)) != NULL)
	*ptr = '\0';
      if (1)
	{
	  DEB (Line);
	  if (*Line == 'l' && strstr (Line, " -> "))
	    continue;
	  if (*Line == 'd')
	    {
	      i = 1;
	      ptr = Line;
	      while (i < 9 && ptr)
		{
		  ptr = strchr (ptr, ' ');
		  if (ptr)
		    {
		      while (*ptr == ' ' && ptr)
			{
			  ptr++;
			}
		    }
		  i++;
		}
	    }
	  else if ((ptr = strstr (Line, "<DIR>")))
	    {
	      ptr = ptr + 5;
	      while (*ptr == ' ' && ptr)
		ptr++;
	    }

	  else
	    continue;
	  strcpy (tmpstr, topdir);
	  if (tmpstr[strlen (tmpstr) - 1] != '/')
	    strcat (tmpstr, "/");
	  strcat (tmpstr, ptr);
	  DEB (tmpstr);
	  rc = DoRecursive (tmpstr, res);
	  if (rc != S_OK)
	    {
	      DEB ("DoLookup returned an error");
	      rc = 0;
	    }
	}
    }
  fclose (dirf);
  unlink (tmpfn);
  return (rc);
}


/* use QueryDir(download the list file like list-lR.gz ) to get entire dir list */
int
DoDownload (char *outfile, char *topdir)
{
  char newdir[MAX];
  int i;
  char tmpfn[MAX];
  int rc;
  char command[MAX];
  struct path
  {
    char *path, *file;
  };
  struct path Lists[7];
  Lists[0] = (struct path)
  {
  "/", "ls-lR.gz"};
  Lists[1] = (struct path)
  {
  "/", "ls-lR.Z"};
  Lists[2] = (struct path)
  {
  "/", "ls-lR"};
  Lists[3] = (struct path)
  {
  "/pub/", "ls-lR.gz"};
  Lists[4] = (struct path)
  {
  "/pub/", "ls-lR.Z"};
  Lists[5] = (struct path)
  {
  "/pub/", "ls-lR"};
  Lists[6] = (struct path)
  {
  NULL, NULL};
  rc = 0;
  strcpy (tmpfn, TempFile (WorkDir, "Down"));
  for (i = 0; Lists[i].path; i++)
    {
      fprintf (CtlOut, "CWD %s\r\n", Lists[i].path);
      rc = WaitReply ();
      if (rc == S_CLOSED)
	{
	  DEB ("Connection closed!!!");
	  exit (111);
	}

      else if (rc != S_OK)
	continue;
      GetPwd (newdir);
      ConvertBS (newdir);
      if ((rc = QueryDir (tmpfn, 2, Lists[i].file)) == S_OK)
	break;
    }
  if (Lists[i].path)
    {
      sprintf (command, "%s:%s Fetched %s%s\n", machine, topdir,
	       Lists[i].path, Lists[i].file);
      DEB (command);
      if (toupper (Lists[i].file[strlen (Lists[i].file) - 1]) == 'Z')
	{
	  DEB ("Uncompressing");
	  strcpy (command, MV);
	  strcat (command, " ");
	  strcat (command, tmpfn);
	  strcat (command, " ");
	  strcat (command, outfile);
	  strcat (command, ".gz");
	  system (command);
	  strcpy (command, GUNZIP);
	  strcat (command, " ");
	  strcat (command, outfile);
	  system (command);
	}
      else
	{
	  strcpy (command, MV);
	  strcat (command, " ");
	  strcat (command, tmpfn);
	  strcat (command, " ");
	  strcat (command, outfile);
	  system (command);
	}
    }

  else
    {
      DEB ("Giving up remote ls-lR files...");
      unlink (tmpfn);
    }
  return (rc);
}


// 尝试所有方式来获取列表,通过递归方式进行吗?
int Probe (char *outputdir, char TypeOfFetch)
{
  int rc;			// 返回代码
  FILE *res = NULL;
  char tempfile[MAX];
  char resfile[MAX];
  char command[MAX];
  char TopDir[MAX];        // ftp顶层目录
  char HostIP[MAX];
  char URL[MAX];
  struct filestatist files;  // filestatist定义在collect.c开头
  GetHostipStr (machine, HostIP);  // 把值写到HostIP数组?通过域名获取IP,然后把IP sprintf到HostIP数组(不用sprintf也可以做到的,直接赋值)
  sprintf (resfile, "%s/%s.org", WorkDir, HostIP);  // WorkDir又是全局变量
  DEB ("Probe");  // DEB是一个宏,定义在collect.h中。
  alarm (TIMEOUT);
  if (Connect (machine) != S_OK)
    {
      DEB ("Couldn't connect");
      return (S_ERROR);
    }
  strcpy (TopDir, "/");
  if (TypeOfFetch == 'd')
    {
      rc = DoDownload (resfile, TopDir);
    }
  else if (TypeOfFetch == 'l')
    {
      rc = DoLISTlR (resfile);
    }
  else if (TypeOfFetch == 'r')
    {
      res = fopen (resfile, "w");
      rc = DoRecursive (TopDir, res);
      fclose (res);
    }
  else
    if ((rc = DoLISTlR (resfile)) != S_OK
	&& ((rc = DoDownload (resfile, TopDir)) != S_OK))
    {
      DEB ("use Recursive Look up");
      res = fopen (resfile, "w");
      if ((rc = DoRecursive (TopDir, res)) != S_OK)
	return (S_ERROR);
      fclose (res);
    }
  if (rc != S_OK)
    return (S_ERROR);
  alarm (0);
  sprintf (tempfile, "%s/%s.fmt", WorkDir, HostIP);
  DoFormat (TopDir, resfile, tempfile, &files);

// For debug usage.
// printf("port: %s\n user: %s\n pass: %s\n name: %s\n hostip: %s\n",site.ftp_port,site.ftp_user,site.ftp_pass,site.ftp_name,
// HostIP);
// exit(0);
//patched by Sunry Chen 2006-02-22
  if (strcasecmp(site.ftp_user,"ANONYMOUS"))
  {
    strcat(URL,site.ftp_user);
    strcat(URL,":");
    strcat(URL,site.ftp_pass);
    strcat(URL,"@");
  }
  strcat(URL,HostIP);
  printf("--- URL: %s\n",URL);

  sprintf (command, "%s/%s/%s %s %s/%s -s", PARKER_HOME, BINDIR,
//	   LZOCOMP, tempfile, outputdir, HostIP);
	LZOCOMP, tempfile, outputdir, URL);
  system (command);
  unlink (resfile);
  unlink (tempfile);
  sprintf (resfile, "%s/%s/%s.%s", PARKER_HOME, HOSTDATADIR, HostIP,
	   HOSTINFOEXT);
  res = fopen (resfile, "w");
  fprintf (res, "%s %s %d %d %d %d %d\n", machine, HostIP,
	   files.files, files.rms, files.mp3, files.exefiles,
	   files.linuxfiles);
  fclose (res);
  DEB ("Done with Probe");
  return (rc);
}

// 支持多种ftp列表格式,整个过程实际上就是设置了site的值

void scanline (char line[])
{
  char *scan, *at, *colon;
  site.ftp_name[0]='\0';  // 初始化site结构体成员变量
  site.ftp_port[0]='\0';
  site.ftp_user[0]='\0';
  site.ftp_pass[0]='\0';
  if ((scan = strchr (line, CR)) != NULL)  // 是宏,定义在parker.h中,CR是13,LF是10(这两个东西和换行有关系,检查line[]里面的字符,看是否有这种换行符,如果有的话,scan就指向 空地址,这有什么用吗?)
	  *scan = '\0';
  if ((scan = strchr (line, LF)) != NULL)  // strchr,如果找不到指定字符,就返回空指针。 LF, CR这两个名称,在ASCII表中就有定义,是比较特殊的两个字符。
	  *scan = '\0';
  scan = strstr (line, "ftp://"); // 检查line,指向第一个ftp://字符串,如果line中没有ftp://字符串,scan为空
  if (!scan)
    scan = line; // 表明line没有ftp://前缀,scan直接等于line字符串。
  else
    scan = line + 6;  // 或者跳过前面的ftp://前缀,scan里面不能有ftp://前缀
  at = strchr (scan, '@');  // line中ftp://前缀已经被去掉,返回出现@的位置
  colon = strchr (scan, ':'); // 返回出现:的地方,用于提取用户名@密码:地址?
  if (!at)
    {
      if (colon)
	{
	  *colon = '\0';  // 没有@,表明:后面就是端口号了。为什么把:置为\0呢,之后计算只用到前面的串了吗?
	  colon++;
	  strcpy (site.ftp_port, colon); // 获取端口号
	}
      strcpy (site.ftp_name, scan); // 直接把ftp名称拷贝过来,因为:已经被置为\0
      strcpy (machine, site.ftp_name);
    }
  else if (at != NULL)
    {
      *at = '\0';
      at++;
      if (colon && colon < at)
	{
	  *colon = '\0';
	  colon++;
	  strcpy (site.ftp_pass, colon);
	}
      strcpy (site.ftp_user, scan);  // 冒号意见那个被设置为\0
      colon = strchr (at, ':');
      if (colon)
	{
	  *colon = '\0';
	  colon++;
	  strcpy (site.ftp_port, colon);
	}
      strcpy (site.ftp_name, at);
      strcpy (machine, site.ftp_name);
    }
  if (site.ftp_port[0] == '\0')
    strcpy (site.ftp_port, "21");  // 默认端口21
  if (site.ftp_user[0] == '\0')
  {
    strcpy (site.ftp_user, ANONYMOUS);  // 默认使用匿名登录
    strcpy (site.ftp_pass, ANONYPASS);
  }
}

int main (int n, char *p[])
{
  char LZODir[MAX];
  char TypeOfFetch = ' ';
  int child;
  int hostnum;
  FILE *hostListRes;
  if (n > 3)
    {
      printf ("USAGE: collect\n");
      printf ("       collect [-d|-l|-r] [destination ftp host]\n");
      printf ("      -d download the list file like ls-lR.tgz \n");
      printf ("      -l use \"LIST -lR\" \n");
      printf ("      -r use recursive \"LIST\" to get the entire dir \n");
      return (0);
    }
  nice (PARKER_NICE);  // @info 设定进程的优先级?
  signal (SIGALRM, (void (*)(int)) Alarm);  // @info 前面定义的Alarm函数用到这里,用于发送信号?
  sprintf (WorkDir, "%s/%s", PARKER_HOME, WORKDIR);
  sprintf (LZODir, "%s/%s", PARKER_HOME, LZOFILEDATADIR);
  hostnum = 0;
  if (n > 1 && *p[1] == '-')
    TypeOfFetch = p[1][1];
  if (n == 3 || (n == 2 && *p[1] != '-'))
    {
      if (n == 3)
	strcpy (machine, p[2]);

      else
	strcpy (machine, p[1]);
      strcpy (site.ftp_port, "21");
      strcpy (site.ftp_user, ANONYMOUS);
      strcpy (site.ftp_pass, ANONYPASS);
      if (Probe (LZODir, TypeOfFetch) != S_OK)
	printf ("Cannot get the ftp data on host  %s.\n", machine);
    }

  else
    {				/*  use default collect host list */
      strcpy (Line, HOSTLIST);
      if (!(hostListRes = fopen (Line, "r")))
	{
	  printf ("Can't open Collect list file: %s\n", Line);
	  return 0;
	}
      while (1)
	{
	  fgets (Line, MAX, hostListRes);
	  if (feof (hostListRes))
	    break;
	  while ((child = fork ()) == -1)
	    sleep (1);
	  if (!child)
	    {
//                              strcpy(machine, Line);
	      scanline (Line);
	      Probe (LZODir, TypeOfFetch);
	      exit (0);
	    }

	  else
	    {
	      hostnum++;
	      sleep (5);
	      if (hostnum >= MAXAGENTS)
		{
		  wait (&child);
		  hostnum--;
		}
	    }
	}
      fclose (hostListRes);
      while (hostnum--)
	wait (&child);
    }
  return 0;
}




1、怎么只认一个ftp,CollectList是从哪里开始读入的?
2、collect过程中生成了如下文件/var/parker/tmp/xxx.fmt,但是之后又被删除了。
/var/parker/LZOData/xxx 在LZOData目录下又生成了一个文件,但是不大,我看到的大小怎么只有8K,一个很大的ftp站点,难道就这么写内容?居然还显示是个 二进制文件,是压缩过的索引?
3、把数组的前length个字节清零,可以直接用char* for实现,也可以用memset实现,这种函数没咋用过啊。像bzero(不是bezero。。)这种函数,在做嵌入式时,可能需要自己重新实现这些方法?

你可能感兴趣的:(C++,c,linux,socket,C#)