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.
This commit is contained in:
		| @@ -1,5 +1,14 @@ | ||||
| 2009-07-03  Eric Blake  <ebb9@byu.net> | ||||
|  | ||||
| 	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): | ||||
|   | ||||
| @@ -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))); | ||||
|   | ||||
| @@ -23,27 +23,40 @@ | ||||
|  | ||||
| /* | ||||
| FUNCTION | ||||
| <<mktemp>>, <<mkstemp>>---generate unused file name | ||||
| <<mktemp>>, <<mkstemp>>, <<mkstemps>>---generate unused file name | ||||
| <<mkdtemp>>---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 <stdio.h> | ||||
| 	#include <stdlib.h> | ||||
| 	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 <stdio.h> | ||||
| 	#include <stdlib.h> | ||||
| 	char *mktemp(<[path]>) | ||||
| 	char *<[path]>; | ||||
|  | ||||
| @@ -59,20 +72,24 @@ TRAD_SYNOPSIS | ||||
| 	char *<[path]>; | ||||
|  | ||||
| DESCRIPTION | ||||
| <<mktemp>> and <<mkstemp>> attempt to generate a file name that is not | ||||
| yet in use for any existing file.  <<mkstemp>> creates the file and | ||||
| opens it for reading and writing; <<mktemp>> simply generates the file name. | ||||
| <<mktemp>>, <<mkstemp>>, and <<mkstemps>> attempt to generate a file name | ||||
| that is not yet in use for any existing file.  <<mkstemp>> and <<mkstemps>> | ||||
| create the file and open it for reading and writing; <<mktemp>> simply | ||||
| generates the file name (making <<mktemp>> a security risk).  <<mkdtemp>> | ||||
| 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 `<<X>>' | ||||
| information if you wish) ending with at least six `<<X>>' | ||||
| characters.  The generated filename will match the leading part of the | ||||
| name you supply, with the trailing `<<X>>' characters replaced by some | ||||
| combination of digits and letters. | ||||
| combination of digits and letters.  With <<mkstemps>>, the `<<X>>' | ||||
| 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 | ||||
| <<mktemp>> 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 <<NULL>>. | ||||
|  | ||||
| <<mkstemp>> returns a file descriptor to the newly created file, | ||||
| unless it could not generate an unused filename, or the pattern you | ||||
| <<mkdtemp>> returns the pointer <[path]> to the modified string if the | ||||
| directory was created, otherwise it returns <<NULL>>. | ||||
|  | ||||
| <<mkstemp>> and <<mkstemps>> 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 <<mktemp>> or <<mkstemp>>; the System | ||||
| V Interface Definition requires <<mktemp>> as of Issue 2. | ||||
| V Interface Definition requires <<mktemp>> as of Issue 2.  POSIX 2001 | ||||
| requires <<mkstemp>>, and POSIX 2008 requires <<mkdtemp>>, but | ||||
| <<mkstemps>> is not standardized. | ||||
|  | ||||
| Supporting OS subroutines required: <<getpid>>, <<open>>, <<stat>>. | ||||
| Supporting OS subroutines required: <<getpid>>, <<mkdir>>, <<open>>, <<stat>>. | ||||
| */ | ||||
|  | ||||
| #include <_ansi.h> | ||||
| @@ -109,12 +131,15 @@ Supporting OS subroutines required: <<getpid>>, <<open>>, <<stat>>. | ||||
| #include <ctype.h> | ||||
|  | ||||
| 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) */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user