ftp.c

来自「网络爬虫程序」· C语言 代码 · 共 2,200 行 · 第 1/4 页

C
2,200
字号
  if(!docp->ftp_control)  {    if(priv_cfg.ftp_proxy && cfg.ftp_dirtyp)    {      if(!(docp->datasock =          bufio_sock_fdopen(net_connect(priv_cfg.ftp_proxy,              cfg.ftp_proxy_port, docp))))      {        if(_h_errno_ != 0)          xherror(priv_cfg.ftp_proxy);        else          xperror("net_connect");        docp->errcode = ERR_PROXY_CONNECT;        return NULL;      }      if(http_dumy_proxy_connect(docp, host, port, priv_cfg.ftp_proxy,          cfg.ftp_proxy_port))      {        docp->errcode = ERR_PROXY_CONNECT;        return NULL;      }      docp->ftp_control = docp->datasock;      docp->datasock = NULL;    }    else    {      if(!(docp->ftp_control =          bufio_sock_fdopen(net_connect(host, port, docp))))      {        if(_h_errno_ != 0)          xherror(host);        else          xperror("net_connect");        docp->errcode = ERR_FTP_CONNECT;        docp->ftp_fatal_err = TRUE;        return NULL;      }    }    if(ftp_get_response(docp, NULL, TRUE) >= 400)    {      CLOSE_CONTROL;      docp->ftp_fatal_err = TRUE;      docp->errcode = ERR_FTP_CONNECT;      return NULL;    }#ifdef USE_SSL    if(docp->doc_url->type == URLT_FTPS)    {      char buf[2048];      int reply;      bufio *ssl_sock;      sprintf(buf, "AUTH SSL\r\n");      ftp_control_write(docp, buf, strlen(buf));      DEBUG_PROTOC("%s", buf);      reply = ftp_get_response(docp, NULL, TRUE);      /*** 234 code is used by SafeGossip ***/      /*** thank to Martijn ...           ***/      if(reply != 334 && reply != 234)      {        CLOSE_CONTROL;        docp->ftp_fatal_err = (reply == 600);        docp->errcode = ERR_FTPS_UNSUPORTED;        return NULL;      }      ssl_sock = my_ssl_do_connect(docp, docp->ftp_control, NULL);      if(!ssl_sock)      {        if(!docp->errcode)          docp->errcode = ERR_FTPS_CONNECT;        CLOSE_CONTROL;        return NULL;      }      else      {        docp->ftp_control = ssl_sock;      }    }#endif    if(ftp_do_login_handshake(docp, ruser, user, password))    {      CLOSE_CONTROL;      return NULL;    }#ifdef IP_TOS#ifdef IPTOS_LOWDELAY    if(docp->ftp_control)    {      int v = IPTOS_LOWDELAY;      if(setsockopt(bufio_getfd(docp->ftp_control),          IPPROTO_IP, IP_TOS, (char *) &v, sizeof(v)))      {        perror("ftp: setsockopt TOS - LOWDELAY failed");      }    }#endif#endif  }#ifdef DEBUG  else  {    if(cfg.debug)      xprintf(1, gettext("Re-using established FTP control connection\n"));  }#endif  return docp->ftp_control;}static int ftp_set_transfer_type(doc * docp, char *type){  char buf[20];  int reply;  snprintf(buf, sizeof(buf), "TYPE %s\r\n", type);  ftp_control_write(docp, buf, strlen(buf));  DEBUG_PROTOC("%s", buf);  if((reply = ftp_get_response(docp, NULL, TRUE)) >= 400)  {    CLOSE_CONTROL;    docp->ftp_fatal_err = (reply == 600);    docp->errcode = ERR_FTP_UNKNOWN;    return -1;  }  return 0;}static int ftp_send_list_command(doc * docp, char *filename){  char buf[2148];  int l;  l = strlen(filename) - 1;  if(l)  {    if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))      l--;  }  if(cfg.ftp_list)    strcpy(buf, "LIST");  else    strcpy(buf, "NLST");  if(cfg.ftp_list_options)  {    strcat(buf, " ");    strncat(buf, cfg.ftp_list_options, sizeof(buf) - strlen(buf));    buf[sizeof(buf) - 1] = '\0';  }  if(l)  {    strncat(buf, " ", sizeof(buf) - strlen(buf));    buf[sizeof(buf) - 1] = '\0';    strncat(buf, filename + 1, sizeof(buf) - strlen(buf));    buf[sizeof(buf) - 1] = '\0';  }  strncat(buf, "\r\n", sizeof(buf) - strlen(buf));  buf[sizeof(buf) - 1] = '\0';  ftp_control_write(docp, buf, strlen(buf));  DEBUG_PROTOC("%s", buf);  return 0;}static int ftp_check_directory_existence(doc * docp, char *filename){  int rv = 0;  if(cfg.ftp_list && cfg.fix_wuftpd)  {    int l;    char buf[2148];    char *mbuf;    l = strlen(filename) - 1;    if(l)    {      if(tl_is_dirname(filename + 1) && strcmp(filename, "//"))        l--;    }    strcpy(buf, "STAT -d1 ");    if(l)    {      strncat(buf, filename + 1, sizeof(buf) - strlen(buf));      buf[sizeof(buf) - 1] = '\0';      strncat(buf, "\r\n", sizeof(buf) - strlen(buf));      buf[sizeof(buf) - 1] = '\0';    }    else    {      /* we can assume that login directory exists */      return 0;    }    ftp_control_write(docp, buf, strlen(buf));    DEBUG_PROTOC("%s", buf);    mbuf = NULL;    if(ftp_get_response(docp, &mbuf, TRUE) == 213)    {      char *p;      p = mbuf + strcspn(mbuf, "\r\n");      p += strspn(p, "\r\n");      if(strncmp(filename + 1, p, strcspn(p, "\r\n")))        rv = -1;    }    _free(mbuf);  }  return rv;}/****************************************************************//* otvorenie spojenia na FTP server, prihlasenie + zahajenie    *//* prenosu suboru / adresara                                    *//* FIXME: Translate me!                                         *//****************************************************************/static bufio *ftp_connect(doc * docp, char *host, int port, char *ruser,  char *user, char *password, char *filename, bool_t * is_dir){  char buf[2148];  int reply;  char *mbuf;  docp->errcode = ERR_NOERROR;  docp->ftp_fatal_err = FALSE;  docp->ftp_respc = 0;  if(!(docp->ftp_control =      ftp_open_control_connection(docp, host, port, ruser, user, password)))    return NULL;  if(!tl_is_dirname(filename) && cfg.mode != MODE_FTPDIR)  {    if(docp->doc_url->extension &&      ((ftp_url_extension *) docp->doc_url->extension)->size > 0)    {      docp->totsz = ((ftp_url_extension *) docp->doc_url->extension)->size;      reply = 213;      DEBUG_PROTOC("taking stored size\n");    }    else    {      snprintf(buf, sizeof(buf), "SIZE %s\r\n", filename + 1);      ftp_control_write(docp, buf, strlen(buf));      DEBUG_PROTOC("%s", buf);      mbuf = NULL;      if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)      {        int sz;        sscanf(mbuf, "%d %d", &reply, &sz);        docp->totsz = sz;      }      else      {        if(reply == 600)        {          docp->errcode = ERR_READ;          docp->ftp_fatal_err = TRUE;          _free(mbuf);          return NULL;        }      }      _free(mbuf);    }    if(reply != 550)  /*** file doesn't exist or not plain file  == 550 ***/    {      if(!cfg.always_mdtm &&        docp->doc_url->extension &&        ((ftp_url_extension *) docp->doc_url->extension)->time != 0)      {        docp->dtime = ((ftp_url_extension *) docp->doc_url->extension)->time;        reply = 213;        DEBUG_PROTOC("taking stored MDTM %d\n", (int)          ((ftp_url_extension *) docp->doc_url->extension)->time);      }      else      {        snprintf(buf, sizeof(buf), "MDTM %s\r\n", filename + 1);        ftp_control_write(docp, buf, strlen(buf));        DEBUG_PROTOC("%s", buf);        mbuf = NULL;        if((reply = ftp_get_response(docp, &mbuf, TRUE)) == 213)        {          sscanf(mbuf, "%d %2147s", &reply, buf);          if(strlen(buf) == 14)          {            docp->dtime = time_ftp_scn(buf);          }        }        else        {          if(reply == 600)          {            docp->ftp_fatal_err = TRUE;            docp->errcode = ERR_READ;            _free(mbuf);            return NULL;          }        }        _free(mbuf);      }      DEBUG_PROTOC("Size: file %d, remote %d; time: file %d, remote %d\n",        docp->origsize, docp->totsz, docp->origtime, docp->dtime);      if(docp->origsize && (docp->totsz >= 0)        && (docp->origsize != docp->totsz))      {        xprintf(1, gettext("Size differs, regeting whole\n"));        docp->rest_pos = 0;      }      else if(docp->origtime && docp->dtime)      {        if((difftime(docp->dtime, docp->origtime) > 0))        {          if(docp->rest_pos)          {            docp->rest_pos = 0;            xprintf(1,              gettext("Modified from last download - regeting whole\n"));          }        }        else if((cfg.mode == MODE_SYNC || cfg.mode == MODE_MIRROR)          && !docp->rest_pos)        {          docp->errcode = ERR_FTP_ACTUAL;          return NULL;        }      }      if(docp->check_limits)      {        cond_info_t condp;        int r;        condp.level = 3;        condp.urlnr = docp->doc_nr;        condp.size = docp->totsz;        condp.time = docp->dtime;        condp.mimet = NULL;        condp.full_tag = NULL;        condp.params = NULL;        condp.html_doc = NULL;        condp.html_doc_offset = 0;        condp.tag = NULL;        condp.attrib = NULL;        r = url_append_condition(docp->doc_url, &condp);        if(!r)        {          switch (condp.reason)          {          case CONDT_MAX_SIZE:            docp->errcode = ERR_BIGGER;            break;          case CONDT_MIN_SIZE:            docp->errcode = ERR_SMALLER;            break;          case CONDT_NEWER_THAN:          case CONDT_OLDER_THAN:            docp->errcode = ERR_OUTTIME;            break;          case CONDT_USER_CONDITION:            docp->errcode = ERR_SCRIPT_DISABLED;            break;          default:            docp->errcode = ERR_RDISABLED;            break;          }          return NULL;        }      }      if(ftp_set_transfer_type(docp, "I"))      {        docp->ftp_fatal_err = TRUE;        docp->errcode = ERR_FTP_DATACON;        return NULL;      }      if(ftp_open_data_init(docp))      {        bufio_close(docp->ftp_control);        docp->ftp_control = NULL;        docp->errcode = ERR_FTP_DATACON;        return NULL;      }      if(docp->rest_pos)      {        char *rsp;        sprintf(buf, "REST %ld\r\n", (long) docp->rest_pos);        ftp_control_write(docp, buf, strlen(buf));        DEBUG_PROTOC("%s", buf);        if((reply = ftp_get_response(docp, &rsp, TRUE)) >= 400)        {          _free(rsp);          if(reply == 600)          {            docp->ftp_fatal_err = TRUE;            bufio_close(docp->datasock);            docp->datasock = NULL;            docp->errcode = ERR_READ;            return NULL;          }          docp->errcode = ERR_FTP_NOREGET;        }        else        {          sprintf(buf, "%ld", (long) docp->rest_pos);          if(!strstr(rsp + 3, buf))          {            xprintf(1,              gettext              ("Warning: FTP server understands REST command, but can't handle it properly.\n"));            docp->errcode = ERR_FTP_NOREGET;          }          _free(rsp);        }      }      snprintf(buf, sizeof(buf), "RETR %s\r\n", filename + 1);      ftp_control_write(docp, buf, strlen(buf));      DEBUG_PROTOC("%s", buf);        /** check control connection if there is available  **/        /** server response. This is required to properly   **/        /** establish support active data connections, also **/        /** in case of error                                **/      if(!cfg.ftp_activec ||        tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)      {        if(!ftp_open_data_finish(docp))        {          docp->ftp_fatal_err = TRUE;          if(!docp->errcode)            docp->errcode = ERR_FTP_DATACON;          return NULL;        }      }      if(!((reply = ftp_get_response(docp, NULL, TRUE)) >= 400))      {        docp->errcode = ERR_NOERROR;        if(!ftp_open_data_finish(docp))        {          docp->ftp_fatal_err = TRUE;          if(!docp->errcode)            docp->errcode = ERR_FTP_DATACON;          return NULL;        }        return docp->datasock;      }      if(reply == 600)      {        docp->ftp_fatal_err = TRUE;        bufio_close(docp->datasock);        docp->datasock = NULL;        docp->errcode = ERR_READ;        return NULL;      }      docp->errcode = ERR_FTP_GET;    }    else    {      docp->errcode = ERR_FTP_GET;    }  }  if(((docp->doc_url->extension &&        ((ftp_url_extension *) docp->doc_url->extension)->type == FTP_TYPE_D)      || !docp->doc_url->extension) && ((docp->check_limits        && cfg.condition.ftpdir) || !docp->check_limits))  {    if(ftp_check_directory_existence(docp, filename))    {      docp->errcode = ERR_FTP_NODIR;      docp->ftp_respc = 550;      if(docp->datasock)      {        bufio_close(docp->datasock);        docp->datasock = NULL;      }      return NULL;    }    if(ftp_set_transfer_type(docp, "A"))    {      return NULL;    }    if(!docp->datasock)    {      if(ftp_open_data_init(docp))      {        bufio_close(docp->ftp_control);        docp->ftp_control = NULL;        docp->errcode = ERR_FTP_DATACON;        return NULL;      }    }    ftp_send_list_command(docp, filename);    /** check control connection if there is available  **/    /** server response. This is required to properly   **/    /** establish support active data connections, also **/    /** in case of error                                **/    if(!cfg.ftp_activec ||      tl_selectr(bufio_getfd(docp->ftp_control), 10) == 0)    {      if(!ftp_open_data_finish(docp))      {        docp->ftp_fatal_err = TRUE;        if(!docp->errcode)          docp->errcode = ERR_FTP_DATACON;        return NULL;      }    }

⌨️ 快捷键说明

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