Temporary Files
Quite often, we need temporary files in our programs. Some intermediate data needs to be stored and the file can be discarded when the process terminates. There are multiple ways of creating temporary files in Linux. The best way to create a temporary file in Linux is to use the O_TMPFILE flag in the open system call. The tmpfile function creates a temporary file and returns a file pointer. The mkstemp function creates a temporary file and returns a file descriptor. The mkdtemp function creates a temporary directory. The mktemp command is for creating a temporary file or directory from the shell. We will look at all these approaches, one by one.
Table of Contents
1.0 O_TMPFILE flag
The O_TMPFILE flag in the open system call creates an unnamed regular temporary file. The first parameter to the open call is a directory name. An i-node is created on this directory’s filesystem. The flags are O_TMPFILE | O_RDWR | O_EXCL. The file has to be opened with either O_RDWR or O_WRONLY flag. The O_EXCL flag ensures that the file cannot be given a name. When the last close for the file descriptor is done, the file is removed from the filesystem.
The O_TMPFILE flag is specific to Linux. In order to compile with the O_TMPFILE flag, the symbolic constant _GNU_SOURCE needs to be defined before the #include statement for the fcntl.h header file. An example C program is given below.
/* * * check-tmp.c: check open call for temporary file * */ #define _GNU_SOURCE #include <stdio.h> #include <sys/types.h> #include <unistd.h> #include <sys/stat.h> #include <fcntl.h> #include <stdlib.h> #include <string.h> #include <limits.h> char buf [PATH_MAX]; int main (int argc, char **argv) { int fd, num; char *ptr; if ((ptr = getcwd (buf, sizeof (buf))) == NULL) { perror ("getcwd"); exit (EXIT_FAILURE); } num = strlen (ptr); printf ("Current working directory = %s\n", ptr); if ((fd = open (ptr, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR)) == -1) { perror ("open"); exit (EXIT_FAILURE); } if (write (fd, buf, strlen (buf)) == -1) { perror ("write"); exit (EXIT_FAILURE); } if (lseek (fd, 0, SEEK_SET) == -1) { perror ("lseek"); exit (EXIT_FAILURE); } memset (buf, '#', sizeof (buf)); if (read (fd, buf, num) == -1) { perror ("write"); exit (EXIT_FAILURE); } buf [num] = '\0'; printf ("%s\n", buf); if (close (fd) == -1) { perror ("close"); exit (EXIT_FAILURE); } exit (EXIT_SUCCESS); }
If O_EXCL flag is not used, the file can be assigned a name with the linkat(2) and, instead of temporary, it becomes a permanent file in the filesystem. For instance,
... if ((fd = open (ptr, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR)) == -1) { perror ("open"); exit (EXIT_FAILURE); } ... snprintf (buf, sizeof (buf), "/proc/self/fd/%d", fd); if (linkat (AT_FDCWD, buf, AT_FDCWD, "mytmpfile", AT_SYMLINK_FOLLOW) == -1) { perror ("linkat"); exit (EXIT_FAILURE); } ...
after the above call, the file is saved as “mytmpfile” in the current working directory.
2.0 tmpfile function
#include <stdio.h> FILE *tmpfile (void);
The tmpfile function creates a temporary file. It returns a FILE pointer or NULL in case of error. The file is automatically opened in read/write mode and is deleted when it is closed, or, when the calling process terminates. An example program using tmpfile is given below.
#include <stdio.h> #include <stdlib.h> #include <string.h> void error (char *str); int main (int argc, char **argv) { char buf [128]; FILE *fp; if ((fp = tmpfile ()) == NULL) error ("tmpfile"); strcpy (buf, "Hello World!\n"); if (fwrite (buf, strlen (buf), 1, fp) != 1) error ("fwrite"); } void error (char *str) { perror (str); exit (1); }
3.0 mkstemp function
#include <stdlib.h> int mkstemp (char *template);
The mkstemp function creates a unique temporary file, opens it and returns a file descriptor to it. The file is created from the parameter, template, whose last six characters must be “XXXXXX”. mkstemp modifies the six X’s to get a unique filename. Since the template is modified, it should not be a constant string. It should be a null terminated character array. The file is created with 0600 permissions, which means read and write permissions for the owner and none for the group and others. The file is opened with O_EXCL flag, which guarantees that the caller process has created the file.
As an example, we can use mkstemp to create a temporary file in code like this.
#include <stdio.h> #include <string.h> #include <stdlib.h> #include <unistd.h> void error (char *str); int main (int argc, char **argv) { char filename [64] = "/tmp/mkstemp-example-XXXXXX"; char buf [128]; int fd; if ((fd = mkstemp (filename)) == -1) error ("mkstemp"); unlink (filename); strcpy (buf, "Hello World!\n"); if (write (fd, buf, strlen (buf)) == -1) error ("write"); } void error (char *str) { perror (str); exit (1); }
The unlink call deletes the file. Since the file descriptor is in use, the file inode and data stay in the filesystem. When the process terminates, there is no link to the file and no process has it open, and so, it is deleted.
4.0 Temporary directory with mkdtemp function
#include <stdlib.h> char *mkdtemp (char *template);
The mkdtemp function creates a temporary directory using the template. The last six characters of the template must be “XXXXXX”. mkdtemp changes the X’s in the template to generate a unique pathname. template is modified and must not be a constant string. It should be a null terminated character array. The directory is created with the permissions 0700. mkdtemp returns a pointer to the modified template on success and NULL on failure.
5.0 mktemp command
The mktemp command creates a temporary file or directory and prints its name. The command usage is,
mktemp [OPTION]... [TEMPLATE]
The TEMPLATE is a character string containing at least 3 consecutive X’s at the end. The X’s are modified to get a unique file name. The important options are -d to create a temporary directory and not a file and –tmpdir[=DIR]. With the tmpdir option, the TEMPLATE is interpreted with respect to the DIR specified with tmpdir. If tmpdir is specified without the DIR, the directory in the environment variable $TMPDIR is used and if $TMPDIR is not set /tmp is used.
If TEMPLATE is not specified then a default TEMPLATE value tmp.XXXXXXXXXX is used and the option –tmpdir is implied. Some examples of using mktemp are given below. The environment variable $TMPDIR is not set.
$ # make a temp file with file name starting with "abc" $ # and three other characters in the current directory $ mktemp abcXXX abc2nD $ # make a temp file in /tmp $ mktemp /tmp/tmp.Xzt1K9T2Fk $ # make a temp directory $ mktemp -d mytempdirXXX mytempdir7GH