Quite often a programmer will want to replace a use of
mktemp() with
mkstemp(), usually to avoid the problems described above. Doing this correctly requires a good understanding of the code in question.
For instance, code of this form:
char sfn[15] = "";
FILE *sfp;
strlcpy(sfn, "/tmp/ed.XXXXXX", sizeof sfn);
if (mktemp(sfn) == NULL || (sfp = fopen(sfn, "w+")) == NULL) {
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
return (NULL);
}
return (sfp);
should be rewritten like this:
char sfn[15] = "";
FILE *sfp;
int fd = -1;
strlcpy(sfn, "/tmp/ed.XXXXXX", sizeof sfn);
if ((fd = mkstemp(sfn)) == -1 ||
(sfp = fdopen(fd, "w+")) == NULL) {
if (fd != -1) {
unlink(sfn);
close(fd);
}
fprintf(stderr, "%s: %s\n", sfn, strerror(errno));
return (NULL);
}
return (sfp);
Often one will find code which uses
mktemp() very early on, perhaps to globally initialize the template nicely, but the code which calls
open(2) or
fopen(3) on that filename will occur much later. (In almost all cases, the use of
fopen(3) will mean that the flags
O_CREAT |
O_EXCL are not given to
open(2), and thus a symbolic link race becomes possible, hence making necessary the use of
fdopen(3) as seen above). Furthermore, one must be careful about code which opens, closes, and then re-opens the file in question. Finally, one must ensure that upon error the temporary file is removed correctly.
There are also cases where modifying the code to use
mktemp(), in concert with
open(2) using the flags
O_CREAT |
O_EXCL, is better, as long as the code retries a new template if
open(2) fails with an
errno of
EEXIST.