source: trunk/libs/newlib/src/newlib/libc/stdio/mktemp.c @ 567

Last change on this file since 567 was 444, checked in by satin@…, 6 years ago

add newlib,libalmos-mkh, restructure shared_syscalls.h and mini-libc

File size: 9.2 KB
Line 
1/*
2 * Copyright (c) 1987 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
6 * provided that: (1) source distributions retain this entire copyright
7 * notice and comment, and (2) distributions including binaries display
8 * the following acknowledgement:  ``This product includes software
9 * developed by the University of California, Berkeley and its contributors''
10 * in the documentation or other materials provided with the distribution
11 * and in all advertising materials mentioning features or use of this
12 * software. Neither the name of the University nor the names of its
13 * contributors may be used to endorse or promote products derived
14 * from this software without specific prior written permission.
15 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
18 */
19/* This is file MKTEMP.C */
20/* This file may have been modified by DJ Delorie (Jan 1991).  If so,
21** these modifications are Copyright (C) 1991 DJ Delorie.
22*/
23
24/*
25FUNCTION
26<<mktemp>>, <<mkstemp>>, <<mkostemp>>, <<mkstemps>>,
27<<mkostemps>>---generate unused file name
28<<mkdtemp>>---generate unused directory
29
30INDEX
31        mktemp
32INDEX
33        mkdtemp
34INDEX
35        mkstemp
36INDEX
37        mkstemps
38INDEX
39        mkostemp
40INDEX
41        mkostemps
42INDEX
43        _mktemp_r
44INDEX
45        _mkdtemp_r
46INDEX
47        _mkstemp_r
48INDEX
49        _mkstemps_r
50INDEX
51        _mkostemp_r
52INDEX
53        _mkostemps_r
54
55SYNOPSIS
56        #include <stdlib.h>
57        char *mktemp(char *<[path]>);
58        char *mkdtemp(char *<[path]>);
59        int mkstemp(char *<[path]>);
60        int mkstemps(char *<[path]>, int <[suffixlen]>);
61        int mkostemp(char *<[path]>, int <[flags]>);
62        int mkostemps(char *<[path]>, int <[suffixlen]>, int <[flags]>);
63
64        char *_mktemp_r(struct _reent *<[reent]>, char *<[path]>);
65        char *_mkdtemp_r(struct _reent *<[reent]>, char *<[path]>);
66        int *_mkstemp_r(struct _reent *<[reent]>, char *<[path]>);
67        int *_mkstemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>);
68        int *_mkostemp_r(struct _reent *<[reent]>, char *<[path]>,
69                         int <[flags]>);
70        int *_mkostemps_r(struct _reent *<[reent]>, char *<[path]>, int <[len]>,
71                          int <[flags]>);
72
73DESCRIPTION
74<<mktemp>>, <<mkstemp>>, and <<mkstemps>> attempt to generate a file name
75that is not yet in use for any existing file.  <<mkstemp>> and <<mkstemps>>
76create the file and open it for reading and writing; <<mktemp>> simply
77generates the file name (making <<mktemp>> a security risk).  <<mkostemp>>
78and <<mkostemps>> allow the addition of other <<open>> flags, such
79as <<O_CLOEXEC>>, <<O_APPEND>>, or <<O_SYNC>>.  On platforms with a
80separate text mode, <<mkstemp>> forces <<O_BINARY>>, while <<mkostemp>>
81allows the choice between <<O_BINARY>>, <<O_TEXT>>, or 0 for default.
82<<mkdtemp>> attempts to create a directory instead of a file, with a
83permissions mask of 0700.
84
85You supply a simple pattern for the generated file name, as the string
86at <[path]>.  The pattern should be a valid filename (including path
87information if you wish) ending with at least six `<<X>>'
88characters.  The generated filename will match the leading part of the
89name you supply, with the trailing `<<X>>' characters replaced by some
90combination of digits and letters.  With <<mkstemps>>, the `<<X>>'
91characters end <[suffixlen]> bytes before the end of the string.
92
93The alternate functions <<_mktemp_r>>, <<_mkdtemp_r>>, <<_mkstemp_r>>,
94<<_mkostemp_r>>, <<_mkostemps_r>>, and <<_mkstemps_r>> are reentrant
95versions.  The extra argument <[reent]> is a pointer to a reentrancy
96structure.
97
98RETURNS
99<<mktemp>> returns the pointer <[path]> to the modified string
100representing an unused filename, unless it could not generate one, or
101the pattern you provided is not suitable for a filename; in that case,
102it returns <<NULL>>.  Be aware that there is an inherent race between
103generating the name and attempting to create a file by that name;
104you are advised to use <<O_EXCL|O_CREAT>>.
105
106<<mkdtemp>> returns the pointer <[path]> to the modified string if the
107directory was created, otherwise it returns <<NULL>>.
108
109<<mkstemp>>, <<mkstemps>>, <<mkostemp>>, and <<mkostemps>> return a file
110descriptor to the newly created file, unless it could not generate an
111unused filename, or the pattern you provided is not suitable for a
112filename; in that case, it returns <<-1>>.
113
114NOTES
115Never use <<mktemp>>.  The generated filenames are easy to guess and
116there's a race between the test if the file exists and the creation
117of the file.  In combination this makes <<mktemp>> prone to attacks
118and using it is a security risk.  Whenever possible use <<mkstemp>>
119instead.  It doesn't suffer the race condition.
120
121PORTABILITY
122ANSI C does not require either <<mktemp>> or <<mkstemp>>; the System
123V Interface Definition requires <<mktemp>> as of Issue 2.  POSIX 2001
124requires <<mkstemp>>, and POSIX 2008 requires <<mkdtemp>> while
125deprecating <<mktemp>>.  <<mkstemps>>, <<mkostemp>>, and <<mkostemps>>
126are not standardized.
127
128Supporting OS subroutines required: <<getpid>>, <<mkdir>>, <<open>>, <<stat>>.
129*/
130
131#include <_ansi.h>
132#include <stdlib.h>
133#include <reent.h>
134#include <sys/types.h>
135#include <fcntl.h>
136#include <sys/stat.h>
137#include <errno.h>
138#include <stdio.h>
139#include <ctype.h>
140
141static int
142_gettemp (struct _reent *ptr,
143       char *path,
144       register int *doopen,
145       int domkdir,
146       size_t suffixlen,
147       int flags)
148{
149  register char *start, *trv;
150  char *end;
151#ifdef __USE_INTERNAL_STAT64
152  struct stat64 sbuf;
153#else
154  struct stat sbuf;
155#endif
156  unsigned int pid;
157
158  pid = _getpid_r (ptr);
159  for (trv = path; *trv; ++trv)         /* extra X's get set to 0's */
160    continue;
161  if (trv - path < suffixlen)
162    {
163      ptr->_errno = EINVAL;
164      return 0;
165    }
166  trv -= suffixlen;
167  end = trv;
168  while (path < trv && *--trv == 'X')
169    {
170      *trv = (pid % 10) + '0';
171      pid /= 10;
172    }
173  if (end - trv < 6)
174    {
175      ptr->_errno = EINVAL;
176      return 0;
177    }
178
179  /*
180   * Check the target directory; if you have six X's and it
181   * doesn't exist this runs for a *very* long time.
182   */
183
184  for (start = trv + 1;; --trv)
185    {
186      if (trv <= path)
187        break;
188      if (*trv == '/')
189        {
190          *trv = '\0';
191#ifdef __USE_INTERNAL_STAT64
192          if (_stat64_r (ptr, path, &sbuf))
193#else
194          if (_stat_r (ptr, path, &sbuf))
195#endif
196            return (0);
197          if (!(sbuf.st_mode & S_IFDIR))
198            {
199              ptr->_errno = ENOTDIR;
200              return (0);
201            }
202          *trv = '/';
203          break;
204        }
205    }
206
207  for (;;)
208    {
209#if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
210      if (domkdir)
211        {
212#ifdef HAVE_MKDIR
213          if (_mkdir_r (ptr, path, 0700) == 0)
214            return 1;
215          if (ptr->_errno != EEXIST)
216            return 0;
217#else /* !HAVE_MKDIR */
218          ptr->_errno = ENOSYS;
219          return 0;
220#endif /* !HAVE_MKDIR */
221        }
222      else
223#endif /* _ELIX_LEVEL */
224      if (doopen)
225        {
226          if ((*doopen = _open_r (ptr, path, O_CREAT | O_EXCL | O_RDWR | flags,
227                                  0600)) >= 0)
228            return 1;
229          if (ptr->_errno != EEXIST)
230            return 0;
231        }
232#ifdef __USE_INTERNAL_STAT64
233      else if (_stat64_r (ptr, path, &sbuf))
234#else
235      else if (_stat_r (ptr, path, &sbuf))
236#endif
237        return (ptr->_errno == ENOENT ? 1 : 0);
238
239      /* tricky little algorithm for backward compatibility */
240      for (trv = start;;)
241        {
242          if (trv == end)
243            return 0;
244          if (*trv == 'z')
245            *trv++ = 'a';
246          else
247            {
248              /* Safe, since it only encounters 7-bit characters.  */
249              if (isdigit ((unsigned char) *trv))
250                *trv = 'a';
251              else
252                ++ * trv;
253              break;
254            }
255        }
256    }
257  /*NOTREACHED*/
258}
259
260#ifndef O_BINARY
261# define O_BINARY 0
262#endif
263
264int
265_mkstemp_r (struct _reent *ptr,
266       char *path)
267{
268  int fd;
269
270  return (_gettemp (ptr, path, &fd, 0, 0, O_BINARY) ? fd : -1);
271}
272
273#if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
274char *
275_mkdtemp_r (struct _reent *ptr,
276       char *path)
277{
278  return (_gettemp (ptr, path, (int *) NULL, 1, 0, 0) ? path : NULL);
279}
280
281int
282_mkstemps_r (struct _reent *ptr,
283       char *path,
284       int len)
285{
286  int fd;
287
288  return (_gettemp (ptr, path, &fd, 0, len, O_BINARY) ? fd : -1);
289}
290
291int
292_mkostemp_r (struct _reent *ptr,
293       char *path,
294       int flags)
295{
296  int fd;
297
298  return (_gettemp (ptr, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
299}
300
301int
302_mkostemps_r (struct _reent *ptr,
303       char *path,
304       int len,
305       int flags)
306{
307  int fd;
308
309  return (_gettemp (ptr, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
310}
311#endif /* _ELIX_LEVEL */
312
313char *
314_mktemp_r (struct _reent *ptr,
315       char *path)
316{
317  return (_gettemp (ptr, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
318}
319
320#ifndef _REENT_ONLY
321
322int
323mkstemp (char *path)
324{
325  int fd;
326
327  return (_gettemp (_REENT, path, &fd, 0, 0, O_BINARY) ? fd : -1);
328}
329
330# if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
331char *
332mkdtemp (char *path)
333{
334  return (_gettemp (_REENT, path, (int *) NULL, 1, 0, 0) ? path : NULL);
335}
336
337int
338mkstemps (char *path,
339       int len)
340{
341  int fd;
342
343  return (_gettemp (_REENT, path, &fd, 0, len, O_BINARY) ? fd : -1);
344}
345
346int
347mkostemp (char *path,
348       int flags)
349{
350  int fd;
351
352  return (_gettemp (_REENT, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
353}
354
355int
356mkostemps (char *path,
357       int len,
358       int flags)
359{
360  int fd;
361
362  return (_gettemp (_REENT, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
363}
364# endif /* _ELIX_LEVEL */
365
366char *
367mktemp (char *path)
368{
369  return (_gettemp (_REENT, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
370}
371
372#endif /* ! defined (_REENT_ONLY) */
Note: See TracBrowser for help on using the repository browser.