Add mkostemp() and mkostemps().
These are like mkstemp() and mkstemps() but allow passing open(2) flags like O_CLOEXEC.
This commit is contained in:
parent
5d82a21469
commit
65ba8dff5f
@ -282,6 +282,8 @@ const char *
|
||||
int heapsort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
int l64a_r(long, char *, int);
|
||||
int mergesort(void *, size_t, size_t, int (*)(const void *, const void *));
|
||||
int mkostemp(char *, int);
|
||||
int mkostemps(char *, int, int);
|
||||
void qsort_r(void *, size_t, size_t, void *,
|
||||
int (*)(void *, const void *, const void *));
|
||||
int radixsort(const unsigned char **, int, const unsigned char *,
|
||||
|
@ -60,7 +60,8 @@ MLINKS+=getc.3 fgetc.3 getc.3 getc_unlocked.3 getc.3 getchar.3 \
|
||||
getc.3 getchar_unlocked.3 getc.3 getw.3
|
||||
MLINKS+=getline.3 getdelim.3
|
||||
MLINKS+=getwc.3 fgetwc.3 getwc.3 getwchar.3
|
||||
MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3
|
||||
MLINKS+=mktemp.3 mkdtemp.3 mktemp.3 mkstemp.3 mktemp.3 mkstemps.3 \
|
||||
mktemp.3 mkostemp.3 mktemp.3 mkostemps.3
|
||||
MLINKS+=open_memstream.3 open_wmemstream.3
|
||||
MLINKS+=printf.3 asprintf.3 printf.3 dprintf.3 printf.3 fprintf.3 \
|
||||
printf.3 snprintf.3 printf.3 sprintf.3 \
|
||||
|
@ -158,6 +158,8 @@ FBSD_1.3 {
|
||||
fmemopen;
|
||||
open_memstream;
|
||||
open_wmemstream;
|
||||
mkostemp;
|
||||
mkostemps;
|
||||
};
|
||||
|
||||
FBSDprivate_1.0 {
|
||||
|
@ -28,7 +28,7 @@
|
||||
.\" @(#)mktemp.3 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd July 5, 2013
|
||||
.Dd August 8, 2013
|
||||
.Dt MKTEMP 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -42,6 +42,10 @@
|
||||
.Fn mktemp "char *template"
|
||||
.Ft int
|
||||
.Fn mkstemp "char *template"
|
||||
.Ft int
|
||||
.Fn mkostemp "char *template" "int oflags"
|
||||
.Ft int
|
||||
.Fn mkostemps "char *template" "int suffixlen" "int oflags"
|
||||
.Ft char *
|
||||
.Fn mkdtemp "char *template"
|
||||
.In unistd.h
|
||||
@ -85,16 +89,41 @@ This avoids the race between testing for a file's existence and opening it
|
||||
for use.
|
||||
.Pp
|
||||
The
|
||||
.Fn mkostemp
|
||||
function
|
||||
is like
|
||||
.Fn mkstemp
|
||||
but allows specifying additional
|
||||
.Xr open 2
|
||||
flags (defined in
|
||||
.In fcntl.h ) .
|
||||
The permitted flags are
|
||||
.Dv O_APPEND ,
|
||||
.Dv O_DIRECT ,
|
||||
.Dv O_SHLOCK ,
|
||||
.Dv O_EXLOCK ,
|
||||
.Dv O_SYNC
|
||||
and
|
||||
.Dv O_CLOEXEC .
|
||||
.Pp
|
||||
The
|
||||
.Fn mkstemps
|
||||
function acts the same as
|
||||
.Fn mkstemp ,
|
||||
except it permits a suffix to exist in the template.
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions act the same as
|
||||
.Fn mkstemp
|
||||
and
|
||||
.Fn mkostemp
|
||||
respectively,
|
||||
except they permit a suffix to exist in the template.
|
||||
The template should be of the form
|
||||
.Pa /tmp/tmpXXXXXXsuffix .
|
||||
The
|
||||
.Fn mkstemps
|
||||
and
|
||||
.Fn mkostemps
|
||||
function
|
||||
is told the length of the suffix string.
|
||||
are told the length of the suffix string.
|
||||
.Pp
|
||||
The
|
||||
.Fn mkdtemp
|
||||
@ -110,9 +139,11 @@ functions return a pointer to the template on success and
|
||||
.Dv NULL
|
||||
on failure.
|
||||
The
|
||||
.Fn mkstemp
|
||||
and
|
||||
.Fn mkstemp ,
|
||||
.Fn mkostemp
|
||||
.Fn mkstemps
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions
|
||||
return \-1 if no suitable file could be created.
|
||||
If either call fails an error code is placed in the global variable
|
||||
@ -120,7 +151,9 @@ If either call fails an error code is placed in the global variable
|
||||
.Sh ERRORS
|
||||
The
|
||||
.Fn mkstemp ,
|
||||
.Fn mkstemps
|
||||
.Fn mkostemp ,
|
||||
.Fn mkstemps ,
|
||||
.Fn mkostemps
|
||||
and
|
||||
.Fn mkdtemp
|
||||
functions
|
||||
@ -133,8 +166,25 @@ The pathname portion of the template is not an existing directory.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn mkostemp
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions
|
||||
may also set
|
||||
.Va errno
|
||||
to the following value:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EINVAL
|
||||
The
|
||||
.Fa oflags
|
||||
argument is invalid.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn mkstemp ,
|
||||
.Fn mkstemps
|
||||
.Fn mkostemp ,
|
||||
.Fn mkstemps ,
|
||||
.Fn mkostemps
|
||||
and
|
||||
.Fn mkdtemp
|
||||
functions
|
||||
@ -145,9 +195,11 @@ to any value specified by the
|
||||
function.
|
||||
.Pp
|
||||
The
|
||||
.Fn mkstemp
|
||||
and
|
||||
.Fn mkstemp ,
|
||||
.Fn mkostemp ,
|
||||
.Fn mkstemps
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions
|
||||
may also set
|
||||
.Va errno
|
||||
@ -209,8 +261,11 @@ function is expected to conform to
|
||||
and is not specified by
|
||||
.St -p1003.1-2008 .
|
||||
The
|
||||
.Fn mkostemp ,
|
||||
.Fn mkstemps
|
||||
function does not conform to any standard.
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions do not conform to any standard.
|
||||
.Sh HISTORY
|
||||
A
|
||||
.Fn mktemp
|
||||
@ -232,6 +287,12 @@ function first appeared in
|
||||
.Ox 2.4 ,
|
||||
and later in
|
||||
.Fx 3.4 .
|
||||
The
|
||||
.Fn mkostemp
|
||||
and
|
||||
.Fn mkostemps
|
||||
functions appeared in
|
||||
.Fx 10.0 .
|
||||
.Sh BUGS
|
||||
This family of functions produces filenames which can be guessed,
|
||||
though the risk is minimized when large numbers of
|
||||
@ -248,6 +309,8 @@ and opening it for use
|
||||
particularly dangerous from a security perspective.
|
||||
Whenever it is possible,
|
||||
.Fn mkstemp
|
||||
or
|
||||
.Fn mkostemp
|
||||
should be used instead, since it does not have the race condition.
|
||||
If
|
||||
.Fn mkstemp
|
||||
|
@ -47,17 +47,33 @@ __FBSDID("$FreeBSD$");
|
||||
|
||||
char *_mktemp(char *);
|
||||
|
||||
static int _gettemp(char *, int *, int, int);
|
||||
static int _gettemp(char *, int *, int, int, int);
|
||||
|
||||
static const unsigned char padchar[] =
|
||||
"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
||||
|
||||
int
|
||||
mkostemps(char *path, int slen, int oflags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd, 0, slen, oflags) ? fd : -1);
|
||||
}
|
||||
|
||||
int
|
||||
mkstemps(char *path, int slen)
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd, 0, slen) ? fd : -1);
|
||||
return (_gettemp(path, &fd, 0, slen, 0) ? fd : -1);
|
||||
}
|
||||
|
||||
int
|
||||
mkostemp(char *path, int oflags)
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd, 0, 0, oflags) ? fd : -1);
|
||||
}
|
||||
|
||||
int
|
||||
@ -65,19 +81,19 @@ mkstemp(char *path)
|
||||
{
|
||||
int fd;
|
||||
|
||||
return (_gettemp(path, &fd, 0, 0) ? fd : -1);
|
||||
return (_gettemp(path, &fd, 0, 0, 0) ? fd : -1);
|
||||
}
|
||||
|
||||
char *
|
||||
mkdtemp(char *path)
|
||||
{
|
||||
return (_gettemp(path, (int *)NULL, 1, 0) ? path : (char *)NULL);
|
||||
return (_gettemp(path, (int *)NULL, 1, 0, 0) ? path : (char *)NULL);
|
||||
}
|
||||
|
||||
char *
|
||||
_mktemp(char *path)
|
||||
{
|
||||
return (_gettemp(path, (int *)NULL, 0, 0) ? path : (char *)NULL);
|
||||
return (_gettemp(path, (int *)NULL, 0, 0, 0) ? path : (char *)NULL);
|
||||
}
|
||||
|
||||
__warn_references(mktemp,
|
||||
@ -90,7 +106,7 @@ mktemp(char *path)
|
||||
}
|
||||
|
||||
static int
|
||||
_gettemp(char *path, int *doopen, int domkdir, int slen)
|
||||
_gettemp(char *path, int *doopen, int domkdir, int slen, int oflags)
|
||||
{
|
||||
char *start, *trv, *suffp, *carryp;
|
||||
char *pad;
|
||||
@ -99,7 +115,9 @@ _gettemp(char *path, int *doopen, int domkdir, int slen)
|
||||
uint32_t rand;
|
||||
char carrybuf[MAXPATHLEN];
|
||||
|
||||
if ((doopen != NULL && domkdir) || slen < 0) {
|
||||
if ((doopen != NULL && domkdir) || slen < 0 ||
|
||||
(oflags & ~(O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC |
|
||||
O_CLOEXEC)) != 0) {
|
||||
errno = EINVAL;
|
||||
return (0);
|
||||
}
|
||||
@ -151,7 +169,8 @@ _gettemp(char *path, int *doopen, int domkdir, int slen)
|
||||
for (;;) {
|
||||
if (doopen) {
|
||||
if ((*doopen =
|
||||
_open(path, O_CREAT|O_EXCL|O_RDWR, 0600)) >= 0)
|
||||
_open(path, O_CREAT|O_EXCL|O_RDWR|oflags, 0600)) >=
|
||||
0)
|
||||
return (1);
|
||||
if (errno != EEXIST)
|
||||
return (0);
|
||||
|
@ -1,8 +1,8 @@
|
||||
# $FreeBSD$
|
||||
|
||||
TESTS= test-fmemopen test-getdelim test-open_memstream test-open_wmemstream \
|
||||
test-perror test-print-positional test-printbasic test-printfloat \
|
||||
test-scanfloat
|
||||
TESTS= test-fmemopen test-getdelim test-mkostemp test-open_memstream \
|
||||
test-open_wmemstream test-perror test-print-positional test-printbasic \
|
||||
test-printfloat test-scanfloat
|
||||
CFLAGS+= -lm
|
||||
|
||||
.PHONY: tests
|
||||
|
164
tools/regression/lib/libc/stdio/test-mkostemp.c
Normal file
164
tools/regression/lib/libc/stdio/test-mkostemp.c
Normal file
@ -0,0 +1,164 @@
|
||||
/*-
|
||||
* Copyright (c) 2013 Jilles Tjoelker
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Test program for mkostemp().
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <paths.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char template[] = _PATH_TMP "mkostemp.XXXXXXXX";
|
||||
static int testnum;
|
||||
|
||||
#define MISCFLAGS (O_APPEND | O_DIRECT | O_SHLOCK | O_EXLOCK | O_SYNC)
|
||||
|
||||
static void
|
||||
test_one(int oflags)
|
||||
{
|
||||
char tmpf[sizeof(template)];
|
||||
struct stat st1, st2;
|
||||
int fd;
|
||||
|
||||
memcpy(tmpf, template, sizeof(tmpf));
|
||||
fd = mkostemp(tmpf, oflags);
|
||||
if (fd < 0) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"mkostemp() reported failure: %s\n",
|
||||
testnum++, oflags, strerror(errno));
|
||||
return;
|
||||
}
|
||||
if (memcmp(tmpf, template, sizeof(tmpf) - 8 - 1) != 0) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"returned pathname does not match template: %s\n",
|
||||
testnum++, oflags, tmpf);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
if (fcntl(fd, F_GETFD) !=
|
||||
(oflags & O_CLOEXEC ? FD_CLOEXEC : 0)) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"close-on-exec flag incorrect\n",
|
||||
testnum++, oflags);
|
||||
break;
|
||||
}
|
||||
if ((fcntl(fd, F_GETFL) & MISCFLAGS) != (oflags & MISCFLAGS)) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"open flags incorrect\n",
|
||||
testnum++, oflags);
|
||||
break;
|
||||
}
|
||||
if (stat(tmpf, &st1) == -1) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"cannot stat returned pathname %s: %s\n",
|
||||
testnum++, oflags, tmpf, strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (fstat(fd, &st2) == -1) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"cannot fstat returned fd %d: %s\n",
|
||||
testnum++, oflags, fd, strerror(errno));
|
||||
break;
|
||||
}
|
||||
if (!S_ISREG(st1.st_mode) || (st1.st_mode & 0777) != 0600 ||
|
||||
st1.st_nlink != 1 || st1.st_size != 0) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"named file attributes incorrect\n",
|
||||
testnum++, oflags);
|
||||
break;
|
||||
}
|
||||
if (!S_ISREG(st2.st_mode) || (st2.st_mode & 0777) != 0600 ||
|
||||
st2.st_nlink != 1 || st2.st_size != 0) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"opened file attributes incorrect\n",
|
||||
testnum++, oflags);
|
||||
break;
|
||||
}
|
||||
if (st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) {
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"named and opened file do not match\n",
|
||||
testnum++, oflags);
|
||||
break;
|
||||
}
|
||||
(void)unlink(tmpf);
|
||||
if (fstat(fd, &st2) == -1)
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"cannot fstat returned fd %d again: %s\n",
|
||||
testnum++, oflags, fd, strerror(errno));
|
||||
else if (st2.st_nlink != 0)
|
||||
printf("not ok %d - oflags=%#x "
|
||||
"st_nlink is not 0 after unlink\n",
|
||||
testnum++, oflags);
|
||||
else
|
||||
printf("ok %d - oflags=%#x\n", testnum++, oflags);
|
||||
(void)close(fd);
|
||||
return;
|
||||
} while (0);
|
||||
(void)close(fd);
|
||||
(void)unlink(tmpf);
|
||||
}
|
||||
|
||||
static void
|
||||
test_badflags(void)
|
||||
{
|
||||
char tmpf[sizeof(template)];
|
||||
|
||||
memcpy(tmpf, template, sizeof(tmpf));
|
||||
if (mkostemp(tmpf, O_CREAT) == -1)
|
||||
printf("ok %d - mkostemp(O_CREAT) correctly failed\n",
|
||||
testnum++);
|
||||
else
|
||||
printf("not ok %d - mkostemp(O_CREAT) wrongly succeeded\n",
|
||||
testnum++);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
int i;
|
||||
const char *e;
|
||||
|
||||
printf("1..5\n");
|
||||
testnum = 1;
|
||||
|
||||
test_one(0);
|
||||
test_one(O_CLOEXEC);
|
||||
test_one(O_APPEND);
|
||||
test_one(O_APPEND | O_CLOEXEC);
|
||||
test_badflags();
|
||||
|
||||
return (0);
|
||||
}
|
Loading…
Reference in New Issue
Block a user