↩️
Linuxなら一時ファイルはunlinkで実現可能
一時ファイルを実現する方法としてunlink
を使った方法がある。
open
でファイルディスクリプタを取得した状態でunlink
すると、ファイルディスクリプタをclose
したタイミングでファイルの削除されるのだ。
unlink
はOSが持っているファイルへの参照を消すイメージで、そのファイルへの参照カウントが1減る。すでにopen
していた場合は、そのファイルディスクリプタが最後の参照になり、close
でファイルの参照カウントが0になるとファイルは削除される。
以下、実験を行った。unlink
しておいた一時ファイルは自動的に消去されていることがわかる。
$ ls
Makefile main.c
$ make
gcc main.c -g -o unlink-technique
$ ./unlink-technique
> touch(./not_unlink.tmp) < './not_unlink.tmp'
> fd = open(./not_unlink.tmp)
// > unlink(./not_unlink.tmp)
> content = read(fd)
> print(content)
./not_unlink.tmp
> is_exist(./not_unlink.tmp)
YES
> touch(./unlinked.tmp) < './unlinked.tmp'
> fd = open(./unlinked.tmp)
> unlink(./unlinked.tmp)
> content = read(fd)
> print(content)
./unlinked.tmp
> is_exist(./unlinked.tmp)
NO
$ ls
Makefile main.c not_unlink.tmp unlink-technique
main.c
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
void touch_and_write(const char *file, const char *content) {
int fd = open(file, O_RDWR | O_CREAT, 0644);
if (fd < 0) {
perror("open");
exit(1);
}
write(fd, content, strlen(content));
close(fd);
}
int main() {
const char *tmpfiles[] = {"./not_unlink.tmp", "./unlinked.tmp"};
for (int i = 0; i < sizeof(tmpfiles) / sizeof(*tmpfiles); ++i) {
const char *tmp = tmpfiles[i];
const char do_unlink = (i == 1);
touch_and_write(tmp, tmp);
printf("> touch(%s) < '%s'\n", tmp, tmp);
int fd = open(tmp, O_RDONLY);
if (fd < 0) {
perror("open");
exit(1);
}
printf("> fd = open(%s)\n", tmp);
if (do_unlink) {
char c;
unlink(tmp);
printf("> unlink(%s)\n", tmp);
} else {
printf("// > unlink(%s)\n", tmp);
}
char buffer[1024];
int size = read(fd, buffer, sizeof(buffer) - 1);
if (size < 0) {
perror("read");
close(fd);
exit(1);
}
buffer[size] = '\0';
printf("> content = read(fd)\n");
close(fd);
printf("> print(content)\n");
printf("%s\n", buffer);
printf("> is_exist(%s)\n", tmp);
printf("%s\n", access(tmp, F_OK) == 0 ? "YES" : "NO");
printf("\n");
}
}
Discussion