Add copyright notices to long-enough files that lack them, since
[gnulib.git] / lib / tmpdir.c
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 2, or (at your option)
7    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, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 /* Extracted from sysdeps/posix/tempname.c.  */
19
20 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 /* Specification.  */
25 #include "tmpdir.h"
26
27 #include <stdbool.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <errno.h>
32 #ifndef __set_errno
33 # define __set_errno(Val) errno = (Val)
34 #endif
35
36 #include <stdio.h>
37 #ifndef P_tmpdir
38 # define P_tmpdir "/tmp"
39 #endif
40
41 #include <sys/stat.h>
42 #if !defined S_ISDIR && defined S_IFDIR
43 # define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
44 #endif
45 #if !S_IRUSR && S_IREAD
46 # define S_IRUSR S_IREAD
47 #endif
48 #if !S_IRUSR
49 # define S_IRUSR 00400
50 #endif
51 #if !S_IWUSR && S_IWRITE
52 # define S_IWUSR S_IWRITE
53 #endif
54 #if !S_IWUSR
55 # define S_IWUSR 00200
56 #endif
57 #if !S_IXUSR && S_IEXEC
58 # define S_IXUSR S_IEXEC
59 #endif
60 #if !S_IXUSR
61 # define S_IXUSR 00100
62 #endif
63
64 #if _LIBC
65 # define struct_stat64 struct stat64
66 #else
67 # define struct_stat64 struct stat
68 # define __xstat64(version, path, buf) stat (path, buf)
69 #endif
70
71 #if ! (HAVE___SECURE_GETENV || _LIBC)
72 # define __secure_getenv getenv
73 #endif
74
75 /* Pathname support.
76    ISSLASH(C)           tests whether C is a directory separator character.
77  */
78 #if defined _WIN32 || defined __WIN32__ || defined __CYGWIN__ || defined __EMX__ || defined __DJGPP__
79   /* Win32, Cygwin, OS/2, DOS */
80 # define ISSLASH(C) ((C) == '/' || (C) == '\\')
81 #else
82   /* Unix */
83 # define ISSLASH(C) ((C) == '/')
84 #endif
85
86
87 /* Return nonzero if DIR is an existent directory.  */
88 static bool
89 direxists (const char *dir)
90 {
91   struct_stat64 buf;
92   return __xstat64 (_STAT_VER, dir, &buf) == 0 && S_ISDIR (buf.st_mode);
93 }
94
95 /* Path search algorithm, for tmpnam, tmpfile, etc.  If DIR is
96    non-null and exists, uses it; otherwise uses the first of $TMPDIR,
97    P_tmpdir, /tmp that exists.  Copies into TMPL a template suitable
98    for use with mk[s]temp.  Will fail (-1) if DIR is non-null and
99    doesn't exist, none of the searched dirs exists, or there's not
100    enough space in TMPL. */
101 int
102 path_search (char *tmpl, size_t tmpl_len, const char *dir, const char *pfx,
103              bool try_tmpdir)
104 {
105   const char *d;
106   size_t dlen, plen;
107
108   if (!pfx || !pfx[0])
109     {
110       pfx = "file";
111       plen = 4;
112     }
113   else
114     {
115       plen = strlen (pfx);
116       if (plen > 5)
117         plen = 5;
118     }
119
120   if (try_tmpdir)
121     {
122       d = __secure_getenv ("TMPDIR");
123       if (d != NULL && direxists (d))
124         dir = d;
125       else if (dir != NULL && direxists (dir))
126         /* nothing */ ;
127       else
128         dir = NULL;
129     }
130   if (dir == NULL)
131     {
132       if (direxists (P_tmpdir))
133         dir = P_tmpdir;
134       else if (strcmp (P_tmpdir, "/tmp") != 0 && direxists ("/tmp"))
135         dir = "/tmp";
136       else
137         {
138           __set_errno (ENOENT);
139           return -1;
140         }
141     }
142
143   dlen = strlen (dir);
144   while (dlen >= 1 && ISSLASH (dir[dlen - 1]))
145     dlen--;                     /* remove trailing slashes */
146
147   /* check we have room for "${dir}/${pfx}XXXXXX\0" */
148   if (tmpl_len < dlen + 1 + plen + 6 + 1)
149     {
150       __set_errno (EINVAL);
151       return -1;
152     }
153
154   sprintf (tmpl, "%.*s/%.*sXXXXXX", (int) dlen, dir, (int) plen, pfx);
155   return 0;
156 }