diff options
| author | Paul Eggert | 2013-08-04 09:56:56 -0700 |
|---|---|---|
| committer | Paul Eggert | 2013-08-04 09:56:56 -0700 |
| commit | e0fdb6943066032db294720915c3bd644bf2bcd1 (patch) | |
| tree | 0aa420b81dc0187e2efec3ff4fe3cf046ad1c598 /lib | |
| parent | 484ab23924d39b3e26d54074fd659633e1660ef4 (diff) | |
| download | emacs-e0fdb6943066032db294720915c3bd644bf2bcd1.tar.gz emacs-e0fdb6943066032db294720915c3bd644bf2bcd1.zip | |
Fix some minor races in hosts lacking mkostemp.
Gnulib's emulation of mkostemp doesn't have races that Emacs's does.
* configure.ac (mkostemp): Remove check for this function;
gnulib does the check now.
(mkstemp): Remove check for this no-longer-used function.
* lib/mkostemp.c, lib/secure_getenv.c, lib/tempname.c, lib/tempname.h:
* m4/mkostemp.m4, m4/secure_getenv.m4, m4/tempname.m4:
New files, copied from Gnulib.
* lib/gnulib.mk, m4/gnulib-comp.m4: Regenerate.
* admin/merge-gnulib (GNULIB_MODULES): Add mkostemp.
* lib-src/movemail.c (main):
* lib-src/update-game-score.c (write_scores):
Use mkostemp (which now works on all platforms, due to changes
in the portability layer) rather than mktemp (which has a race)
or mkstemp (which we no longer bother with).
* src/callproc.c (create_temp_file):
* src/filelock.c (create_lock_file):
Assume mkostemp, since it's now provided by Gnulib.
Fixes: debbugs:15015
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/gnulib.mk | 32 | ||||
| -rw-r--r-- | lib/mkostemp.c | 46 | ||||
| -rw-r--r-- | lib/secure_getenv.c | 41 | ||||
| -rw-r--r-- | lib/tempname.c | 306 | ||||
| -rw-r--r-- | lib/tempname.h | 50 |
5 files changed, 474 insertions, 1 deletions
diff --git a/lib/gnulib.mk b/lib/gnulib.mk index d053e15efc1..32255181fb4 100644 --- a/lib/gnulib.mk +++ b/lib/gnulib.mk | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | # the same distribution terms as the rest of that program. | 21 | # the same distribution terms as the rest of that program. |
| 22 | # | 22 | # |
| 23 | # Generated by gnulib-tool. | 23 | # Generated by gnulib-tool. |
| 24 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings | 24 | # Reproduce by: gnulib-tool --import --dir=. --lib=libgnu --source-base=lib --m4-base=m4 --doc-base=doc --tests-base=tests --aux-dir=build-aux --avoid=close --avoid=dup --avoid=fchdir --avoid=fstat --avoid=malloc-posix --avoid=msvc-inval --avoid=msvc-nothrow --avoid=open --avoid=openat-die --avoid=opendir --avoid=raise --avoid=save-cwd --avoid=select --avoid=sigprocmask --avoid=sys_types --avoid=threadlib --makefile-name=gnulib.mk --conditional-dependencies --no-libtool --macro-prefix=gl --no-vc-files alloca-opt c-ctype c-strcase careadlinkat close-stream crypto/md5 crypto/sha1 crypto/sha256 crypto/sha512 dtoastr dtotimespec dup2 environ execinfo faccessat fcntl fcntl-h fdatasync fdopendir filemode fstatat fsync getloadavg getopt-gnu gettime gettimeofday intprops largefile lstat manywarnings memrchr mkostemp mktime pipe2 pselect pthread_sigmask putenv qacl readlink readlinkat sig2str socklen stat-time stdalign stdarg stdbool stdio strftime strtoimax strtoumax symlink sys_stat sys_time time timer-time timespec-add timespec-sub unsetenv utimens warnings |
| 25 | 25 | ||
| 26 | 26 | ||
| 27 | MOSTLYCLEANFILES += core *.stackdump | 27 | MOSTLYCLEANFILES += core *.stackdump |
| @@ -560,6 +560,15 @@ EXTRA_libgnu_a_SOURCES += memrchr.c | |||
| 560 | 560 | ||
| 561 | ## end gnulib module memrchr | 561 | ## end gnulib module memrchr |
| 562 | 562 | ||
| 563 | ## begin gnulib module mkostemp | ||
| 564 | |||
| 565 | |||
| 566 | EXTRA_DIST += mkostemp.c | ||
| 567 | |||
| 568 | EXTRA_libgnu_a_SOURCES += mkostemp.c | ||
| 569 | |||
| 570 | ## end gnulib module mkostemp | ||
| 571 | |||
| 563 | ## begin gnulib module mktime | 572 | ## begin gnulib module mktime |
| 564 | 573 | ||
| 565 | 574 | ||
| @@ -657,6 +666,17 @@ EXTRA_DIST += root-uid.h | |||
| 657 | 666 | ||
| 658 | ## end gnulib module root-uid | 667 | ## end gnulib module root-uid |
| 659 | 668 | ||
| 669 | ## begin gnulib module secure_getenv | ||
| 670 | |||
| 671 | if gl_GNULIB_ENABLED_secure_getenv | ||
| 672 | |||
| 673 | endif | ||
| 674 | EXTRA_DIST += secure_getenv.c | ||
| 675 | |||
| 676 | EXTRA_libgnu_a_SOURCES += secure_getenv.c | ||
| 677 | |||
| 678 | ## end gnulib module secure_getenv | ||
| 679 | |||
| 660 | ## begin gnulib module sig2str | 680 | ## begin gnulib module sig2str |
| 661 | 681 | ||
| 662 | 682 | ||
| @@ -1480,6 +1500,16 @@ EXTRA_DIST += sys_time.in.h | |||
| 1480 | 1500 | ||
| 1481 | ## end gnulib module sys_time | 1501 | ## end gnulib module sys_time |
| 1482 | 1502 | ||
| 1503 | ## begin gnulib module tempname | ||
| 1504 | |||
| 1505 | if gl_GNULIB_ENABLED_tempname | ||
| 1506 | libgnu_a_SOURCES += tempname.c | ||
| 1507 | |||
| 1508 | endif | ||
| 1509 | EXTRA_DIST += tempname.h | ||
| 1510 | |||
| 1511 | ## end gnulib module tempname | ||
| 1512 | |||
| 1483 | ## begin gnulib module time | 1513 | ## begin gnulib module time |
| 1484 | 1514 | ||
| 1485 | BUILT_SOURCES += time.h | 1515 | BUILT_SOURCES += time.h |
diff --git a/lib/mkostemp.c b/lib/mkostemp.c new file mode 100644 index 00000000000..2188ff5dd61 --- /dev/null +++ b/lib/mkostemp.c | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* Copyright (C) 1998-1999, 2001, 2005-2007, 2009-2013 Free Software | ||
| 2 | Foundation, Inc. | ||
| 3 | This file is derived from the one in the GNU C Library. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | #if !_LIBC | ||
| 19 | # include <config.h> | ||
| 20 | #endif | ||
| 21 | |||
| 22 | #include <stdlib.h> | ||
| 23 | |||
| 24 | #if !_LIBC | ||
| 25 | # include "tempname.h" | ||
| 26 | # define __gen_tempname gen_tempname | ||
| 27 | # ifndef __GTFILE | ||
| 28 | # define __GT_FILE GT_FILE | ||
| 29 | # endif | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #include <stdio.h> | ||
| 33 | |||
| 34 | #ifndef __GT_FILE | ||
| 35 | # define __GT_FILE 0 | ||
| 36 | #endif | ||
| 37 | |||
| 38 | /* Generate a unique temporary file name from XTEMPLATE. | ||
| 39 | The last six characters of XTEMPLATE must be "XXXXXX"; | ||
| 40 | they are replaced with a string that makes the file name unique. | ||
| 41 | Then open the file and return a fd. */ | ||
| 42 | int | ||
| 43 | mkostemp (char *xtemplate, int flags) | ||
| 44 | { | ||
| 45 | return __gen_tempname (xtemplate, 0, flags, __GT_FILE); | ||
| 46 | } | ||
diff --git a/lib/secure_getenv.c b/lib/secure_getenv.c new file mode 100644 index 00000000000..6c11c5e0edb --- /dev/null +++ b/lib/secure_getenv.c | |||
| @@ -0,0 +1,41 @@ | |||
| 1 | /* Look up an environment variable more securely. | ||
| 2 | |||
| 3 | Copyright 2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify it | ||
| 6 | under the terms of the GNU General Public License as published | ||
| 7 | by the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 13 | General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | #include <config.h> | ||
| 19 | |||
| 20 | #include <stdlib.h> | ||
| 21 | |||
| 22 | #if !HAVE___SECURE_GETENV | ||
| 23 | # if HAVE_ISSETUGID | ||
| 24 | # include <unistd.h> | ||
| 25 | # else | ||
| 26 | # undef issetugid | ||
| 27 | # define issetugid() 1 | ||
| 28 | # endif | ||
| 29 | #endif | ||
| 30 | |||
| 31 | char * | ||
| 32 | secure_getenv (char const *name) | ||
| 33 | { | ||
| 34 | #if HAVE___SECURE_GETENV | ||
| 35 | return __secure_getenv (name); | ||
| 36 | #else | ||
| 37 | if (issetugid ()) | ||
| 38 | return 0; | ||
| 39 | return getenv (name); | ||
| 40 | #endif | ||
| 41 | } | ||
diff --git a/lib/tempname.c b/lib/tempname.c new file mode 100644 index 00000000000..087b79b31fe --- /dev/null +++ b/lib/tempname.c | |||
| @@ -0,0 +1,306 @@ | |||
| 1 | /* tempname.c - generate the name of a temporary file. | ||
| 2 | |||
| 3 | Copyright (C) 1991-2003, 2005-2007, 2009-2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* Extracted from glibc sysdeps/posix/tempname.c. See also tmpdir.c. */ | ||
| 19 | |||
| 20 | #if !_LIBC | ||
| 21 | # include <config.h> | ||
| 22 | # include "tempname.h" | ||
| 23 | #endif | ||
| 24 | |||
| 25 | #include <sys/types.h> | ||
| 26 | #include <assert.h> | ||
| 27 | |||
| 28 | #include <errno.h> | ||
| 29 | #ifndef __set_errno | ||
| 30 | # define __set_errno(Val) errno = (Val) | ||
| 31 | #endif | ||
| 32 | |||
| 33 | #include <stdio.h> | ||
| 34 | #ifndef P_tmpdir | ||
| 35 | # define P_tmpdir "/tmp" | ||
| 36 | #endif | ||
| 37 | #ifndef TMP_MAX | ||
| 38 | # define TMP_MAX 238328 | ||
| 39 | #endif | ||
| 40 | #ifndef __GT_FILE | ||
| 41 | # define __GT_FILE 0 | ||
| 42 | # define __GT_DIR 1 | ||
| 43 | # define __GT_NOCREATE 2 | ||
| 44 | #endif | ||
| 45 | #if !_LIBC && (GT_FILE != __GT_FILE || GT_DIR != __GT_DIR \ | ||
| 46 | || GT_NOCREATE != __GT_NOCREATE) | ||
| 47 | # error report this to bug-gnulib@gnu.org | ||
| 48 | #endif | ||
| 49 | |||
| 50 | #include <stddef.h> | ||
| 51 | #include <stdlib.h> | ||
| 52 | #include <string.h> | ||
| 53 | |||
| 54 | #include <fcntl.h> | ||
| 55 | #include <sys/time.h> | ||
| 56 | #include <stdint.h> | ||
| 57 | #include <unistd.h> | ||
| 58 | |||
| 59 | #include <sys/stat.h> | ||
| 60 | |||
| 61 | #if _LIBC | ||
| 62 | # define struct_stat64 struct stat64 | ||
| 63 | #else | ||
| 64 | # define struct_stat64 struct stat | ||
| 65 | # define __gen_tempname gen_tempname | ||
| 66 | # define __getpid getpid | ||
| 67 | # define __gettimeofday gettimeofday | ||
| 68 | # define __mkdir mkdir | ||
| 69 | # define __open open | ||
| 70 | # define __lxstat64(version, file, buf) lstat (file, buf) | ||
| 71 | # define __secure_getenv secure_getenv | ||
| 72 | #endif | ||
| 73 | |||
| 74 | #ifdef _LIBC | ||
| 75 | # include <hp-timing.h> | ||
| 76 | # if HP_TIMING_AVAIL | ||
| 77 | # define RANDOM_BITS(Var) \ | ||
| 78 | if (__builtin_expect (value == UINT64_C (0), 0)) \ | ||
| 79 | { \ | ||
| 80 | /* If this is the first time this function is used initialize \ | ||
| 81 | the variable we accumulate the value in to some somewhat \ | ||
| 82 | random value. If we'd not do this programs at startup time \ | ||
| 83 | might have a reduced set of possible names, at least on slow \ | ||
| 84 | machines. */ \ | ||
| 85 | struct timeval tv; \ | ||
| 86 | __gettimeofday (&tv, NULL); \ | ||
| 87 | value = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; \ | ||
| 88 | } \ | ||
| 89 | HP_TIMING_NOW (Var) | ||
| 90 | # endif | ||
| 91 | #endif | ||
| 92 | |||
| 93 | /* Use the widest available unsigned type if uint64_t is not | ||
| 94 | available. The algorithm below extracts a number less than 62**6 | ||
| 95 | (approximately 2**35.725) from uint64_t, so ancient hosts where | ||
| 96 | uintmax_t is only 32 bits lose about 3.725 bits of randomness, | ||
| 97 | which is better than not having mkstemp at all. */ | ||
| 98 | #if !defined UINT64_MAX && !defined uint64_t | ||
| 99 | # define uint64_t uintmax_t | ||
| 100 | #endif | ||
| 101 | |||
| 102 | #if _LIBC | ||
| 103 | /* Return nonzero if DIR is an existent directory. */ | ||
| 104 | static int | ||
| 105 | direxists (const char *dir) | ||
| 106 | { | ||
| 107 | struct_stat64 buf; | ||
| 108 | return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); | ||
| 109 | } | ||
| 110 | |||
| 111 | /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is | ||
| 112 | non-null and exists, uses it; otherwise uses the first of $TMPDIR, | ||
| 113 | P_tmpdir, /tmp that exists. Copies into TMPL a template suitable | ||
| 114 | for use with mk[s]temp. Will fail (-1) if DIR is non-null and | ||
| 115 | doesn't exist, none of the searched dirs exists, or there's not | ||
| 116 | enough space in TMPL. */ | ||
| 117 | int | ||
| 118 | __path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, | ||
| 119 | int try_tmpdir) | ||
| 120 | { | ||
| 121 | const char *d; | ||
| 122 | size_t dlen, plen; | ||
| 123 | |||
| 124 | if (!pfx || !pfx[0]) | ||
| 125 | { | ||
| 126 | pfx = "file"; | ||
| 127 | plen = 4; | ||
| 128 | } | ||
| 129 | else | ||
| 130 | { | ||
| 131 | plen = strlen (pfx); | ||
| 132 | if (plen > 5) | ||
| 133 | plen = 5; | ||
| 134 | } | ||
| 135 | |||
| 136 | if (try_tmpdir) | ||
| 137 | { | ||
| 138 | d = __secure_getenv ("TMPDIR"); | ||
| 139 | if (d != NULL && direxists (d)) | ||
| 140 | dir = d; | ||
| 141 | else if (dir != NULL && direxists (dir)) | ||
| 142 | /* nothing */ ; | ||
| 143 | else | ||
| 144 | dir = NULL; | ||
| 145 | } | ||
| 146 | if (dir == NULL) | ||
| 147 | { | ||
| 148 | if (direxists (P_tmpdir)) | ||
| 149 | dir = P_tmpdir; | ||
| 150 | else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) | ||
| 151 | dir = "/tmp"; | ||
| 152 | else | ||
| 153 | { | ||
| 154 | __set_errno (ENOENT); | ||
| 155 | return -1; | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | dlen = strlen (dir); | ||
| 160 | while (dlen > 1 && dir[dlen - 1] == '/') | ||
| 161 | dlen--; /* remove trailing slashes */ | ||
| 162 | |||
| 163 | /* check we have room for "${dir}/${pfx}XXXXXX\0" */ | ||
| 164 | if (tmpl_len < dlen + 1 + plen + 6 + 1) | ||
| 165 | { | ||
| 166 | __set_errno (EINVAL); | ||
| 167 | return -1; | ||
| 168 | } | ||
| 169 | |||
| 170 | sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); | ||
| 171 | return 0; | ||
| 172 | } | ||
| 173 | #endif /* _LIBC */ | ||
| 174 | |||
| 175 | /* These are the characters used in temporary file names. */ | ||
| 176 | static const char letters[] = | ||
| 177 | "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; | ||
| 178 | |||
| 179 | /* Generate a temporary file name based on TMPL. TMPL must match the | ||
| 180 | rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). | ||
| 181 | The name constructed does not exist at the time of the call to | ||
| 182 | __gen_tempname. TMPL is overwritten with the result. | ||
| 183 | |||
| 184 | KIND may be one of: | ||
| 185 | __GT_NOCREATE: simply verify that the name does not exist | ||
| 186 | at the time of the call. | ||
| 187 | __GT_FILE: create the file using open(O_CREAT|O_EXCL) | ||
| 188 | and return a read-write fd. The file is mode 0600. | ||
| 189 | __GT_DIR: create a directory, which will be mode 0700. | ||
| 190 | |||
| 191 | We use a clever algorithm to get hard-to-predict names. */ | ||
| 192 | int | ||
| 193 | __gen_tempname (char *tmpl, int suffixlen, int flags, int kind) | ||
| 194 | { | ||
| 195 | int len; | ||
| 196 | char *XXXXXX; | ||
| 197 | static uint64_t value; | ||
| 198 | uint64_t random_time_bits; | ||
| 199 | unsigned int count; | ||
| 200 | int fd = -1; | ||
| 201 | int save_errno = errno; | ||
| 202 | struct_stat64 st; | ||
| 203 | |||
| 204 | /* A lower bound on the number of temporary files to attempt to | ||
| 205 | generate. The maximum total number of temporary file names that | ||
| 206 | can exist for a given template is 62**6. It should never be | ||
| 207 | necessary to try all of these combinations. Instead if a reasonable | ||
| 208 | number of names is tried (we define reasonable as 62**3) fail to | ||
| 209 | give the system administrator the chance to remove the problems. */ | ||
| 210 | #define ATTEMPTS_MIN (62 * 62 * 62) | ||
| 211 | |||
| 212 | /* The number of times to attempt to generate a temporary file. To | ||
| 213 | conform to POSIX, this must be no smaller than TMP_MAX. */ | ||
| 214 | #if ATTEMPTS_MIN < TMP_MAX | ||
| 215 | unsigned int attempts = TMP_MAX; | ||
| 216 | #else | ||
| 217 | unsigned int attempts = ATTEMPTS_MIN; | ||
| 218 | #endif | ||
| 219 | |||
| 220 | len = strlen (tmpl); | ||
| 221 | if (len < 6 + suffixlen || memcmp (&tmpl[len - 6 - suffixlen], "XXXXXX", 6)) | ||
| 222 | { | ||
| 223 | __set_errno (EINVAL); | ||
| 224 | return -1; | ||
| 225 | } | ||
| 226 | |||
| 227 | /* This is where the Xs start. */ | ||
| 228 | XXXXXX = &tmpl[len - 6 - suffixlen]; | ||
| 229 | |||
| 230 | /* Get some more or less random data. */ | ||
| 231 | #ifdef RANDOM_BITS | ||
| 232 | RANDOM_BITS (random_time_bits); | ||
| 233 | #else | ||
| 234 | { | ||
| 235 | struct timeval tv; | ||
| 236 | __gettimeofday (&tv, NULL); | ||
| 237 | random_time_bits = ((uint64_t) tv.tv_usec << 16) ^ tv.tv_sec; | ||
| 238 | } | ||
| 239 | #endif | ||
| 240 | value += random_time_bits ^ __getpid (); | ||
| 241 | |||
| 242 | for (count = 0; count < attempts; value += 7777, ++count) | ||
| 243 | { | ||
| 244 | uint64_t v = value; | ||
| 245 | |||
| 246 | /* Fill in the random bits. */ | ||
| 247 | XXXXXX[0] = letters[v % 62]; | ||
| 248 | v /= 62; | ||
| 249 | XXXXXX[1] = letters[v % 62]; | ||
| 250 | v /= 62; | ||
| 251 | XXXXXX[2] = letters[v % 62]; | ||
| 252 | v /= 62; | ||
| 253 | XXXXXX[3] = letters[v % 62]; | ||
| 254 | v /= 62; | ||
| 255 | XXXXXX[4] = letters[v % 62]; | ||
| 256 | v /= 62; | ||
| 257 | XXXXXX[5] = letters[v % 62]; | ||
| 258 | |||
| 259 | switch (kind) | ||
| 260 | { | ||
| 261 | case __GT_FILE: | ||
| 262 | fd = __open (tmpl, | ||
| 263 | (flags & ~O_ACCMODE) | ||
| 264 | | O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR); | ||
| 265 | break; | ||
| 266 | |||
| 267 | case __GT_DIR: | ||
| 268 | fd = __mkdir (tmpl, S_IRUSR | S_IWUSR | S_IXUSR); | ||
| 269 | break; | ||
| 270 | |||
| 271 | case __GT_NOCREATE: | ||
| 272 | /* This case is backward from the other three. __gen_tempname | ||
| 273 | succeeds if __xstat fails because the name does not exist. | ||
| 274 | Note the continue to bypass the common logic at the bottom | ||
| 275 | of the loop. */ | ||
| 276 | if (__lxstat64 (_STAT_VER, tmpl, &st) < 0) | ||
| 277 | { | ||
| 278 | if (errno == ENOENT) | ||
| 279 | { | ||
| 280 | __set_errno (save_errno); | ||
| 281 | return 0; | ||
| 282 | } | ||
| 283 | else | ||
| 284 | /* Give up now. */ | ||
| 285 | return -1; | ||
| 286 | } | ||
| 287 | continue; | ||
| 288 | |||
| 289 | default: | ||
| 290 | assert (! "invalid KIND in __gen_tempname"); | ||
| 291 | abort (); | ||
| 292 | } | ||
| 293 | |||
| 294 | if (fd >= 0) | ||
| 295 | { | ||
| 296 | __set_errno (save_errno); | ||
| 297 | return fd; | ||
| 298 | } | ||
| 299 | else if (errno != EEXIST) | ||
| 300 | return -1; | ||
| 301 | } | ||
| 302 | |||
| 303 | /* We got out of the loop because we ran out of combinations to try. */ | ||
| 304 | __set_errno (EEXIST); | ||
| 305 | return -1; | ||
| 306 | } | ||
diff --git a/lib/tempname.h b/lib/tempname.h new file mode 100644 index 00000000000..333267dfd09 --- /dev/null +++ b/lib/tempname.h | |||
| @@ -0,0 +1,50 @@ | |||
| 1 | /* Create a temporary file or directory. | ||
| 2 | |||
| 3 | Copyright (C) 2006, 2009-2013 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | This program is free software: you can redistribute it and/or modify | ||
| 6 | it under the terms of the GNU General Public License as published by | ||
| 7 | the Free Software Foundation; either version 3 of the License, or | ||
| 8 | (at your option) any later version. | ||
| 9 | |||
| 10 | This program is distributed in the hope that it will be useful, | ||
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 13 | GNU General Public License for more details. | ||
| 14 | |||
| 15 | You should have received a copy of the GNU General Public License | ||
| 16 | along with this program. If not, see <http://www.gnu.org/licenses/>. */ | ||
| 17 | |||
| 18 | /* header written by Eric Blake */ | ||
| 19 | |||
| 20 | #ifndef GL_TEMPNAME_H | ||
| 21 | # define GL_TEMPNAME_H | ||
| 22 | |||
| 23 | # include <stdio.h> | ||
| 24 | |||
| 25 | # ifdef __GT_FILE | ||
| 26 | # define GT_FILE __GT_FILE | ||
| 27 | # define GT_DIR __GT_DIR | ||
| 28 | # define GT_NOCREATE __GT_NOCREATE | ||
| 29 | # else | ||
| 30 | # define GT_FILE 0 | ||
| 31 | # define GT_DIR 1 | ||
| 32 | # define GT_NOCREATE 2 | ||
| 33 | # endif | ||
| 34 | |||
| 35 | /* Generate a temporary file name based on TMPL. TMPL must match the | ||
| 36 | rules for mk[s]temp (i.e. end in "XXXXXX", possibly with a suffix). | ||
| 37 | The name constructed does not exist at the time of the call to | ||
| 38 | gen_tempname. TMPL is overwritten with the result. | ||
| 39 | |||
| 40 | KIND may be one of: | ||
| 41 | GT_NOCREATE: simply verify that the name does not exist | ||
| 42 | at the time of the call. | ||
| 43 | GT_FILE: create a large file using open(O_CREAT|O_EXCL) | ||
| 44 | and return a read-write fd. The file is mode 0600. | ||
| 45 | GT_DIR: create a directory, which will be mode 0700. | ||
| 46 | |||
| 47 | We use a clever algorithm to get hard-to-predict names. */ | ||
| 48 | extern int gen_tempname (char *tmpl, int suffixlen, int flags, int kind); | ||
| 49 | |||
| 50 | #endif /* GL_TEMPNAME_H */ | ||