ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

libcurl 详解 CURLINFO_FILETIME_T:安全获取远端资源的修改时间(64 位时间戳)

2026/9/10 13:45:36 拓冰建站 浏览量
libcurl 详解 CURLINFO_FILETIME_T:安全获取远端资源的修改时间(64 位时间戳) libcurl 详解 CURLINFO_FILETIME_T安全获取远端资源的修改时间64 位时间戳【免费下载链接】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/curlCURLINFO_FILETIME_T是 libcurl 提供的curl_easy_getinfo()查询选项用于在传输完成后获取远端文档的修改时间以 GMT/UTC 时区下自 1970-01-01 起的秒数表示。它是CURLINFO_FILETIME的 64 位时间戳版本专为在long为 32 位的系统如 Windows上突破 2038 年时间溢出限制而设计。本文以 docs/libcurl/opts/CURLINFO_FILETIME_T.md 为骨架结合 lib/getinfo.c、lib/setopt.c、lib/http.c 等源码与 src/tool_operate.c 中的实际调用完整讲解其用法、底层原理与工程实践。一、接口定义从 SYNOPSIS 看函数签名CURLINFO_FILETIME_T的官方文档位于 docs/libcurl/opts/CURLINFO_FILETIME_T.md其函数签名如下#include curl/curl.h CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_FILETIME_T, curl_off_t *timep);要点解读该选项由curl_easy_getinfo()使用属于读取型query信息选项与curl_easy_setopt()配合的写入型选项CURLOPT_FILETIME相对应见 CURLOPT_FILETIME.md传入的是指向curl_off_t的指针而非long指针——这正是它与旧版选项最本质的区别根据 include/curl/curl.h 中的枚举定义CURLINFO_FILETIME CURLINFO_LONG 14而CURLINFO_FILETIME_T CURLINFO_OFF_T 14两者共享同一个“14”槽位但分别归属 LONG 与 OFF_T 两个信息类型族说明它们在类型体系上被刻意区分。该选项自7.59.0版本起加入Added-in: 7.59.0参见 docs/libcurl/symbols-in-versions适用协议为 HTTP、FTP 与 SFTP。二、返回值语义epoch 秒与 -1 的含义文档明确说明调用者将得到一个curl_off_t其值为远端文档的修改时间单位为自 1970 年 1 月 1 日起的秒数GMT/UTC 时区。当返回值是-1时表示时间未知可能的原因包括服务器未提供该信息未返回相关时间字段服务器有意隐藏修改时间服务器不支持查询文档时间的命令例如 FTP 服务器不支持MDTM类命令。从源码实现看这一语义被完整落实在 lib/getinfo.c 的Curl_initinfo()中info-filetime -1; /* -1 is an illegal time and thus means unknown */该初始化函数在curl_easy_reset、curl_easy_duphandle以及每次 perform 会话开始时都会被调用因此每次传输都会从“未知”状态重新开始上一次查询得到的时间不会残留到下一次传输。三、与 CURLINFO_FILETIME 的区别为什么需要 _T 版本官方文档将本选项定位为CURLINFO_FILETIME的替代方案参见 CURLINFO_FILETIME.md允许long为 32 位的系统提取超出 32 位时间戳范围即 2038 年之后的日期。两者在源码实现上的差异非常直观。旧版CURLINFO_FILETIMElib/getinfo.c在取出内部时间后需要做钳制clamp处理以防溢出 32 位longcase CURLINFO_FILETIME: if(data-info.filetime LONG_MAX) *param_longp LONG_MAX; #if !defined(MSDOS) !defined(__AMIGA__) else if(data-info.filetime LONG_MIN) *param_longp LONG_MIN; #endif else *param_longp (long)data-info.filetime; break;而CURLINFO_FILETIME_Tlib/getinfo.c直接原样拷贝不做任何钳制case CURLINFO_FILETIME_T: *param_offt (curl_off_t)data-info.filetime; break;由于curl_off_t被定义为足够容纳文件大小的 64 位宽整数类型它可以无损承载远超过 2038 年的时间值。因此在涉及“长期时间戳”“未来日期”“跨世纪归档”等场景下应优先使用CURLINFO_FILETIME_T。四、使用前提必须先设置 CURLOPT_FILETIME这是本选项最关键的约束文档用强语气强调必须在传输开始前通过CURLOPT_FILETIME请求该信息否则无条件得到 -1。curl_easy_setopt(curl, CURLOPT_FILETIME, 1L);从源码看CURLOPT_FILETIME在 lib/setopt.c 中的处理是把标志位写入会话设置case CURLOPT_FILETIME: /* * Try to get the file time of the remote document. The time will * later (possibly) become available using curl_easy_getinfo(). */ s-get_filetime enabled; break;get_filetime标志随后驱动各协议层去主动收集时间信息。以 HTTP 为例lib/http.c 中的响应头解析函数http_header_l()会专门匹配Last-Modified:头const char *v (!k-http_bodyless (data-set.timecondition ||>int main(void) { CURL *curl curl_easy_init(); if(curl) { CURLcode result; curl_easy_setopt(curl, CURLOPT_URL, https://example.com/); /* Ask for filetime */ curl_easy_setopt(curl, CURLOPT_FILETIME, 1L); result curl_easy_perform(curl); if(result CURLE_OK) { curl_off_t filetime; result curl_easy_getinfo(curl, CURLINFO_FILETIME_T, filetime); if((result CURLE_OK) (filetime ! -1)) { time_t file_time (time_t)filetime; printf(filetime: %s, ctime(file_time)); } } /* always cleanup */ curl_easy_cleanup(curl); } }对示例代码的补充说明curl_easy_setopt(curl, CURLOPT_FILETIME, 1L)必须位于curl_easy_perform()之前这是整个流程成立的前提curl_easy_getinfo()返回CURLE_OK只代表调用成功不代表时间可用必须同时检查filetime ! -1这一条件由于curl_off_t与time_t的宽度可能不同尤其在不同平台上将filetime显式转换为time_t后再交给ctime()是安全的做法若服务器返回的时间在 32 位时间戳范围之外旧版CURLINFO_FILETIME得到的long会被钳制为LONG_MAX/LONG_MIN失去真实精度而本选项可以原样返回完整值。六、工程实践curl 命令行工具自身的 -R/--remote-timeCURLINFO_FILETIME_T并非仅面向库使用者curl 命令行工具本身就在生产环境中使用它。在 src/tool_operate.c 中-R/--remote-time选项的实现正是依赖此接口在文件关闭后把远端时间写回本地文件/* File time can only be set _after_ the file has been closed */ if(!result config-remote_time outs-regular_file outs-filename) { /* Ask libcurl if we got a remote file time */ curl_off_t filetime -1; curl_easy_getinfo(per-curl, CURLINFO_FILETIME_T, filetime); if(filetime ! -1) setfiletime(filetime, outs-filename); }这段代码也印证了两个工程要点调用时机对文件的mtime设置必须发生在文件关闭之后否则写入操作会覆盖刚设置的时间-1 的防御性检查工具层同样先检查filetime ! -1再执行setfiletime()避免用“未知时间”污染本地文件属性。因此你可以直接用一条命令行体验本选项的效果curl -R -o local.html https://example.com/下载完成后local.html的修改时间会被设置为服务器返回的Last-Modified时间。七、返回值与错误处理curl_easy_getinfo()总是返回一个CURLcode来指示成功或失败CURLE_OK0一切正常timep指向的变量已被填充可能为 -1表示时间未知非零值发生了错误具体的错误码说明参见 libcurl-errors 文档 对应的错误码清单。常见的错误场景与排查思路现象可能原因处理建议恒返回 -1未设置CURLOPT_FILETIME在curl_easy_perform()前设置curl_easy_setopt(curl, CURLOPT_FILETIME, 1L)恒返回 -1服务器不发送Last-Modified头或不支持MDTM换用支持时间查询的服务器/协议验证时间不精确服务器时间粒度或时区处理差异注意返回值是 GMT/UTC 秒展示时自行做时区换算时间被截断误用了CURLINFO_FILETIME 32 位long改用CURLINFO_FILETIME_Tcurl_off_t八、总结与参考CURLINFO_FILETIME_T是 libcurl 面向 64 位时间戳时代的标准做法以curl_off_t无损承载远端资源的修改时间规避 32 位long的 2038 年问题并贯穿 HTTPLast-Modified头、FTPMDTM、SFTPmtime属性等主流协议。使用时的三要素可概括为先CURLOPT_FILETIME请求、后curl_easy_getinfo读取、务必判-1。进一步阅读CURLINFO_FILETIME_T 官方文档本选项的权威定义CURLINFO_FILETIME.mdlong版本对照CURLOPT_FILETIME.md配套的请求选项curl_easy_getinfo.md查询接口总览lib/getinfo.c信息存储与返回值实现lib/http.cHTTPLast-Modified头解析src/tool_operate.ccurl 工具层--remote-time的实际用法。【免费下载链接】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),仅供参考