Linux O_TMPFILE creates a regular file without first placing a name for that file in a directory. The caller receives a file descriptor and can write data, set metadata, or abandon the object while no pathname exposes the partially prepared file. If publication is required, a later link operation can attach a directory entry to the same inode.
This separates object construction from namespace publication. It does not make every surrounding filesystem operation transactional, and it does not provide replacement semantics for an existing destination. Its useful boundary is narrower: intermediate file state can remain reachable only through open references until the process explicitly creates a name.
Creation starts from a directory, not a destination pathname
O_TMPFILE is passed to open() or openat() together with O_RDWR or O_WRONLY. The pathname identifies a directory whose filesystem will contain the unnamed inode. It is not the eventual filename.
int fd = open("/srv/output", O_TMPFILE | O_RDWR | O_CLOEXEC, 0640);
if (fd == -1) {
/* handle unsupported filesystem, permissions, or other errors */
}The resulting descriptor refers to a new regular file. Data written through fd belongs to that file even though directory enumeration has no entry for it. If the last reference is closed before the file is linked into the namespace, the temporary object disappears.
Filesystem support is a condition of the interface. A kernel that implements O_TMPFILE does not imply that every mounted filesystem accepts the flag. Applications that depend on this mechanism need an explicit fallback or an explicit failure policy for filesystems that reject it.
The unnamed phase removes a class of staging names
A conventional staging sequence often creates a visible temporary pathname, writes content, then renames that pathname into place. Such a design can be sound, but the temporary name is still a namespace object. Other processes with suitable directory access can observe it, and cleanup logic must account for names left by interrupted processes.
With O_TMPFILE, no staging filename exists during preparation. There is consequently no temporary basename to collide with another creator and no pathname for another process to open during that phase. Access can still be shared deliberately by passing the file descriptor, so unnamed does not mean intrinsically private from every process. It means pathname lookup is not the route to the object before publication.
That distinction matters for threat models as well as cleanup. Removing a temporary pathname removes pathname races around that temporary name, but it does not remove authorization requirements on the directory, descriptor transfer channels, or the eventual publication operation.
Publication attaches a name to the existing inode
When O_EXCL is not combined with O_TMPFILE, Linux permits the unnamed file to be linked into the filesystem. One documented form uses linkat() with an empty old pathname and AT_EMPTY_PATH:
if (linkat(fd, "", dirfd, "report.bin", AT_EMPTY_PATH) == -1) {
/* publication failed; fd still refers to the unnamed file */
}AT_EMPTY_PATH makes fd identify the source object directly. This form has a privilege condition: Linux requires CAP_DAC_READ_SEARCH for linkat() with AT_EMPTY_PATH. The documented alternative, when procfs is available, is to refer to /proc/self/fd/<fd> and use AT_SYMLINK_FOLLOW.
The important semantic point is that publication links the already-populated object. It does not copy bytes from a temporary file into a second file. Metadata and content prepared through the descriptor belong to the inode that receives the new directory entry.
Specifying O_EXCL with O_TMPFILE changes this lifecycle. In that combination, the temporary file cannot later be linked into the filesystem using this mechanism. Here O_EXCL does not carry its usual create-if-absent meaning; it explicitly blocks later naming of the unnamed object.
Link publication is not replacement
Attaching a name with linkat() must not be conflated with rename() replacement behavior. A hard-link creation targets a new directory entry for an existing file. If the destination name already exists, the link operation fails rather than replacing that entry.
This makes O_TMPFILE a natural fit for create-if-absent publication when the desired final name must be unused. A workflow that must replace an existing pathname needs additional namespace operations and must reason about their separate semantics.
That boundary also separates this mechanism from crash durability. A successful link makes a name visible according to filesystem namespace semantics, but visibility is not itself a promise that file data and directory metadata have reached stable storage. Applications with a crash-durability requirement still need the synchronization operations appropriate to the filesystem and failure model.
The same distinction applies to application-level atomicity. Preparing one unnamed file prevents observers from seeing its partial byte sequence through a pathname, but it does not atomically coordinate database state, multiple files, remote messages, or other resources.
Descriptor lifetime controls the unpublished object
Before publication, the file’s practical lifetime is tied to references held by processes. Closing the final descriptor without linking the object leaves no pathname through which it can be recovered. Error handling can therefore abandon an incomplete artifact by closing its descriptor instead of discovering and unlinking a generated staging name.
This property changes cleanup mechanics but also raises a resource-lifetime constraint. A process that accidentally retains descriptors can retain unnamed files and their allocated storage. The absence of a directory entry can make such consumption less obvious to pathname-oriented inspection. Descriptor ownership and close behavior remain part of the design.
O_CLOEXEC is relevant for the same reason. Setting close-on-exec during creation prevents an unintended descriptor inheritance across execve() from extending the object’s lifetime. Applying the flag atomically at open time also avoids a separate fcntl() window in multithreaded programs.
Metadata can be finalized before naming
Because the unnamed object is a normal open regular file, preparation can include operations beyond byte writes. Applications can set permissions and other supported metadata through descriptor-oriented interfaces before publication, subject to filesystem and permission rules.
This supports a useful invariant: the first pathname-visible state can already contain the intended content and metadata. The invariant is limited to properties actually established before the link and to observers that reach the file through the new pathname. Open descriptors held elsewhere can still access the same inode, and later metadata changes remain possible unless separate controls prevent them.
The mode passed to open() participates in initial permission selection in the same manner documented for creation, including the effects of process and directory policy. Treating the final mode as an assumption rather than checking the effective result can be incorrect on deployments with additional filesystem policy.
The mechanism narrows the namespace boundary
O_TMPFILE is most precise when described as unnamed inode creation with optional later naming. Its value comes from the gap it removes: file construction no longer requires a temporary directory entry.
That property eliminates staging-name collisions and pathname exposure during preparation, while descriptor semantics continue to govern access and lifetime. Publication through linkat() creates a name for the prepared inode, but does not replace an existing name and does not substitute for durability synchronization.
The resulting design boundary is explicit. Before publication, the file is an open kernel object without a directory name. After successful linking, the same object participates in the filesystem namespace. Systems that keep those two phases distinct can reason about partial content exposure, cleanup, naming conflicts, and durability as separate concerns rather than treating temporary-file creation as one indivisible operation.