diff options
Diffstat (limited to 'newlib/libc/stdio/mktemp.c')
-rw-r--r-- | newlib/libc/stdio/mktemp.c | 219 |
1 files changed, 219 insertions, 0 deletions
diff --git a/newlib/libc/stdio/mktemp.c b/newlib/libc/stdio/mktemp.c new file mode 100644 index 0000000..f6a6b68 --- /dev/null +++ b/newlib/libc/stdio/mktemp.c @@ -0,0 +1,219 @@ +/* This is file MKTEMP.C */ +/* This file may have been modified by DJ Delorie (Jan 1991). If so, +** these modifications are Coyright (C) 1991 DJ Delorie, 24 Kirsten Ave, +** Rochester NH, 03867-2954, USA. +*/ + +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that: (1) source distributions retain this entire copyright + * notice and comment, and (2) distributions including binaries display + * the following acknowledgement: ``This product includes software + * developed by the University of California, Berkeley and its contributors'' + * in the documentation or other materials provided with the distribution + * and in all advertising materials mentioning features or use of this + * software. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* +FUNCTION +<<mktemp>>, <<mkstemp>>---generate unused file name + +INDEX + mktemp +INDEX + mkstemp +INDEX + _mktemp_r +INDEX + _mkstemp_r + +ANSI_SYNOPSIS + #include <stdio.h> + char *mktemp(char *<[path]>); + int mkstemp(char *<[path]>); + + char *_mktemp_r(void *<[reent]>, char *<[path]>); + int *_mkstemp_r(void *<[reent]>, char *<[path]>); + +TRAD_SYNOPSIS + #include <stdio.h> + char *mktemp(<[path]>) + char *<[path]>; + + int mkstemp(<[path]>) + char *<[path]>; + + char *_mktemp_r(<[reent]>, <[path]>) + char *<[reent]>; + char *<[path]>; + + int _mkstemp_r(<[reent]>, <[path]>) + char *<[reent]>; + 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. + +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>>' +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. + +The alternate functions <<_mktemp_r>> and <<_mkstemp_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 +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 +provided is not suitable for a filename; in that case, it returns +<<-1>>. + +PORTABILITY +ANSI C does not require either <<mktemp>> or <<mkstemp>>; the System +V Interface Definition requires <<mktemp>> as of Issue 2. + +Supporting OS subroutines required: <<getpid>>, <<open>>, <<stat>>. +*/ + +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <errno.h> +#include <stdio.h> +#include <ctype.h> +#include <reent.h> + +static +_DEFUN (_gettemp, (ptr, path, doopen), + struct _reent *ptr _AND + char *path _AND + register int *doopen) +{ + register char *start, *trv; + struct stat sbuf; + unsigned int pid; + + pid = _getpid_r (ptr); + for (trv = path; *trv; ++trv) /* extra X's get set to 0's */ + continue; + while (*--trv == 'X') + { + *trv = (pid % 10) + '0'; + pid /= 10; + } + + /* + * Check the target directory; if you have six X's and it + * doesn't exist this runs for a *very* long time. + */ + + for (start = trv + 1;; --trv) + { + if (trv <= path) + break; + if (*trv == '/') + { + *trv = '\0'; + if (_stat_r (ptr, path, &sbuf)) + return (0); + if (!(sbuf.st_mode & S_IFDIR)) + { + ptr->_errno = ENOTDIR; + return (0); + } + *trv = '/'; + break; + } + } + + for (;;) + { + if (doopen) + { + if ((*doopen = _open_r (ptr, path, O_CREAT | O_EXCL | O_RDWR, 0600)) + >= 0) + return 1; +#if defined(__CYGWIN32__) || defined(__CYGWIN__) + if (ptr->_errno != EEXIST && ptr->_errno != EACCES) +#else + if (ptr->_errno != EEXIST) +#endif + return 0; + } + else if (_stat_r (ptr, path, &sbuf)) + return (ptr->_errno == ENOENT ? 1 : 0); + + /* tricky little algorithm for backward compatibility */ + for (trv = start;;) + { + if (!*trv) + return 0; + if (*trv == 'z') + *trv++ = 'a'; + else + { + if (isdigit (*trv)) + *trv = 'a'; + else + ++ * trv; + break; + } + } + } + /*NOTREACHED*/ +} + +_DEFUN (_mkstemp_r, (ptr, path), + struct _reent *ptr _AND + char *path) +{ + int fd; + + return (_gettemp (ptr, path, &fd) ? fd : -1); +} + +char * +_DEFUN (_mktemp_r, (ptr, path), + struct _reent *ptr _AND + char *path) +{ + return (_gettemp (ptr, path, (int *) NULL) ? path : (char *) NULL); +} + +#ifndef _REENT_ONLY + +_DEFUN (mkstemp, (path), + char *path) +{ + int fd; + + return (_gettemp (_REENT, path, &fd) ? fd : -1); +} + +char * +_DEFUN (mktemp, (path), + char *path) +{ + return (_gettemp (_REENT, path, (int *) NULL) ? path : (char *) NULL); +} + +#endif /* ! defined (_REENT_ONLY) */ |