1 /*
2 * Temp file utilities for CUPS.
3 *
4 * Copyright © 2007-2018 by Apple Inc.
5 * Copyright © 1997-2006 by Easy Software Products.
6 *
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
8 * information.
9 */
10
11 /*
12 * Include necessary headers...
13 */
14
15 #include "cups-private.h"
16 #include "debug-internal.h"
17 #include <stdlib.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #if defined(_WIN32) || defined(__EMX__)
21 # include <io.h>
22 #else
23 # include <unistd.h>
24 #endif /* _WIN32 || __EMX__ */
25
26
27 /*
28 * 'cupsTempFd()' - Creates a temporary file.
29 *
30 * The temporary filename is returned in the filename buffer.
31 * The temporary file is opened for reading and writing.
32 */
33
34 int /* O - New file descriptor or -1 on error */
cupsTempFd(char * filename,int len)35 cupsTempFd(char *filename, /* I - Pointer to buffer */
36 int len) /* I - Size of buffer */
37 {
38 int fd; /* File descriptor for temp file */
39 int tries; /* Number of tries */
40 const char *tmpdir; /* TMPDIR environment var */
41 #if defined(__APPLE__) || defined(_WIN32)
42 char tmppath[1024]; /* Temporary directory */
43 #endif /* __APPLE__ || _WIN32 */
44 #ifdef _WIN32
45 DWORD curtime; /* Current time */
46 #else
47 struct timeval curtime; /* Current time */
48 #endif /* _WIN32 */
49
50
51 /*
52 * See if TMPDIR is defined...
53 */
54
55 #ifdef _WIN32
56 if ((tmpdir = getenv("TEMP")) == NULL)
57 {
58 GetTempPathA(sizeof(tmppath), tmppath);
59 tmpdir = tmppath;
60 }
61
62 #elif defined(__APPLE__)
63 /*
64 * On macOS and iOS, the TMPDIR environment variable is not always the best
65 * location to place temporary files due to sandboxing. Instead, the confstr
66 * function should be called to get the proper per-user, per-process TMPDIR
67 * value.
68 */
69
70 if ((tmpdir = getenv("TMPDIR")) != NULL && access(tmpdir, W_OK))
71 tmpdir = NULL;
72
73 if (!tmpdir)
74 {
75 if (confstr(_CS_DARWIN_USER_TEMP_DIR, tmppath, sizeof(tmppath)))
76 tmpdir = tmppath;
77 else
78 tmpdir = "/private/tmp"; /* This should never happen */
79 }
80
81 #else
82 /*
83 * Previously we put root temporary files in the default CUPS temporary
84 * directory under /var/spool/cups. However, since the scheduler cleans
85 * out temporary files there and runs independently of the user apps, we
86 * don't want to use it unless specifically told to by cupsd.
87 */
88
89 if ((tmpdir = getenv("TMPDIR")) == NULL)
90 tmpdir = "/tmp";
91 #endif /* _WIN32 */
92
93 /*
94 * Make the temporary name using the specified directory...
95 */
96
97 tries = 0;
98
99 do
100 {
101 #ifdef _WIN32
102 /*
103 * Get the current time of day...
104 */
105
106 curtime = GetTickCount() + tries;
107
108 /*
109 * Format a string using the hex time values...
110 */
111
112 snprintf(filename, (size_t)len - 1, "%s/%05lx%08lx", tmpdir, GetCurrentProcessId(), curtime);
113 #else
114 /*
115 * Get the current time of day...
116 */
117
118 gettimeofday(&curtime, NULL);
119
120 /*
121 * Format a string using the hex time values...
122 */
123
124 snprintf(filename, (size_t)len - 1, "%s/%05x%08x", tmpdir, (unsigned)getpid(), (unsigned)(curtime.tv_sec + curtime.tv_usec + tries));
125 #endif /* _WIN32 */
126
127 /*
128 * Open the file in "exclusive" mode, making sure that we don't
129 * stomp on an existing file or someone's symlink crack...
130 */
131
132 #ifdef _WIN32
133 fd = open(filename, _O_CREAT | _O_RDWR | _O_TRUNC | _O_BINARY,
134 _S_IREAD | _S_IWRITE);
135 #elif defined(O_NOFOLLOW)
136 fd = open(filename, O_RDWR | O_CREAT | O_EXCL | O_NOFOLLOW, 0600);
137 #else
138 fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
139 #endif /* _WIN32 */
140
141 if (fd < 0 && errno != EEXIST)
142 break;
143
144 tries ++;
145 }
146 while (fd < 0 && tries < 1000);
147
148 /*
149 * Return the file descriptor...
150 */
151
152 return (fd);
153 }
154
155
156 /*
157 * 'cupsTempFile()' - Generates a temporary filename.
158 *
159 * The temporary filename is returned in the filename buffer.
160 * This function is deprecated and will no longer generate a temporary
161 * filename - use @link cupsTempFd@ or @link cupsTempFile2@ instead.
162 *
163 * @deprecated@
164 */
165
166 char * /* O - Filename or @code NULL@ on error */
cupsTempFile(char * filename,int len)167 cupsTempFile(char *filename, /* I - Pointer to buffer */
168 int len) /* I - Size of buffer */
169 {
170 (void)len;
171
172 if (filename)
173 *filename = '\0';
174
175 return (NULL);
176 }
177
178
179 /*
180 * 'cupsTempFile2()' - Creates a temporary CUPS file.
181 *
182 * The temporary filename is returned in the filename buffer.
183 * The temporary file is opened for writing.
184 *
185 * @since CUPS 1.2/macOS 10.5@
186 */
187
188 cups_file_t * /* O - CUPS file or @code NULL@ on error */
cupsTempFile2(char * filename,int len)189 cupsTempFile2(char *filename, /* I - Pointer to buffer */
190 int len) /* I - Size of buffer */
191 {
192 cups_file_t *file; /* CUPS file */
193 int fd; /* File descriptor */
194
195
196 if ((fd = cupsTempFd(filename, len)) < 0)
197 return (NULL);
198 else if ((file = cupsFileOpenFd(fd, "w")) == NULL)
199 {
200 close(fd);
201 unlink(filename);
202 return (NULL);
203 }
204 else
205 return (file);
206 }
207