Line data Source code
1 : /* Copyright (C) 1999, 2001-2002, 2006, 2009-2016 Free Software Foundation,
2 : Inc.
3 : This file is part of 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 : /* Extracted from sysdeps/posix/tempname.c. */
19 :
20 : #include <config.h>
21 :
22 : /* Specification. */
23 : #include "tmpdir.h"
24 :
25 : #include <stdbool.h>
26 : #include <stdlib.h>
27 : #include <string.h>
28 :
29 : #include <errno.h>
30 : #ifndef __set_errno
31 : # define __set_errno(Val) errno = (Val)
32 : #endif
33 :
34 : #include <stdio.h>
35 : #ifndef P_tmpdir
36 : # ifdef _P_tmpdir /* native Windows */
37 : # define P_tmpdir _P_tmpdir
38 : # else
39 : # define P_tmpdir "/tmp"
40 : # endif
41 : #endif
42 :
43 : #include <sys/stat.h>
44 :
45 : #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
46 : # define WIN32_LEAN_AND_MEAN /* avoid including junk */
47 : # include <windows.h>
48 : #endif
49 :
50 : #include "pathmax.h"
51 :
52 : #if _LIBC
53 : # define struct_stat64 struct stat64
54 : #else
55 : # define struct_stat64 struct stat
56 : # define __libc_secure_getenv secure_getenv
57 : # define __xstat64(version, path, buf) stat (path, buf)
58 : #endif
59 :
60 : /* Pathname support.
61 : ISSLASH(C) tests whether C is a directory separator character.
62 : */
63 : #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
64 : /* Native Windows, Cygwin, OS/2, DOS */
65 : # define ISSLASH(C) ((C) == '/' || (C) == '\\')
66 : #else
67 : /* Unix */
68 : # define ISSLASH(C) ((C) == '/')
69 : #endif
70 :
71 :
72 : /* Return nonzero if DIR is an existent directory. */
73 : static bool
74 0 : direxists (const char *dir)
75 : {
76 : struct_stat64 buf;
77 0 : return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
78 : }
79 :
80 : /* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is
81 : non-null and exists, uses it; otherwise uses the first of $TMPDIR,
82 : P_tmpdir, /tmp that exists. Copies into TMPL a template suitable
83 : for use with mk[s]temp. Will fail (-1) if DIR is non-null and
84 : doesn't exist, none of the searched dirs exists, or there's not
85 : enough space in TMPL. */
86 : int
87 0 : path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
88 : bool try_tmpdir)
89 : {
90 : const char *d;
91 : size_t dlen, plen;
92 : bool add_slash;
93 :
94 0 : if (!pfx || !pfx[0])
95 : {
96 0 : pfx = "file";
97 0 : plen = 4;
98 : }
99 : else
100 : {
101 0 : plen = strlen (pfx);
102 0 : if (plen > 5)
103 0 : plen = 5;
104 : }
105 :
106 0 : if (try_tmpdir)
107 : {
108 0 : d = __libc_secure_getenv ("TMPDIR");
109 0 : if (d != NULL && direxists (d))
110 0 : dir = d;
111 0 : else if (dir != NULL && direxists (dir))
112 : /* nothing */ ;
113 : else
114 0 : dir = NULL;
115 : }
116 0 : if (dir == NULL)
117 : {
118 : #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
119 : char dirbuf[PATH_MAX];
120 : DWORD retval;
121 :
122 : /* Find Windows temporary file directory.
123 : We try this before P_tmpdir because Windows defines P_tmpdir to "\\"
124 : and will therefore try to put all temporary files in the root
125 : directory (unless $TMPDIR is set). */
126 : retval = GetTempPath (PATH_MAX, dirbuf);
127 : if (retval > 0 && retval < PATH_MAX && direxists (dirbuf))
128 : dir = dirbuf;
129 : else
130 : #endif
131 0 : if (direxists (P_tmpdir))
132 0 : dir = P_tmpdir;
133 : else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
134 : dir = "/tmp";
135 : else
136 : {
137 0 : __set_errno (ENOENT);
138 0 : return -1;
139 : }
140 : }
141 :
142 0 : dlen = strlen (dir);
143 : #ifdef __VMS
144 : add_slash = 0;
145 : #else
146 0 : add_slash = dlen != 0 && !ISSLASH (dir[dlen - 1]);
147 : #endif
148 :
149 : /* check we have room for "${dir}/${pfx}XXXXXX\0" */
150 0 : if (tmpl_len < dlen + add_slash + plen + 6 + 1)
151 : {
152 0 : __set_errno (EINVAL);
153 0 : return -1;
154 : }
155 :
156 0 : memcpy (tmpl, dir, dlen);
157 0 : sprintf (tmpl + dlen, &"/%.*sXXXXXX"[!add_slash], (int) plen, pfx);
158 0 : return 0;
159 : }
|