1/* Copyright (C) 1999, 2001-2002, 2006, 2009-2014 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. */ 73static bool 74direxists (const char *dir) 75{ 76 struct_stat64 buf; 77 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. */ 86int 87path_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 if (!pfx || !pfx[0]) 95 { 96 pfx = "file"; 97 plen = 4; 98 } 99 else 100 { 101 plen = strlen (pfx); 102 if (plen > 5) 103 plen = 5; 104 } 105 106 if (try_tmpdir) 107 { 108 d = __libc_secure_getenv ("TMPDIR"); 109 if (d != NULL && direxists (d)) 110 dir = d; 111 else if (dir != NULL && direxists (dir)) 112 /* nothing */ ; 113 else 114 dir = NULL; 115 } 116 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 if (direxists (P_tmpdir)) 132 dir = P_tmpdir; 133 else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) 134 dir = "/tmp"; 135 else 136 { 137 __set_errno (ENOENT); 138 return -1; 139 } 140 } 141 142 dlen = strlen (dir); 143#ifdef __VMS 144 add_slash = 0; 145#else 146 add_slash = dlen != 0 && !ISSLASH (dir[dlen - 1]); 147#endif 148 149 /* check we have room for "${dir}/${pfx}XXXXXX\0" */ 150 if (tmpl_len < dlen + add_slash + plen + 6 + 1) 151 { 152 __set_errno (EINVAL); 153 return -1; 154 } 155 156 memcpy (tmpl, dir, dlen); 157 sprintf (tmpl + dlen, &"/%.*sXXXXXX"[!add_slash], (int) plen, pfx); 158 return 0; 159} 160