diff --git a/newlib/ChangeLog b/newlib/ChangeLog index 69ef08b8a..005ff984a 100644 --- a/newlib/ChangeLog +++ b/newlib/ChangeLog @@ -1,5 +1,14 @@ 2009-07-03 Eric Blake + Add mkdtemp, mkstemps. + * libc/stdio/mktemp.c: Fix documentation. + (_gettemp): Add domkdir and length parameters. Check for + insufficient 'X' suffix. Drop cygwin-specific code. + (_mkstemp_r, _mktemp_r, mkstemp, mktemp): Adjust clients. + (_mkdtemp_r, _mkstemps_r, mkdtemp, mkstemps): New functions. + * libc/include/stdlib.h (_mkdtemp_r, _mkstemps_r, mkdtemp) + (mkstemps): Declare them. + Add fpurge. * libc/stdio/fpurge.c (fpurge, _fpurge_r): New file. * libc/stdio/Makefile.am (ELIX_4_SOURCES, CHEWOUT_FILES, fpurge): diff --git a/newlib/libc/include/stdlib.h b/newlib/libc/include/stdlib.h index 8f7d31e18..9dcd5e251 100644 --- a/newlib/libc/include/stdlib.h +++ b/newlib/libc/include/stdlib.h @@ -98,10 +98,14 @@ size_t _EXFUN(wcstombs,(char *, const wchar_t *, size_t)); size_t _EXFUN(_wcstombs_r,(struct _reent *, char *, const wchar_t *, size_t, _mbstate_t *)); #ifndef __STRICT_ANSI__ #ifndef _REENT_ONLY -int _EXFUN(mkstemp,(char *)); -char * _EXFUN(mktemp,(char *) _ATTRIBUTE ((warning ("the use of `mktemp' is dangerous; use `mkstemp' instead")))); +char * _EXFUN(mkdtemp,(char *)); +int _EXFUN(mkstemp,(char *)); +int _EXFUN(mkstemps,(char *, int)); +char * _EXFUN(mktemp,(char *) _ATTRIBUTE ((warning ("the use of `mktemp' is dangerous; use `mkstemp' instead")))); #endif +char * _EXFUN(_mkdtemp_r, (struct _reent *, char *)); int _EXFUN(_mkstemp_r, (struct _reent *, char *)); +int _EXFUN(_mkstemps_r, (struct _reent *, char *, int)); char * _EXFUN(_mktemp_r, (struct _reent *, char *) _ATTRIBUTE ((warning ("the use of `mktemp' is dangerous; use `mkstemp' instead")))); #endif _VOID _EXFUN(qsort,(_PTR __base, size_t __nmemb, size_t __size, int(*_compar)(const _PTR, const _PTR))); diff --git a/newlib/libc/stdio/mktemp.c b/newlib/libc/stdio/mktemp.c index c4347cd05..167ee9b0f 100644 --- a/newlib/libc/stdio/mktemp.c +++ b/newlib/libc/stdio/mktemp.c @@ -23,27 +23,40 @@ /* FUNCTION -<>, <>---generate unused file name +<>, <>, <>---generate unused file name +<>---generate unused directory INDEX mktemp +INDEX + mkdtemp INDEX mkstemp +INDEX + mkstemps INDEX _mktemp_r +INDEX + _mkdtemp_r INDEX _mkstemp_r +INDEX + _mkstemps_r ANSI_SYNOPSIS - #include + #include char *mktemp(char *<[path]>); + char *mkdtemp(char *<[path]>); int mkstemp(char *<[path]>); + int mkstemps(char *<[path]>, int <[suffixlen]>); char *_mktemp_r(struct _reent *<[reent]>, char *<[path]>); + char *_mkdtemp_r(struct _reent *<[reent]>, char *<[path]>); int *_mkstemp_r(struct _reent *<[reent]>, char *<[path]>); + int *_mkstemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>); TRAD_SYNOPSIS - #include + #include char *mktemp(<[path]>) char *<[path]>; @@ -59,20 +72,24 @@ TRAD_SYNOPSIS char *<[path]>; DESCRIPTION -<> and <> attempt to generate a file name that is not -yet in use for any existing file. <> creates the file and -opens it for reading and writing; <> simply generates the file name. +<>, <>, and <> attempt to generate a file name +that is not yet in use for any existing file. <> and <> +create the file and open it for reading and writing; <> simply +generates the file name (making <> a security risk). <> +attempts to create a directory instead of a file, with a permissions +mask of 0700. You supply a simple pattern for the generated file name, as the string at <[path]>. The pattern should be a valid filename (including path -information if you wish) ending with some number of `<>' +information if you wish) ending with at least six `<>' characters. The generated filename will match the leading part of the name you supply, with the trailing `<>' characters replaced by some -combination of digits and letters. +combination of digits and letters. With <>, the `<>' +characters end <[suffixlen]> bytes before the end of the string. -The alternate functions <<_mktemp_r>> and <<_mkstemp_r>> are reentrant -versions. The extra argument <[reent]> is a pointer to a reentrancy -structure. +The alternate functions <<_mktemp_r>>, <<_mkdtemp_r>>, <<_mkstemp_r>>, +and <<_mkstemps_r>> are reentrant versions. The extra argument <[reent]> +is a pointer to a reentrancy structure. RETURNS <> returns the pointer <[path]> to the modified string @@ -80,8 +97,11 @@ representing an unused filename, unless it could not generate one, or the pattern you provided is not suitable for a filename; in that case, it returns <>. -<> returns a file descriptor to the newly created file, -unless it could not generate an unused filename, or the pattern you +<> returns the pointer <[path]> to the modified string if the +directory was created, otherwise it returns <>. + +<> and <> return a file descriptor to the newly created +file, unless it could not generate an unused filename, or the pattern you provided is not suitable for a filename; in that case, it returns <<-1>>. @@ -94,9 +114,11 @@ instead. It doesn't suffer the race condition. PORTABILITY ANSI C does not require either <> or <>; the System -V Interface Definition requires <> as of Issue 2. +V Interface Definition requires <> as of Issue 2. POSIX 2001 +requires <>, and POSIX 2008 requires <>, but +<> is not standardized. -Supporting OS subroutines required: <>, <>, <>. +Supporting OS subroutines required: <>, <>, <>, <>. */ #include <_ansi.h> @@ -109,12 +131,15 @@ Supporting OS subroutines required: <>, <>, <>. #include static int -_DEFUN(_gettemp, (ptr, path, doopen), +_DEFUN(_gettemp, (ptr, path, doopen, domkdir, suffixlen), struct _reent *ptr _AND char *path _AND - register int *doopen) + register int *doopen _AND + int domkdir _AND + size_t suffixlen) { register char *start, *trv; + char *end; #ifdef __USE_INTERNAL_STAT64 struct stat64 sbuf; #else @@ -125,11 +150,23 @@ _DEFUN(_gettemp, (ptr, path, doopen), pid = _getpid_r (ptr); for (trv = path; *trv; ++trv) /* extra X's get set to 0's */ continue; - while (*--trv == 'X') + if (trv - path < suffixlen) + { + ptr->_errno = EINVAL; + return 0; + } + trv -= suffixlen; + end = trv; + while (path < trv && *--trv == 'X') { *trv = (pid % 10) + '0'; pid /= 10; } + if (end - trv < 6) + { + ptr->_errno = EINVAL; + return 0; + } /* * Check the target directory; if you have six X's and it @@ -161,16 +198,22 @@ _DEFUN(_gettemp, (ptr, path, doopen), for (;;) { +#if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4 + if (domkdir) + { + if (_mkdir_r (ptr, path, 0700) == 0) + return 1; + if (ptr->_errno != EEXIST) + return 0; + } + else +#endif /* _ELIX_LEVEL */ if (doopen) { if ((*doopen = _open_r (ptr, path, O_CREAT | O_EXCL | O_RDWR, 0600)) >= 0) return 1; -#if defined(__CYGWIN__) - if (ptr->_errno != EEXIST && ptr->_errno != EACCES) -#else if (ptr->_errno != EEXIST) -#endif return 0; } #ifdef __USE_INTERNAL_STAT64 @@ -183,12 +226,13 @@ _DEFUN(_gettemp, (ptr, path, doopen), /* tricky little algorithm for backward compatibility */ for (trv = start;;) { - if (!*trv) + if (trv == end) return 0; if (*trv == 'z') *trv++ = 'a'; else { + /* Safe, since it only encounters 7-bit characters. */ if (isdigit (*trv)) *trv = 'a'; else @@ -207,15 +251,36 @@ _DEFUN(_mkstemp_r, (ptr, path), { int fd; - return (_gettemp (ptr, path, &fd) ? fd : -1); + return (_gettemp (ptr, path, &fd, 0, 0) ? fd : -1); } +#if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4 +char * +_DEFUN(_mkdtemp_r, (ptr, path), + struct _reent *ptr _AND + char *path) +{ + return (_gettemp (ptr, path, (int *) NULL, 1, 0) ? path : NULL); +} + +int +_DEFUN(_mkstemps_r, (ptr, path, len), + struct _reent *ptr _AND + char *path _AND + int len) +{ + int fd; + + return (_gettemp (ptr, path, &fd, 0, len) ? fd : -1); +} +#endif /* _ELIX_LEVEL */ + char * _DEFUN(_mktemp_r, (ptr, path), struct _reent *ptr _AND char *path) { - return (_gettemp (ptr, path, (int *) NULL) ? path : (char *) NULL); + return (_gettemp (ptr, path, (int *) NULL, 0, 0) ? path : (char *) NULL); } #ifndef _REENT_ONLY @@ -226,14 +291,33 @@ _DEFUN(mkstemp, (path), { int fd; - return (_gettemp (_REENT, path, &fd) ? fd : -1); + return (_gettemp (_REENT, path, &fd, 0, 0) ? fd : -1); } +# if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4 +char * +_DEFUN(mkdemp, (path), + char *path) +{ + return (_gettemp (_REENT, path, (int *) NULL, 1, 0) ? path : NULL); +} + +int +_DEFUN(mkstemps, (path, len), + char *path _AND + int len) +{ + int fd; + + return (_gettemp (_REENT, path, &fd, 0, len) ? fd : -1); +} +# endif /* _ELIX_LEVEL */ + char * _DEFUN(mktemp, (path), char *path) { - return (_gettemp (_REENT, path, (int *) NULL) ? path : (char *) NULL); + return (_gettemp (_REENT, path, (int *) NULL, 0, 0) ? path : (char *) NULL); } #endif /* ! defined (_REENT_ONLY) */