1/* Copyright (C) 1999, 2001-2002, 2006 Free Software Foundation, Inc. 2 This file is part of the GNU C Library. 3 4 This program is free software: you can redistribute it and/or modify 5 it under the terms of the GNU General Public License as published by 6 the Free Software Foundation; either version 3 of the License, or 7 (at your option) any later version. 8 9 This program is distributed in the hope that it will be useful, 10 but WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 GNU General Public License for more details. 13 14 You should have received a copy of the GNU General Public License 15 along with this program. If not, see <http://www.gnu.org/licenses/>. */ 16 17/* Extracted from sysdeps/posix/tempname.c. */ 18 19#include <config.h> 20 21/* Specification. */ 22#include "tmpdir.h" 23 24#include <stdbool.h> 25#include <stdlib.h> 26#include <string.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 38#include <sys/stat.h> 39 40#if _LIBC 41# define struct_stat64 struct stat64 42#else 43# define struct_stat64 struct stat 44# define __xstat64(version, path, buf) stat (path, buf) 45#endif 46 47#if ! (HAVE___SECURE_GETENV || _LIBC) 48# define __secure_getenv getenv 49#endif 50 51/* Pathname support. 52 ISSLASH(C) tests whether C is a directory separator character. 53 */ 54#if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__ 55 /* Win32, Cygwin, OS/2, DOS */ 56# define ISSLASH(C) ((C) == '/' || (C) == '\\') 57#else 58 /* Unix */ 59# define ISSLASH(C) ((C) == '/') 60#endif 61 62 63/* Return nonzero if DIR is an existent directory. */ 64static bool 65direxists (const char *dir) 66{ 67 struct_stat64 buf; 68 return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode); 69} 70 71/* Path search algorithm, for tmpnam, tmpfile, etc. If DIR is 72 non-null and exists, uses it; otherwise uses the first of $TMPDIR, 73 P_tmpdir, /tmp that exists. Copies into TMPL a template suitable 74 for use with mk[s]temp. Will fail (-1) if DIR is non-null and 75 doesn't exist, none of the searched dirs exists, or there's not 76 enough space in TMPL. */ 77int 78path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx, 79 bool try_tmpdir) 80{ 81 const char *d; 82 size_t dlen, plen; 83 84 if (!pfx || !pfx[0]) 85 { 86 pfx = "file"; 87 plen = 4; 88 } 89 else 90 { 91 plen = strlen (pfx); 92 if (plen > 5) 93 plen = 5; 94 } 95 96 if (try_tmpdir) 97 { 98 d = __secure_getenv ("TMPDIR"); 99 if (d != NULL && direxists (d)) 100 dir = d; 101 else if (dir != NULL && direxists (dir)) 102 /* nothing */ ; 103 else 104 dir = NULL; 105 } 106 if (dir == NULL) 107 { 108 if (direxists (P_tmpdir)) 109 dir = P_tmpdir; 110 else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp")) 111 dir = "/tmp"; 112 else 113 { 114 __set_errno (ENOENT); 115 return -1; 116 } 117 } 118 119 dlen = strlen (dir); 120 while (dlen >= 1 && ISSLASH (dir[dlen - 1])) 121 dlen--; /* remove trailing slashes */ 122 123 /* check we have room for "${dir}/${pfx}XXXXXX\0" */ 124 if (tmpl_len < dlen + 1 + plen + 6 + 1) 125 { 126 __set_errno (EINVAL); 127 return -1; 128 } 129 130 sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx); 131 return 0; 132} 133