libcurl SFTP文件上传断点续传异常:远程文件被截断为0
SFTP断点续传PoC远程文件被截断为0的问题排查与修复
先给你理清楚问题出在哪,以及怎么解决:
我正在开发支持断点续传的SFTP文件上传PoC,基于libcurl官方的FTP断点续传示例修改,做了两个关键改动:
- 将协议改为
sftp协议字符串- 在重试循环中强制让
c=1,直接进入续传分支但验证时遇到异常:连接完成后,首次执行
curl_perform(...)后,远程文件大小被截断为0。
问题根源分析
libcurl对FTP和SFTP的断点续传逻辑差异很大,你直接照搬FTP示例的强制续传逻辑到SFTP上就踩坑了:
- FTP的续传是基于你指定的偏移量直接请求服务器从该位置写入,但SFTP的续传依赖先确认远程文件的当前状态——如果远程文件不存在,你硬指定一个续传偏移量(哪怕是0),libcurl的SFTP驱动会直接创建一个新文件并把偏移量设为你给的值,这就会导致文件被截断成0字节(因为你跳过了“检查远程文件是否存在”的步骤,直接触发了续传分支的逻辑)。
- 原FTP示例里的
c=1是用来处理中断后的重试续传,它原本会先检查远程文件的大小再设置偏移量,但你强制c=1跳过了这个前置检查,相当于告诉libcurl“不管远程有没有文件,直接从某个位置开始写”,首次上传时远程没有文件,这个操作自然会生成一个0字节的空文件。
修复方案
1. 去掉强制c=1,先检查远程文件状态
在进入续传分支前,必须先确认远程文件是否存在以及它的当前大小,再决定是从头上传还是续传:
// 先切换到HEAD模式,获取远程文件大小 curl_off_t remote_file_size = 0; curl_easy_setopt(curl, CURLOPT_NOBODY, 1L); CURLcode res = curl_easy_perform(curl); if (res == CURLE_OK) { // 获取远程文件的大小 curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD_LARGE, &remote_file_size); } // 切回上传模式 curl_easy_setopt(curl, CURLOPT_NOBODY, 0L); // 根据远程文件状态设置上传模式 if (remote_file_size > 0) { // 远程文件存在,开启续传,从文件末尾开始写 curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, remote_file_size); } else { // 远程文件不存在,从头上传 curl_easy_setopt(curl, CURLOPT_RESUME_FROM_LARGE, 0L); } // 执行上传 res = curl_easy_perform(curl);
2. 开启调试日志定位细节
如果还是有问题,打开libcurl的 verbose 日志,查看SFTP的交互过程,确认续传偏移量是否正确,服务器的响应是什么:
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
3. 确保libcurl版本兼容
一些老版本的libcurl对SFTP续传的支持有缺陷,建议升级到最新的稳定版(比如7.80.0+),避免版本带来的隐性bug。
内容的提问来源于stack exchange,提问作者sergico




