设为首页 收藏本站
查看: 1859|回复: 0

[经验分享] CURL库FTP传输文件,当ftpServer端默认登录的目录不是根目录/时,有一个bug会产生

[复制链接]

尚未签到

发表于 2016-6-11 07:27:23 | 显示全部楼层 |阅读模式
  CURL 库在使用FTP传输文件时, 正常情况下, ftp的server端都会默认进入根目录 /, 但是当ftp的server端设置了一个子目录,
  比如 ftp的server设置了 /data/movies 为第一次默认进入的目录, 则curl的FTP将会无法传输文件, 错误的原因是 :
  
  ftp的下载地址为 ftp://root:123456@192.168.2.223/data/movies/vbr.ts
  
  而第一次进入的目录为 /data/movies , 而curl库的FTP解析ftp地址得出 要进入 data 和movies 目录后才能找到下载的文件,
  就会去执行 CWD data 和 CWD movies , 而在 /data/movies 这个目录去进入 data 目录, 目录肯定是不存在的,
  所以出错。
  
  具体的错误现象如下:
  
  * About to connect() to 192.168.2.223 port 21 (#0)*   Trying 192.168.2.223... Leave Lock = Resume Download File* connected* Connected to 192.168.2.223 (192.168.2.223) port 21 (#0)< 220 (vsFTPd 2.0.5)> USER root< 331 Please specify the password.> PASS 123456< 230 Login successful.> PWD< 257 "/data/movies"* Entry path is '/data/movies'> CWD data< 550 Failed to change directory.* Server denied you to change to the given directory* Connection #0 to host 192.168.2.223 left intact* Access denied to remote resource> QUIT< 221 Goodbye.* Closing connection #0
  
  下面的代码是我使用的代码
  
  void dispatch_threadpool_to_me(void *arg){MissionInfo* pMission = (MissionInfo*)arg;uint64 filelen = 0;int tries = 0;CURL *curlhandle;RE_Download:FILE *fp;curl_off_t local_file_len = -1 ;uint64 filesize =0 ;CURLcode result = CURLE_GOT_NOTHING;#ifdef _WIN32struct _stat file_info;#elsestruct stat file_info;#endifint use_resume = 0;/* 得到本地文件大小 */if(stat(pMission->localPath, &file_info) == 0){int flen = file_info.st_size;if (flen%DOWNLOAD_FILE_SEGMENT == 0){//assert (flen > 0);local_file_len = flen - DOWNLOAD_FILE_SEGMENT;}else{local_file_len = flen - flen%DOWNLOAD_FILE_SEGMENT - DOWNLOAD_FILE_SEGMENT;}local_file_len = (local_file_len > 0) ? local_file_len : 0;assert (local_file_len%DOWNLOAD_FILE_SEGMENT == 0);use_resume  = 1;}if (pMission->missionType == MISSION_TYPE_REMOVEFILE){//删除任务if (use_resume == 0){writelog(LOG_ERROR, "remove file is not exists, path=%s/n", pMission->localPath);}unlink(pMission->localPath);(*pMission->downcbfunc)(pMission->missionID, pMission->missionType, pMission->epgID, 0, "removeFileSuccess", pMission->localPath, 0);return;}curlhandle = curl_easy_init();if(curlhandle == NULL)return ;//采用追加方式打开文件,便于实现文件断点续传工作fp = fopen(pMission->localPath, "ab+");//ftp服务器可能无法断点续传,所以不能追加写//fp = fopen(pMission->localPath, "w");if (fp == NULL){curl_easy_cleanup(curlhandle);writelog(LOG_ERROR, "Download fopen file Error , file=%s/n", pMission->localPath);return ;}curl_easy_setopt(curlhandle, CURLOPT_URL, pMission->remotePath);curl_easy_setopt(curlhandle, CURLOPT_CONNECTTIMEOUT, 60);  // 设置连接超时,单位秒curl_easy_setopt(curlhandle, CURLOPT_TIMEOUT, 1800);//设置http 头部处理函数curl_easy_setopt(curlhandle, CURLOPT_HEADERFUNCTION, GetContentLengthFunc);curl_easy_setopt(curlhandle, CURLOPT_HEADERDATA, &filesize);// 设置文件续传的位置给libcurl//use_resume = 0; //服务器不支持断点续传的时候无法续传,所以强制从头开始下载文件curl_easy_setopt(curlhandle, CURLOPT_RESUME_FROM_LARGE, use_resume?local_file_len:0);curl_easy_setopt(curlhandle, CURLOPT_WRITEDATA, fp);curl_easy_setopt(curlhandle, CURLOPT_WRITEFUNCTION, wirtefunc);curl_easy_setopt(curlhandle, CURLOPT_FTP_USE_EPSV, 0); //EPSV设置为0,就代表启用PASVcurl_easy_setopt(curlhandle, CURLOPT_NOPROGRESS, 1L);#ifdef _DEBUGcurl_easy_setopt(curlhandle, CURLOPT_VERBOSE, 1L);#endifresult = curl_easy_perform(curlhandle);curl_easy_cleanup(curlhandle);if (result == CURLE_OK){fseek(fp, 0, SEEK_END);filelen = ftell(fp);fclose(fp);writelog(LOG_ERROR, "Success Download File local = %s, remote = %s/n", pMission->localPath, pMission->remotePath);char buffer[512]={0};if (CompareMD5 (pMission->localPath)){const char* p = g_Config.pukkaIndex;if (*p == '.' || *p == '/')SNPRINTF (buffer, sizeof(buffer)-1, "%s %s", g_Config.pukkaIndex, pMission->localPath);elseSNPRINTF (buffer, sizeof(buffer)-1, "./%s %s", g_Config.pukkaIndex, pMission->localPath);system (buffer);(*pMission->downcbfunc)(pMission->missionID, pMission->missionType, pMission->epgID, 0, "ok", pMission->localPath, filelen);return ;}else{}}else if (result == CURLE_OPERATION_TIMEOUTED){fclose(fp);writelog(LOG_ERROR, "down operation timeout/n");goto RE_Download;}else if (result == CURLE_COULDNT_CONNECT){writelog(LOG_ERROR, "Can not Connect FTP File local = %s, remote = %s/n", pMission->localPath, pMission->remotePath);(*pMission->downcbfunc)(pMission->missionID, pMission->missionType, pMission->epgID, -1, curl_easy_strerror(result), pMission->localPath, filelen);return ;}else{fclose(fp);tries ++;if (tries < MAX_TRY_DOWNLOAD_COUNT){//writelog(LOG_ERROR, "Download File Try = %d /n  localdir = %s /n remotedir = %s /n err=%s/n",//tries, pMission->localPath, pMission->remotePath, curl_easy_strerror(result));sleep(MAX_SLEEP_TIME);if (result == CURLE_BAD_DOWNLOAD_RESUME){unlink(pMission->localPath);//不能断点续传下载,则删除本地已经下载的部分文件}goto RE_Download;}else if (tries == MAX_TRY_DOWNLOAD_COUNT){//万一ftp的服务器不支持断点续传,所以重新把文件删除, 在下载一次tries++;unlink(pMission->localPath);goto RE_Download;}else{writelog(LOG_ERROR, "Fail Download File local = %s, remote = %s/n", pMission->localPath, pMission->remotePath);(*pMission->downcbfunc)(pMission->missionID, pMission->missionType, pMission->epgID, -1, curl_easy_strerror(result), pMission->localPath, filelen);return ;}}}
  
  修改方法是 修改 curl库目录下面 lib文件夹下面的 ftp.c文件
  
  在函数 static CURLcode ftp_parse_url_path(struct connectdata *conn) 中 添加如下代码
  
  if (ftpc->dirdepth == 0){ftpc->dirs[0] = strdup("/");ftpc->dirdepth++;}
  
  意思就是 让ftp客户端从 根目录开始一级一级的进入到文件所在的目录。
  
  添加的位置如下 :
  
    default: /* allow pretty much anything */case FTPFILE_MULTICWD:ftpc->dirdepth = 0;ftpc->diralloc = 5; /* default dir depth to allocate */ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));if(!ftpc->dirs)return CURLE_OUT_OF_MEMORY;/* we have a special case for listing the root dir only */if(strequal(path_to_use, "/")) {cur_pos++; /* make it point to the zero byte */ftpc->dirs[0] = strdup("/");ftpc->dirdepth++;}else {/* parse the URL path into separate path components */while((slash_pos = strchr(cur_pos, '/')) != NULL) {/* 1 or 0 pointer offset to indicate absolute directory */ssize_t absolute_dir = ((cur_pos - data->state.path > 0) && (ftpc->dirdepth == 0))?1:0;if (ftpc->dirdepth == 0){ftpc->dirs[0] = strdup("/");ftpc->dirdepth++;}/* seek out the next path component */if(slash_pos-cur_pos) {/* we skip empty path components, like "x//y" since the FTP commandCWD requires a parameter and a non-existant parameter a) doesn'twork on many servers and b) has no effect on the others. */int len = (int)(slash_pos - cur_pos + absolute_dir);ftpc->dirs[ftpc->dirdepth] = curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);if(!ftpc->dirs[ftpc->dirdepth]){ /* run out of memory ... */failf(data, "no memory");freedirs(ftpc);return CURLE_OUT_OF_MEMORY;}if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {free(ftpc->dirs[ftpc->dirdepth]);freedirs(ftpc);return CURLE_URL_MALFORMAT;}}else {cur_pos = slash_pos + 1; /* jump to the rest of the string */continue;}cur_pos = slash_pos + 1; /* jump to the rest of the string */if(++ftpc->dirdepth >= ftpc->diralloc) {/* enlarge array */char *bigger;ftpc->diralloc *= 2; /* double the size each time */bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));if(!bigger) {freedirs(ftpc);return CURLE_OUT_OF_MEMORY;}ftpc->dirs = (char **)bigger;}}}filename = cur_pos;  /* the rest is the file name */break;} /* switch */

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.iyunv.com/thread-228823-1-1.html 上篇帖子: 阿里云服务器环境配置(挂载数据盘、swap分区、FTP服务器、JDK、Tomcat7) 下篇帖子: BufferedWriter & FileWriter write into a data file.
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表