Linux O_TMPFILE membuat regular file tanpa lebih dulu menempatkan nama file tersebut di sebuah direktori. Pemanggil menerima file descriptor dan dapat menulis data, menetapkan metadata, atau membatalkan objek saat belum ada pathname yang mengekspos file yang baru disiapkan sebagian. Jika publikasi diperlukan, operasi link berikutnya dapat memasang directory entry pada inode yang sama.

Mekanisme ini memisahkan konstruksi objek dari publikasi namespace. Mekanisme tersebut tidak membuat seluruh operasi filesystem di sekitarnya menjadi transaksional, dan tidak menyediakan semantik penggantian untuk tujuan yang sudah ada. Batas manfaatnya lebih sempit: state file perantara dapat tetap terjangkau hanya melalui referensi terbuka sampai proses secara eksplisit membuat nama.

Pembuatan dimulai dari direktori, bukan pathname tujuan

O_TMPFILE diberikan kepada open() atau openat() bersama O_RDWR atau O_WRONLY. Pathname mengidentifikasi direktori yang filesystem-nya akan menampung inode tanpa nama. Path tersebut bukan nama file akhir.

int fd = open("/srv/output", O_TMPFILE | O_RDWR | O_CLOEXEC, 0640);
if (fd == -1) {
    /* tangani filesystem yang tidak mendukung, izin, atau error lain */
}

Descriptor yang dihasilkan merujuk ke regular file baru. Data yang ditulis melalui fd menjadi bagian dari file tersebut meski enumerasi direktori tidak memiliki entry untuknya. Jika referensi terakhir ditutup sebelum file ditautkan ke namespace, objek sementara tersebut hilang.

Dukungan filesystem merupakan syarat interface ini. Kernel yang mengimplementasikan O_TMPFILE tidak berarti setiap filesystem yang di-mount menerima flag tersebut. Aplikasi yang bergantung pada mekanisme ini memerlukan fallback eksplisit atau kebijakan kegagalan eksplisit untuk filesystem yang menolaknya.

Fase tanpa nama menghapus satu kelas nama staging

Urutan staging konvensional sering membuat pathname sementara yang terlihat, menulis konten, lalu melakukan rename terhadap pathname tersebut ke lokasi akhir. Desain semacam itu dapat valid, tetapi nama sementara tetap merupakan objek namespace. Proses lain dengan akses direktori yang sesuai dapat mengamatinya, dan logika cleanup harus memperhitungkan nama yang tertinggal setelah proses terhenti.

Dengan O_TMPFILE, tidak ada filename staging selama persiapan. Karena itu tidak ada basename sementara yang dapat bertabrakan dengan creator lain dan tidak ada pathname yang dapat dibuka proses lain selama fase tersebut. Akses masih dapat dibagikan secara sengaja dengan mengirim file descriptor, jadi tanpa nama tidak berarti selalu privat dari setiap proses. Artinya, lookup pathname bukan jalur menuju objek sebelum publikasi.

Perbedaan itu relevan bagi threat model sekaligus cleanup. Menghapus pathname sementara menghapus race pathname di sekitar nama sementara tersebut, tetapi tidak menghapus kebutuhan otorisasi pada direktori, kanal transfer descriptor, atau operasi publikasi akhirnya.

Publikasi memasang nama pada inode yang sudah ada

Ketika O_EXCL tidak digabungkan dengan O_TMPFILE, Linux mengizinkan file tanpa nama ditautkan ke filesystem. Salah satu bentuk yang didokumentasikan memakai linkat() dengan old pathname kosong dan AT_EMPTY_PATH:

if (linkat(fd, "", dirfd, "report.bin", AT_EMPTY_PATH) == -1) {
    /* publikasi gagal; fd tetap merujuk ke file tanpa nama */
}

AT_EMPTY_PATH membuat fd mengidentifikasi objek sumber secara langsung. Bentuk ini memiliki syarat privilege: Linux memerlukan CAP_DAC_READ_SEARCH untuk linkat() dengan AT_EMPTY_PATH. Alternatif yang didokumentasikan, ketika procfs tersedia, adalah merujuk /proc/self/fd/<fd> dan memakai AT_SYMLINK_FOLLOW.

Poin semantik utamanya adalah bahwa publikasi menautkan objek yang sudah terisi. Operasi tersebut tidak menyalin byte dari file sementara ke file kedua. Metadata dan konten yang disiapkan melalui descriptor merupakan bagian dari inode yang menerima directory entry baru.

Menentukan O_EXCL bersama O_TMPFILE mengubah siklus hidup ini. Dalam kombinasi tersebut, file sementara tidak dapat kemudian ditautkan ke filesystem melalui mekanisme ini. Di sini O_EXCL tidak membawa arti create-if-absent yang lazim; flag tersebut secara eksplisit memblokir pemberian nama kemudian pada objek tanpa nama.

Memasang nama dengan linkat() tidak sama dengan perilaku penggantian rename(). Pembuatan hard link menargetkan directory entry baru untuk file yang sudah ada. Jika nama tujuan sudah ada, operasi link gagal dan tidak mengganti entry tersebut.

Hal ini membuat O_TMPFILE cocok untuk publikasi create-if-absent ketika nama akhir yang diinginkan harus belum dipakai. Workflow yang harus mengganti pathname yang sudah ada memerlukan operasi namespace tambahan dan perlu memperhitungkan semantiknya secara terpisah.

Batas tersebut juga memisahkan mekanisme ini dari crash durability. Link yang sukses membuat nama terlihat sesuai semantik namespace filesystem, tetapi visibility itu sendiri bukan janji bahwa data file dan metadata direktori sudah mencapai storage stabil. Aplikasi dengan kebutuhan crash durability tetap memerlukan operasi sinkronisasi yang sesuai dengan filesystem dan model kegagalannya.

Perbedaan yang sama berlaku pada atomicity tingkat aplikasi. Menyiapkan satu file tanpa nama mencegah observer melihat urutan byte parsialnya melalui pathname, tetapi tidak mengoordinasikan state database, banyak file, pesan remote, atau resource lain secara atomik.

Lifetime descriptor mengendalikan objek yang belum dipublikasikan

Sebelum publikasi, lifetime praktis file terikat pada referensi yang dipegang proses. Menutup descriptor terakhir tanpa menautkan objek tidak meninggalkan pathname yang dapat dipakai untuk memulihkannya. Penanganan error dapat membatalkan artefak yang belum lengkap dengan menutup descriptor, bukan mencari lalu menghapus nama staging yang dibuat sebelumnya.

Properti ini mengubah mekanisme cleanup tetapi juga membawa batas lifetime resource. Proses yang tanpa sengaja mempertahankan descriptor dapat mempertahankan file tanpa nama beserta storage yang dialokasikan. Ketiadaan directory entry dapat membuat konsumsi tersebut kurang terlihat bagi inspeksi yang berorientasi pathname. Kepemilikan descriptor dan perilaku close tetap menjadi bagian desain.

O_CLOEXEC relevan untuk alasan yang sama. Menetapkan close-on-exec saat pembuatan mencegah inheritance descriptor yang tidak disengaja melewati execve() dan memperpanjang lifetime objek. Penerapan flag secara atomik saat open juga menghindari jendela fcntl() terpisah pada program multithreaded.

Metadata dapat difinalisasi sebelum pemberian nama

Karena objek tanpa nama tersebut merupakan regular file terbuka yang normal, persiapan dapat mencakup operasi selain penulisan byte. Aplikasi dapat menetapkan permission dan metadata lain yang didukung melalui interface berbasis descriptor sebelum publikasi, dengan tetap tunduk pada aturan filesystem dan permission.

Hal ini mendukung invariant yang berguna: state pertama yang terlihat melalui pathname dapat sudah memiliki konten dan metadata yang dimaksud. Invariant itu terbatas pada properti yang benar-benar ditetapkan sebelum link dan pada observer yang mencapai file melalui pathname baru. Descriptor terbuka yang dipegang pihak lain tetap dapat mengakses inode yang sama, dan perubahan metadata berikutnya tetap mungkin kecuali kontrol terpisah mencegahnya.

Mode yang diberikan kepada open() ikut menentukan pemilihan permission awal sebagaimana semantik pembuatan yang didokumentasikan, termasuk efek kebijakan proses dan direktori. Menganggap mode akhir tanpa memeriksa hasil efektif dapat keliru pada deployment dengan kebijakan filesystem tambahan.

Mekanisme ini mempersempit batas namespace

O_TMPFILE paling tepat dideskripsikan sebagai pembuatan inode tanpa nama dengan opsi pemberian nama kemudian. Nilainya berasal dari celah yang dihapus: konstruksi file tidak lagi memerlukan directory entry sementara.

Properti tersebut menghilangkan tabrakan nama staging dan paparan pathname selama persiapan, sementara semantik descriptor tetap mengendalikan akses dan lifetime. Publikasi melalui linkat() membuat nama untuk inode yang telah disiapkan, tetapi tidak mengganti nama yang sudah ada dan tidak menggantikan sinkronisasi durability.

Batas desain yang dihasilkan bersifat eksplisit. Sebelum publikasi, file adalah objek kernel terbuka tanpa nama direktori. Setelah linking berhasil, objek yang sama menjadi bagian dari namespace filesystem. Sistem yang menjaga kedua fase ini tetap terpisah dapat memperlakukan paparan konten parsial, cleanup, konflik nama, dan durability sebagai concern yang berbeda, bukan sebagai satu operasi pembuatan file yang tidak dapat dipisahkan.