libcurl CURLOPT_QUOTE 详解:在 FTP/SFTP 传输前执行自定义命令
libcurl CURLOPT_QUOTE 详解在 FTP/SFTP 传输前执行自定义命令【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl导读CURLOPT_QUOTE是 libcurl 提供的“传输前钩子”通过它可以在正式数据传输之前向 FTP 或 SFTP 服务器发送一组自定义命令用于切换目录、重命名文件、修改权限、创建目录等预处理操作。本文以 curl 仓库中的官方文档 docs/libcurl/opts/CURLOPT_QUOTE.md 为主线结合 lib/ftp.c、lib/vssh/libssh.c 等源码实现完整讲解该选项的用法、命令格式、失败处理策略以及全部受支持的 SFTP 命令读完即可在自己的 C 程序中编写出可实际运行的传输前命令序列。CURLOPT_QUOTE 是什么CURLOPT_QUOTE的官方定义是“(S)FTP commands to run before transfer”即在传输开始前向服务器发送的命令列表。它是 FTP 协议中经典“QUOTE”机制的 libcurl 实现curl_easy_setopt的众多选项之一原型如下#include curl/curl.h CURLcode curl_easy_setopt(CURL *handle, CURLOPT_QUOTE, struct curl_slist *cmds);传入的是一个指向struct curl_slist链表的指针链表中每个节点存放一条要发送给服务器的文本命令。该选项最早出现在7.1版本SFTP 支持则在7.16.3加入而针对 SFTP 的*前缀容错能力是7.24.0才提供的详见官方文档“HISTORY”一节。在选项注册表中CURLOPT_QUOTE被归类为CURLOT_SLIST类型见 lib/easyoptions.c与CURLOPT_POSTQUOTE、CURLOPT_PREQUOTE一起构成了三兄弟选项执行时机CURLOPT_PREQUOTE传输前、TYPE命令之后CURLOPT_QUOTE连接建立后、任何其他命令甚至 CWD发出之前CURLOPT_POSTQUOTE传输完成之后三者在 lib/urldata.h 中以三个独立的struct curl_slist *字段存储注释分别标明“after connection is established”QUOTE、“after the transfer”POSTQUOTE、“before the transfer, after type”PREQUOTE。基本用法构造命令链表使用CURLOPT_QUOTE的标准流程是用curl_slist_append(3)见 docs/libcurl/curl_slist_append.md把命令逐条追加进链表设置选项后执行传输最后用curl_slist_free_all(3)见 docs/libcurl/curl_slist_free_all.md释放链表。官方文档给出的完整示例int main(void) { CURL *curl; struct curl_slist *cmdlist NULL; cmdlist curl_slist_append(cmdlist, RNFR source-name); cmdlist curl_slist_append(cmdlist, RNTO new-name); curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, ftp://example.com/foo.bin); /* pass in the FTP commands to run before the transfer */ curl_easy_setopt(curl, CURLOPT_QUOTE, cmdlist); result curl_easy_perform(curl); curl_easy_cleanup(curl); } curl_slist_free_all(cmdlist); }上面示例在下载foo.bin之前先向 FTP 服务器发送RNFR source-name和RNTO new-name两条原始命令完成远程文件重命名。使用时有几个必须注意的规则链表必须保持存活libcurl不会复制该链表它只是保存指针。链表必须存活到传输结束之后中途释放会导致未定义行为。重复设置会覆盖多次使用该选项时最后一次设置的链表会替换之前的传NULL可重新禁用。命令原样透传libcurl不检查、不解析、不“理解”这些命令命令内容原样发给服务器。文档特别警告如果你用 QUOTE 命令改变了连接状态、工作目录等libcurl 对此一无所知后续行为需要你自己负责。默认值为NULL即默认不发送任何 QUOTE 命令。失败处理*前缀与 CURLE_QUOTE_ERROR默认情况下libcurl 会在第一条失败的命令处停止FTP 命令返回码 ≥ 400 即视为失败并返回CURLE_QUOTE_ERROR错误。如果希望某条命令失败时也能继续只需在命令前加一个星号**DELE old-file.txtFTP 合法命令永远不会以*开头因此 libcurl 可以安全地把它当作“允许失败”标记。这一逻辑在 lib/ftp.c 的ftp_sendquote()函数中实现/* if a command starts with an asterisk, which a legal FTP command never can, the command will be allowed to fail without it causing any aborts or cancels etc. */ if(cmd[0] *) { cmd; acceptfail TRUE; } result Curl_pp_sendf(data, ftpc-pp, %s, cmd); ... if(!acceptfail (ftpcode 400)) { failf(data, QUOT string not accepted: %s, cmd); return CURLE_QUOTE_ERROR; }从源码可以看到两条关键实现细节命令通过Curl_pp_sendf按原字符串发给服务器*只被剥掉用于本地标记不会出现在网络上服务器返回码 ≥ 400 且未加*时记录错误QUOT string not accepted并返回CURLE_QUOTE_ERROR。FTP 端的状态机处理位于 lib/ftp.c 的ftp_state_quote()它按FTP_QUOTE对应data-set.quote、FTP_RETR_PREQUOTE/FTP_STOR_PREQUOTE/FTP_LIST_PREQUOTE对应data-set.prequote、FTP_POSTQUOTE对应data-set.postquote三种状态选取链表逐条发送并推进状态。而CURLOPT_QUOTE选项的存储入口在 lib/setopt.c注释明确写着“List of RAW FTP commands to use before a transfer”。另外注意FTP 端哪些命令合法取决于服务器libcurl 不会替你做校验可用命令清单可参考 FTP 标准 RFC 959 中规定的必备命令。SFTP 命令本地解析、逐个分发SFTP 与 FTP 有本质区别SFTP 是二进制协议无法像 FTP 那样把文本命令原样发给服务器。因此 libcurl 在本地解析 QUOTE 命令文本识别出 OpenSSHsftp程序风格的命令后调用对应的 libssh 底层函数执行。源码中的说明lib/vssh/libssh.c/* * SFTP is a binary protocol, so we do not send text commands * to the server. Instead, we scan for commands used by * OpenSSHs sftp program and call the appropriate libssh * functions. */解析入口是myssh_in_SFTP_QUOTE()lib/vssh/libssh.c 起pwd命令被特殊处理为输出一条 FTP 风格的回显257 path is current directory.其余命令则按strncmp前缀匹配分派并用Curl_get_pathname()解析路径参数。路径与引号规则对于 FTP 和 SFTP路径参数中的空格需要用双引号包裹以区分“空格作为参数分隔符”与“空格属于路径的一部分”。例如 SFTP 下用 rename 重命名含空格的文件rename test/_upload.txt test/Hello World.txtSFTP 的文件名若想包含空格、反斜杠、引号或双引号必须放在双引号内并可使用以下转义序列转义序列含义\\反斜杠\双引号\单引号完整命令清单官方文档列出的受支持 SFTP 命令共 12 个逐一说明如下命令作用说明atime date file设置文件最后访问时间date 表达式支持多种日期字符串详见 curl_getdate(3)7.73.0 加入chgrp group file设置文件组 IDgroup 为十进制整数 GIDchmod mode file修改文件权限位mode 为八进制整数chown user file设置文件属主user 为十进制整数 UIDln source_file target_file在 target 处创建指向 source 的符号链接与symlink等价mkdir directory_name创建目录—mtime date file设置文件最后修改时间date 规则同atime7.73.0 加入pwd返回当前工作目录绝对路径回显为 FTP 风格257响应rename source target重命名文件或目录—rm file删除文件—rmdir directory删除空目录目录非空会失败statvfs file返回文件所在文件系统的统计信息底层调用sftp_statvfs从源码看lib/vssh/libssh.c 将chgrp、chmod、chown、atime、mtime归为一类“属性修改”命令统一走SSH_SFTP_QUOTE_STAT状态最终调用sftp_setstatln/symlink走符号链接分支mkdir、rename、rm、rmdir、statvfs各有对应状态。属性命令中chmod解析为八进制权限位strtoul后写入permissions字段chown/chgrp解析十进制 UID/GIDatime/mtime则通过Curl_getdate_capped()解析日期字符串后写入访问/修改时间——这与文档描述完全吻合。与 FTP 模式的区别FTP 模式下命令是透传文本SFTP 模式下命令是本地解析后映射为二进制 SFTP 操作。因此 SFTP 下只有上表列出的命令可用并且命令语法错误如缺少参数、参数过多会被 libcurl 识别并返回CURLE_QUOTE_ERROR源码中对应quote_error()lib/vssh/libssh.c报出“Suspicious data after the command line”或“Syntax error in SFTP command. Supply parameter(s)”。SFTP 的*前缀同样支持7.24.0 起允许命令失败时不中止传输。与相邻选项的关系CURLOPT_PREQUOTE在传输前、TYPE命令之后发送命令适合需要先设置传输类型如 ASCII/二进制再执行其他操作的场景见 docs/libcurl/opts/CURLOPT_PREQUOTE.md。CURLOPT_POSTQUOTE传输完成后执行清理类命令如删除临时文件见 docs/libcurl/opts/CURLOPT_POSTQUOTE.md。FTP 端在ftp_done()中于传输成功且非中断时调用ftp_sendquote(data, ftpc,>#include curl/curl.h int main(void) { CURL *curl; CURLcode res; struct curl_slist *cmdlist NULL; /* 建目录已存在时允许失败 */ cmdlist curl_slist_append(cmdlist, *mkdir /backup); /* 删除旧的临时文件不存在时允许失败 */ cmdlist curl_slist_append(cmdlist, *rm /backup/old.tmp); /* 设置目标目录权限为 755 */ cmdlist curl_slist_append(cmdlist, chmod 0755 /backup); curl curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, sftp://userexample.com/backup/new.tmp); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); curl_easy_setopt(curl, CURLOPT_QUOTE, cmdlist); res curl_easy_perform(curl); if(res ! CURLE_OK) fprintf(stderr, transfer failed: %s\n, curl_easy_strerror(res)); curl_easy_cleanup(curl); } curl_slist_free_all(cmdlist); return 0; }传输完成后若还需清理远程临时文件可另行设置CURLOPT_POSTQUOTE。把 QUOTE传输前、PREQUOTETYPE 后、POSTQUOTE传输后三个选项配合使用即可完整覆盖 FTP/SFTP 会话的“准备—传输—清理”全流程。【免费下载链接】curlA command line tool and library for transferring data with URL syntax, supporting DICT, FILE, FTP, FTPS, GOPHER, GOPHERS, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, MQTT, MQTTS, POP3, POP3S, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, TELNET, TFTP, WS and WSS. libcurl offers a myriad of powerful features项目地址: https://gitcode.com/GitHub_Trending/cu/curl创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考