Temporary Files in Unix

October 18th, 2008

EDIT: It is recommended to use mkstemp instead of tmpfile for security reasons. mkstemp does not work the same way as tmpfile, and so a manual call to unlink would be required to get the automatic delete behavior.

A recent question on Stack Overflow asked why locked files can be deleted in Linux, but not Windows. As the answer states, it’s because of the underlying nature of inodes in the Unix filesystem architecture.

Background

Files in Unix are stored in an inode, which contains all the metadata for the file. Paths on the filesystem then link to the inode that contains the actual file data. As a result, “deleting” a file from the filesystem is really just removing a link to and decrementing a reference count for an inode. An inode that is still opened by a running process, but unlinked from everywhere on the filesystem, will continue to exist until the process closes and the reference count drops to zero.

Temporary Files

In my answer to the question, I mentioned that Unix programs use this behavior explicitly to make temporary files that a) don’t clutter up the file system, and b) are more secure. In the comments for the question, I was asked for examples of this usage. I had learned this tidbit of trivia during an operating systems class in college, and had forgotten the specifics, so I decided to look it up.

glibc

I started poking around looking for an explicit example of this usage, and found out that the behavior is built directly into the glibc. Specifically, the tmpfile function, which creates a temporary file and opens a corresponding stream automatically unlinks the file internally! Here is the psuedocode for the tmpfile function in glibc 2.7, with setup and error-checking snipped for clarity:

FILE *tmpfile (void)
{
  char buf[FILENAME_MAX];
  int fd;
  FILE *f;
 
  /* get a new filename and open it  */
  fd = __gen_tempname(buf);
 
  /* Note that this relies on the Unix semantics that
     a file is not really removed until it is closed.  */
  (void) __unlink (buf);
 
  /* make a FILE* for the file */
  f = __fdopen(fd, "w+b");
 
  return f;
}

So the tmpfile function automatically takes advantage of this behavior and unlinks the inode after opening it.

Test Program

To see this in action, I wrote a small test program in C:

#include <stdio.h>
#include <unistd.h>
#include <sys/stat.h>
 
int main(int argc, char** argv)
{
    FILE *temp;
    struct stat buffer;
    char line[100];
    int fd;
 
    /* open a temporary file and  figure out its inode */
    temp = tmpfile();
    fd = fileno(temp);
    fstat(fd, &#038;buffer);
    printf("inode: %d\n", buffer.st_ino);
 
    /* wait */
    fgets(line, 100, stdin);
 
    return 0;
}

Running the program spits out an inode number then waits around with the file held open. Searching for filenames pointing to that inode returns nothing:

[neil /]$ find -inum 1221 2> /dev/null
[neil /]$

So it would seem that my vague memory from operating systems class was correct; temporary files can be created, opened, and unlinked and the facilities to do this are built in to the system libraries themselves.

Leave a Comment