12、临时文件:tmpfile函数、tmpnam函数、mkstemp(Linux扩展)、临时文件的安全问题
临时文件这东西,说白了就是「用完就扔」的文件。我在嵌入式项目里经常用它来存中间数据、日志片段,或者进程间通信的临时缓存。但你别小看它——用不好,轻则数据泄露,重则系统被黑。今天咱们就把临时文件的几种玩法掰开揉碎讲清楚。
12.1 tmpfile:最省心的临时文件
tmpfile() 是我个人最常用的临时文件函数。它帮你自动创建一个临时文件,返回一个 FILE* 指针。文件以 wb+ 模式打开,可读可写。最关键的是——程序结束或你调用 fclose() 时,文件自动删除。
#include <stdio.h>
int main() {
FILE *fp = tmpfile();
if (fp == NULL) {
perror("tmpfile failed");
return -1;
}
// 写入一些数据
fprintf(fp, "临时数据: %d\n", 42);
// 重置文件位置指针
rewind(fp);
// 读回来
char buf[64];
fgets(buf, sizeof(buf), fp);
printf("读到的内容: %s", buf);
// fclose 时自动删除
fclose(fp);
return 0;
}
但 tmpfile 有个局限——它不给你文件名。你没法在文件系统里看到它,也没法让其他进程访问它。如果你需要文件名,就得用下面这些函数。
12.2 tmpnam:生成唯一文件名(但不安全)
tmpnam() 的作用是生成一个不重复的文件名字符串。你可以用它创建临时文件,但要注意——它只生成名字,不创建文件。
#include <stdio.h>
int main() {
char name[L_tmpnam];
if (tmpnam(name) != NULL) {
printf("临时文件名: %s\n", name);
}
return 0;
}
说白了,tmpnam 只保证名字唯一,不保证文件安全。你拿到名字后,到真正创建文件之间,存在时间窗口。这个窗口足够黑客做手脚了。
所以,我个人建议:不要在安全敏感场景中使用 tmpnam。C 标准也把它标记为「不推荐使用」。
12.3 mkstemp:Linux 下的安全选择
mkstemp() 是 Linux 扩展函数,它解决了 tmpnam 的安全问题。它直接创建并打开文件,返回文件描述符。没有时间窗口,攻击者没法插队。
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
int main() {
char template[] = "/tmp/myapp_XXXXXX";
int fd = mkstemp(template);
if (fd == -1) {
perror("mkstemp failed");
return -1;
}
printf("创建的文件: %s\n", template);
// 写入数据
write(fd, "Hello temp\n", 11);
close(fd);
// 手动删除
unlink(template);
return 0;
}
注意模板字符串里的 XXXXXX——这是必须的占位符,mkstemp 会用随机字符替换它们。我刚开始用的时候忘了写够6个X,结果函数一直返回 -1,排查了半天才发现。
- tmpnam:只生成名字,不创建文件,不安全
- tmpfile:创建并打开,自动删除,但无文件名
- mkstemp:创建并打开,安全,需要手动删除
12.4 临时文件的安全问题
临时文件的安全问题,我把它总结为三类:
| 风险类型 | 描述 | 解决方案 |
|---|---|---|
| TOCTOU 竞争 | 检查文件名和创建文件之间存在时间差 | 使用 mkstemp 等原子操作函数 |
| 权限泄露 | 临时文件权限设置不当,其他进程可读 | umask 设置严格权限,或使用 tmpfile |
| 残留文件 | 程序崩溃后临时文件未被清理 | 注册 atexit 处理函数,或使用 tmpfile |
我曾经在一个嵌入式网关项目里踩过权限泄露的坑。当时用 fopen 创建临时文件,默认权限是 0666,结果另一个服务进程把临时文件里的密钥读走了。从那以后,我但凡创建临时文件,都会显式设置 umask。
#include <sys/stat.h>
// 创建临时文件前设置严格权限
umask(0077); // 只允许当前用户读写
int fd = mkstemp(template);
tmpfile,配合 atexit 注册清理函数,才彻底解决。记住:临时文件的生命周期一定要清晰。
12.5 知识体系图
下面这张图帮你理清临时文件的核心脉络:
嗯,临时文件这块内容其实不难,但细节决定成败。我个人建议:能用 tmpfile 就用 tmpfile,省心又安全。如果非要文件名不可,那就上 mkstemp,别碰 tmpnam。至于权限问题,养成设置 umask 的习惯,能省掉很多麻烦。
公众号:蓝海资料掘金营,微信deep3321