Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  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. /*
  25. FUNCTION
  26. <<mktemp>>, <<mkstemp>>, <<mkostemp>>, <<mkstemps>>,
  27. <<mkostemps>>---generate unused file name
  28. <<mkdtemp>>---generate unused directory
  29.  
  30. INDEX
  31.         mktemp
  32. INDEX
  33.         mkdtemp
  34. INDEX
  35.         mkstemp
  36. INDEX
  37.         mkstemps
  38. INDEX
  39.         mkostemp
  40. INDEX
  41.         mkostemps
  42. INDEX
  43.         _mktemp_r
  44. INDEX
  45.         _mkdtemp_r
  46. INDEX
  47.         _mkstemp_r
  48. INDEX
  49.         _mkstemps_r
  50. INDEX
  51.         _mkostemp_r
  52. INDEX
  53.         _mkostemps_r
  54.  
  55. ANSI_SYNOPSIS
  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.  
  73. DESCRIPTION
  74. <<mktemp>>, <<mkstemp>>, and <<mkstemps>> attempt to generate a file name
  75. that is not yet in use for any existing file.  <<mkstemp>> and <<mkstemps>>
  76. create the file and open it for reading and writing; <<mktemp>> simply
  77. generates the file name (making <<mktemp>> a security risk).  <<mkostemp>>
  78. and <<mkostemps>> allow the addition of other <<open>> flags, such
  79. as <<O_CLOEXEC>>, <<O_APPEND>>, or <<O_SYNC>>.  On platforms with a
  80. separate text mode, <<mkstemp>> forces <<O_BINARY>>, while <<mkostemp>>
  81. allows the choice between <<O_BINARY>>, <<O_TEXT>>, or 0 for default.
  82. <<mkdtemp>> attempts to create a directory instead of a file, with a
  83. permissions mask of 0700.
  84.  
  85. You supply a simple pattern for the generated file name, as the string
  86. at <[path]>.  The pattern should be a valid filename (including path
  87. information if you wish) ending with at least six `<<X>>'
  88. characters.  The generated filename will match the leading part of the
  89. name you supply, with the trailing `<<X>>' characters replaced by some
  90. combination of digits and letters.  With <<mkstemps>>, the `<<X>>'
  91. characters end <[suffixlen]> bytes before the end of the string.
  92.  
  93. The alternate functions <<_mktemp_r>>, <<_mkdtemp_r>>, <<_mkstemp_r>>,
  94. <<_mkostemp_r>>, <<_mkostemps_r>>, and <<_mkstemps_r>> are reentrant
  95. versions.  The extra argument <[reent]> is a pointer to a reentrancy
  96. structure.
  97.  
  98. RETURNS
  99. <<mktemp>> returns the pointer <[path]> to the modified string
  100. representing an unused filename, unless it could not generate one, or
  101. the pattern you provided is not suitable for a filename; in that case,
  102. it returns <<NULL>>.  Be aware that there is an inherent race between
  103. generating the name and attempting to create a file by that name;
  104. you are advised to use <<O_EXCL|O_CREAT>>.
  105.  
  106. <<mkdtemp>> returns the pointer <[path]> to the modified string if the
  107. directory was created, otherwise it returns <<NULL>>.
  108.  
  109. <<mkstemp>>, <<mkstemps>>, <<mkostemp>>, and <<mkostemps>> return a file
  110. descriptor to the newly created file, unless it could not generate an
  111. unused filename, or the pattern you provided is not suitable for a
  112. filename; in that case, it returns <<-1>>.
  113.  
  114. NOTES
  115. Never use <<mktemp>>.  The generated filenames are easy to guess and
  116. there's a race between the test if the file exists and the creation
  117. of the file.  In combination this makes <<mktemp>> prone to attacks
  118. and using it is a security risk.  Whenever possible use <<mkstemp>>
  119. instead.  It doesn't suffer the race condition.
  120.  
  121. PORTABILITY
  122. ANSI C does not require either <<mktemp>> or <<mkstemp>>; the System
  123. V Interface Definition requires <<mktemp>> as of Issue 2.  POSIX 2001
  124. requires <<mkstemp>>, and POSIX 2008 requires <<mkdtemp>> while
  125. deprecating <<mktemp>>.  <<mkstemps>>, <<mkostemp>>, and <<mkostemps>>
  126. are not standardized.
  127.  
  128. Supporting 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.  
  141. static int
  142. _DEFUN(_gettemp, (ptr, path, doopen, domkdir, suffixlen, flags),
  143.        struct _reent *ptr _AND
  144.        char *path         _AND
  145.        register int *doopen _AND
  146.        int domkdir        _AND
  147.        size_t suffixlen   _AND
  148.        int flags)
  149. {
  150.   register char *start, *trv;
  151.   char *end;
  152. #ifdef __USE_INTERNAL_STAT64
  153.   struct stat64 sbuf;
  154. #else
  155.   struct stat sbuf;
  156. #endif
  157.   unsigned int pid;
  158.  
  159.   pid = _getpid_r (ptr);
  160.   for (trv = path; *trv; ++trv)         /* extra X's get set to 0's */
  161.     continue;
  162.   if (trv - path < suffixlen)
  163.     {
  164.       ptr->_errno = EINVAL;
  165.       return 0;
  166.     }
  167.   trv -= suffixlen;
  168.   end = trv;
  169.   while (path < trv && *--trv == 'X')
  170.     {
  171.       *trv = (pid % 10) + '0';
  172.       pid /= 10;
  173.     }
  174.   if (end - trv < 6)
  175.     {
  176.       ptr->_errno = EINVAL;
  177.       return 0;
  178.     }
  179.  
  180.   /*
  181.    * Check the target directory; if you have six X's and it
  182.    * doesn't exist this runs for a *very* long time.
  183.    */
  184.  
  185.   for (start = trv + 1;; --trv)
  186.     {
  187.       if (trv <= path)
  188.         break;
  189.       if (*trv == '/')
  190.         {
  191.           *trv = '\0';
  192. #ifdef __USE_INTERNAL_STAT64
  193.           if (_stat64_r (ptr, path, &sbuf))
  194. #else
  195.           if (_stat_r (ptr, path, &sbuf))
  196. #endif
  197.             return (0);
  198.           if (!(sbuf.st_mode & S_IFDIR))
  199.             {
  200.               ptr->_errno = ENOTDIR;
  201.               return (0);
  202.             }
  203.           *trv = '/';
  204.           break;
  205.         }
  206.     }
  207.  
  208.   for (;;)
  209.     {
  210. #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
  211.       if (domkdir)
  212.         {
  213. #ifdef HAVE_MKDIR
  214.           if (_mkdir_r (ptr, path, 0700) == 0)
  215.             return 1;
  216.           if (ptr->_errno != EEXIST)
  217.             return 0;
  218. #else /* !HAVE_MKDIR */
  219.           ptr->_errno = ENOSYS;
  220.           return 0;
  221. #endif /* !HAVE_MKDIR */
  222.         }
  223.       else
  224. #endif /* _ELIX_LEVEL */
  225.       if (doopen)
  226.         {
  227.           if ((*doopen = _open_r (ptr, path, O_CREAT | O_EXCL | O_RDWR | flags,
  228.                                   0600)) >= 0)
  229.             return 1;
  230.           if (ptr->_errno != EEXIST)
  231.             return 0;
  232.         }
  233. #ifdef __USE_INTERNAL_STAT64
  234.       else if (_stat64_r (ptr, path, &sbuf))
  235. #else
  236.       else if (_stat_r (ptr, path, &sbuf))
  237. #endif
  238.         return (ptr->_errno == ENOENT ? 1 : 0);
  239.  
  240.       /* tricky little algorithm for backward compatibility */
  241.       for (trv = start;;)
  242.         {
  243.           if (trv == end)
  244.             return 0;
  245.           if (*trv == 'z')
  246.             *trv++ = 'a';
  247.           else
  248.             {
  249.               /* Safe, since it only encounters 7-bit characters.  */
  250.               if (isdigit ((unsigned char) *trv))
  251.                 *trv = 'a';
  252.               else
  253.                 ++ * trv;
  254.               break;
  255.             }
  256.         }
  257.     }
  258.   /*NOTREACHED*/
  259. }
  260.  
  261. #ifndef O_BINARY
  262. # define O_BINARY 0
  263. #endif
  264.  
  265. int
  266. _DEFUN(_mkstemp_r, (ptr, path),
  267.        struct _reent *ptr _AND
  268.        char *path)
  269. {
  270.   int fd;
  271.  
  272.   return (_gettemp (ptr, path, &fd, 0, 0, O_BINARY) ? fd : -1);
  273. }
  274.  
  275. #if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
  276. char *
  277. _DEFUN(_mkdtemp_r, (ptr, path),
  278.        struct _reent *ptr _AND
  279.        char *path)
  280. {
  281.   return (_gettemp (ptr, path, (int *) NULL, 1, 0, 0) ? path : NULL);
  282. }
  283.  
  284. int
  285. _DEFUN(_mkstemps_r, (ptr, path, len),
  286.        struct _reent *ptr _AND
  287.        char *path _AND
  288.        int len)
  289. {
  290.   int fd;
  291.  
  292.   return (_gettemp (ptr, path, &fd, 0, len, O_BINARY) ? fd : -1);
  293. }
  294.  
  295. int
  296. _DEFUN(_mkostemp_r, (ptr, path, flags),
  297.        struct _reent *ptr _AND
  298.        char *path _AND
  299.        int flags)
  300. {
  301.   int fd;
  302.  
  303.   return (_gettemp (ptr, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
  304. }
  305.  
  306. int
  307. _DEFUN(_mkostemps_r, (ptr, path, len, flags),
  308.        struct _reent *ptr _AND
  309.        char *path _AND
  310.        int len _AND
  311.        int flags)
  312. {
  313.   int fd;
  314.  
  315.   return (_gettemp (ptr, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
  316. }
  317. #endif /* _ELIX_LEVEL */
  318.  
  319. char *
  320. _DEFUN(_mktemp_r, (ptr, path),
  321.        struct _reent *ptr _AND
  322.        char *path)
  323. {
  324.   return (_gettemp (ptr, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
  325. }
  326.  
  327. #ifndef _REENT_ONLY
  328.  
  329. int
  330. _DEFUN(mkstemp, (path),
  331.        char *path)
  332. {
  333.   int fd;
  334.  
  335.   return (_gettemp (_REENT, path, &fd, 0, 0, O_BINARY) ? fd : -1);
  336. }
  337.  
  338. # if !defined _ELIX_LEVEL || _ELIX_LEVEL >= 4
  339. char *
  340. _DEFUN(mkdtemp, (path),
  341.        char *path)
  342. {
  343.   return (_gettemp (_REENT, path, (int *) NULL, 1, 0, 0) ? path : NULL);
  344. }
  345.  
  346. int
  347. _DEFUN(mkstemps, (path, len),
  348.        char *path _AND
  349.        int len)
  350. {
  351.   int fd;
  352.  
  353.   return (_gettemp (_REENT, path, &fd, 0, len, O_BINARY) ? fd : -1);
  354. }
  355.  
  356. int
  357. _DEFUN(mkostemp, (path, flags),
  358.        char *path _AND
  359.        int flags)
  360. {
  361.   int fd;
  362.  
  363.   return (_gettemp (_REENT, path, &fd, 0, 0, flags & ~O_ACCMODE) ? fd : -1);
  364. }
  365.  
  366. int
  367. _DEFUN(mkostemps, (path, len, flags),
  368.        char *path _AND
  369.        int len _AND
  370.        int flags)
  371. {
  372.   int fd;
  373.  
  374.   return (_gettemp (_REENT, path, &fd, 0, len, flags & ~O_ACCMODE) ? fd : -1);
  375. }
  376. # endif /* _ELIX_LEVEL */
  377.  
  378. char *
  379. _DEFUN(mktemp, (path),
  380.        char *path)
  381. {
  382.   return (_gettemp (_REENT, path, (int *) NULL, 0, 0, 0) ? path : (char *) NULL);
  383. }
  384.  
  385. #endif /* ! defined (_REENT_ONLY) */
  386.