qt5集成libcurl实现tftp和ftp的方法之三:搭建FTP时,当ftpServer端默认登录的目录不是根目录/时,有一个bug会产生的解决办法

本文介绍了解决curl在使用FTP传输文件时遇到的目录更改失败问题。提供了三种解决方案:严格设置文件路径、修改curl源代码及调整参数设置,并详细解释了第二种方案的操作步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在使用curl时遇到一个问题,老出现下面的错误提示:

< 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

在网上找了很长时间,发现真正有价值的博客非常少,只有两个:

http://blog.dou.li/curl-9-server-denied-you-to-change-to-the-given-directory.html和

http://blog.youkuaiyun.com/langeldep/article/details/6166218,不过少比没有好,第二个博客的方法确实能解决问题,所以,我将解决该问题的方法稍作整理。

解决该问题的方法有三种:

第一种是上面链接1,通过严格地设置文件的路径,但是我测试发现不好使。

第二种方法是上面链接2,通过修改代码实现。测试发现确实能解决问题。

第三种方法,没必要修改源码,这不是BUG,只要添加下面的语句设置好参数就行了,不过这种方法我没测试,不知道好不好用。
curl_easy_setopt(curl, CURLOPT_FTP_FILEMETHOD, CURLFTPMETHOD_NOCWD);

第二种方法的详细解释和操作过程为: 

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
修改方法是  修改 curl库目录下面 lib文件夹下面的 ftp.c 文件,在函数 static CURLcode ftp_parse_url_path(struct connectdata *conn) 中 添加如下代码

if (ftpc->dirdepth == 0)
<span style="white-space:pre">		</span>{
<span style="white-space:pre">			</span>ftpc->dirs[0] = strdup("/");
<span style="white-space:pre">			</span>ftpc->dirdepth++;
<span style="white-space:pre">		</span>}
意思就是 让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;

	<span style="color:#ff0000;">	if (ftpc->dirdepth == 0)
		{
			ftpc->dirs[0] = strdup("/");
			ftpc->dirdepth++;
		}</span>

        /* seek out the next path component */
        if(slash_pos-cur_pos) 
		{
          /* we skip empty path components, like "x//y" since the FTP command
             CWD requires a parameter and a non-existant parameter a) doesn't
             work 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 */

然后按照前一篇博客http://blog.youkuaiyun.com/xueyushenzhou/article/details/51702672的说明,重新编译出共享库,再将原来的都替换掉就行啦。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

纵横千里,捭阖四方

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值