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