在 C 中使用 tmpfile() 时的临时文件位置

temporary file location when using tmpfile() in C

$ man tmpfile

The standard does not specify the directory that tmpfile() will use. Glibc will try the path prefix P_tmpdir defined in <stdio.h>, and if that fails the directory /tmp.

我正在使用 Ubuntu 13.10 x86_64、gcc 和 libc BTW。

所以当我尝试使用 tmpfile() 创建临时文件时,我在 /tmp 中看不到任何临时文件。 (我可以在 stdio.h 中看到 # define P_tmpdir "/tmp")。这是我使用的代码片段:

#include <stdio.h>

int main(int argc, char **argv)
{
    FILE *tmp;

    tmp = tmpfile();                            // Where's this file?
    scanf("%*d");

    return 0;
}

$ ./tmpfile
现在,当 scanf 正在等待下一个(冗余)输入时,我应该能够在 /tmp 中看到一个临时文件。但我不能。那么这个 tmpfile 到底是在哪里创建的呢?

可能目录中的文件条目被直接删除了。在 POSIX 系统上,文件本身在删除后仍然有效,只要您有一个打开的文件描述符即可。 (在您的情况下隐藏在 FILE* return 值中。)

使用该技术,任何人都无法潜入并打开该文件,只能通过您的变量 tmp.

访问该文件

编译您的代码并运行它通过strace显示文件的位置和名称:

$ ./a.out
execve("./main", ["./main"], [/* 31 vars */]) = 0
brk(0)                                  = 0xe0c000
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c51a000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY)      = 3
fstat(3, {st_mode=S_IFREG|0644, st_size=103425, ...}) = 0
mmap(NULL, 103425, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f038c500000
close(3)                                = 0
access("/etc/ld.so.nohwcap", F_OK)      = -1 ENOENT (No such file or directory)
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
read(3, "7ELF[=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=][=10=]>[=10=][=10=][=10=][=10=]07[=10=][=10=][=10=][=10=][=10=]"..., 832) = 832
fstat(3, {st_mode=S_IFREG|0755, st_size=1603600, ...}) = 0
mmap(NULL, 3717176, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f038bf71000
mprotect(0x7f038c0f3000, 2097152, PROT_NONE) = 0
mmap(0x7f038c2f3000, 20480, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x182000) = 0x7f038c2f3000
mmap(0x7f038c2f8000, 18488, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f038c2f8000
close(3)                                = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c4ff000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c4fe000
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c4fd000
arch_prctl(ARCH_SET_FS, 0x7f038c4fe700) = 0
mprotect(0x7f038c2f3000, 16384, PROT_READ) = 0
mprotect(0x7f038c51c000, 4096, PROT_READ) = 0
munmap(0x7f038c500000, 103425)          = 0
stat("/tmp", {st_mode=S_IFDIR|0777, st_size=4096, ...}) = 0
getpid()                                = 25957
open("/tmp/tmpfflAlKG", O_RDWR|O_CREAT|O_EXCL, 0600) = 3
unlink("/tmp/tmpfflAlKG")               = 0
fcntl(3, F_GETFL)                       = 0x8002 (flags O_RDWR|O_LARGEFILE)
brk(0)                                  = 0xe0c000
brk(0xe2d000)                           = 0xe2d000
fstat(3, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c519000
lseek(3, 0, SEEK_CUR)                   = 0
fstat(0, {st_mode=S_IFCHR|0620, st_rdev=makedev(136, 2), ...}) = 0
mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f038c518000
read(0, alk
"alk\n", 1024)                  = 4
exit_group(0)                           = ?

"/tmp/tmpfflAlKG" 通过 open()

创建
open("/tmp/tmpfflAlKG", O_RDWR|O_CREAT|O_EXCL, 0600) = 3

然后立即得到 unlink()

unlink("/tmp/tmpfflAlKG")               = 0

所以可见的目录条目消失了。

由于仍然对进程开放,文件本身对进程保持有效,直到进程 close()s 它。后者通过调用 exit_group():

隐式发生
exit_group(0)                           = ?

来自https://en.cppreference.com/w/c/io/tmpfile

On some implementations (e.g. Linux), this function actually creates, opens, and immediately deletes the file from the file system: as long as an open file descriptor to a deleted file is held by a program, the file exists, but since it was deleted, its name does not appear in any directory, so that no other process can open it. Once the file descriptor is closed, or once the program terminates (normally or abnormally), the space occupied by the file is reclaimed by the filesystem.

On some implementations (e.g. Windows), elevated privileges are required as the function may create the temporary file in a system directory.