]> git.ipfire.org Git - thirdparty/cups.git/blob - scheduler/file.c
Remove all of the Subversion keywords from various source files.
[thirdparty/cups.git] / scheduler / file.c
1 /*
2 * File functions for the CUPS scheduler.
3 *
4 * Copyright 2007-2014 by Apple Inc.
5 * Copyright 1997-2007 by Easy Software Products, all rights reserved.
6 *
7 * These coded instructions, statements, and computer programs are the
8 * property of Apple Inc. and are protected by Federal copyright
9 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
10 * "LICENSE" which should have been included with this file. If this
11 * file is missing or damaged, see the license at "http://www.cups.org/".
12 */
13
14 /*
15 * Include necessary headers...
16 */
17
18 #include "cupsd.h"
19 #include <cups/dir.h>
20 #include <fnmatch.h>
21 #ifdef HAVE_REMOVEFILE
22 # include <removefile.h>
23 #else
24 static int overwrite_data(int fd, const char *buffer, int bufsize,
25 int filesize);
26 #endif /* HAVE_REMOVEFILE */
27
28
29 /*
30 * 'cupsdCleanFiles()' - Clean out old files.
31 */
32
33 void
34 cupsdCleanFiles(const char *path, /* I - Directory to clean */
35 const char *pattern) /* I - Filename pattern or NULL */
36 {
37 cups_dir_t *dir; /* Directory */
38 cups_dentry_t *dent; /* Directory entry */
39 char filename[1024]; /* Filename */
40 int status; /* Status from unlink/rmdir */
41
42
43 cupsdLogMessage(CUPSD_LOG_DEBUG,
44 "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
45 pattern ? pattern : "(null)");
46
47 if ((dir = cupsDirOpen(path)) == NULL)
48 {
49 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
50 path, strerror(errno));
51 return;
52 }
53
54 cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path);
55
56 while ((dent = cupsDirRead(dir)) != NULL)
57 {
58 if (pattern && fnmatch(pattern, dent->filename, 0))
59 continue;
60
61 snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
62
63 if (S_ISDIR(dent->fileinfo.st_mode))
64 {
65 cupsdCleanFiles(filename, pattern);
66
67 status = rmdir(filename);
68 }
69 else
70 status = cupsdUnlinkOrRemoveFile(filename);
71
72 if (status)
73 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
74 strerror(errno));
75 }
76
77 cupsDirClose(dir);
78 }
79
80
81 /*
82 * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move
83 * into place.
84 */
85
86 int /* O - 0 on success, -1 on error */
87 cupsdCloseCreatedConfFile(
88 cups_file_t *fp, /* I - File to close */
89 const char *filename) /* I - Filename */
90 {
91 char newfile[1024], /* filename.N */
92 oldfile[1024]; /* filename.O */
93
94
95 /*
96 * Synchronize changes to disk if SyncOnClose is enabled.
97 */
98
99 if (SyncOnClose)
100 {
101 if (cupsFileFlush(fp))
102 {
103 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s",
104 filename, strerror(errno));
105 cupsFileClose(fp);
106 return (-1);
107 }
108
109 if (fsync(cupsFileNumber(fp)))
110 {
111 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s",
112 filename, strerror(errno));
113 cupsFileClose(fp);
114 return (-1);
115 }
116 }
117
118 /*
119 * First close the file...
120 */
121
122 if (cupsFileClose(fp))
123 return (-1);
124
125 /*
126 * Then remove "filename.O", rename "filename" to "filename.O", and rename
127 * "filename.N" to "filename".
128 */
129
130 snprintf(newfile, sizeof(newfile), "%s.N", filename);
131 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
132
133 if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
134 (rename(filename, oldfile) && errno != ENOENT) ||
135 rename(newfile, filename))
136 {
137 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
138 filename, strerror(errno));
139 return (-1);
140 }
141
142 return (0);
143 }
144
145
146 /*
147 * 'cupsdClosePipe()' - Close a pipe as necessary.
148 */
149
150 void
151 cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */
152 {
153 /*
154 * Close file descriptors as needed...
155 */
156
157 if (fds[0] >= 0)
158 {
159 close(fds[0]);
160 fds[0] = -1;
161 }
162
163 if (fds[1] >= 0)
164 {
165 close(fds[1]);
166 fds[1] = -1;
167 }
168 }
169
170
171 /*
172 * 'cupsdCreateConfFile()' - Create a configuration file safely.
173 */
174
175 cups_file_t * /* O - File pointer */
176 cupsdCreateConfFile(
177 const char *filename, /* I - Filename */
178 mode_t mode) /* I - Permissions */
179 {
180 cups_file_t *fp; /* File pointer */
181 char newfile[1024]; /* filename.N */
182
183
184 snprintf(newfile, sizeof(newfile), "%s.N", filename);
185 if ((fp = cupsFileOpen(newfile, "w")) == NULL)
186 {
187 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
188 strerror(errno));
189 }
190 else
191 {
192 if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
193 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
194 newfile, strerror(errno));
195
196 if (fchmod(cupsFileNumber(fp), mode))
197 cupsdLogMessage(CUPSD_LOG_WARN,
198 "Unable to change permissions for \"%s\": %s",
199 newfile, strerror(errno));
200 }
201
202 return (fp);
203 }
204
205
206 /*
207 * 'cupsdOpenConfFile()' - Open a configuration file.
208 *
209 * This function looks for "filename.O" if "filename" does not exist and does
210 * a rename as needed.
211 */
212
213 cups_file_t * /* O - File pointer */
214 cupsdOpenConfFile(const char *filename) /* I - Filename */
215 {
216 cups_file_t *fp; /* File pointer */
217
218
219 if ((fp = cupsFileOpen(filename, "r")) == NULL)
220 {
221 if (errno == ENOENT)
222 {
223 /*
224 * Try opening the backup file...
225 */
226
227 char oldfile[1024]; /* filename.O */
228
229 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
230 fp = cupsFileOpen(oldfile, "r");
231 }
232 else
233 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
234 strerror(errno));
235 }
236
237 return (fp);
238 }
239
240
241 /*
242 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
243 */
244
245 int /* O - 0 on success, -1 on error */
246 cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */
247 {
248 /*
249 * Create the pipe...
250 */
251
252 if (pipe(fds))
253 {
254 fds[0] = -1;
255 fds[1] = -1;
256
257 return (-1);
258 }
259
260 /*
261 * Set the "close on exec" flag on each end of the pipe...
262 */
263
264 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
265 {
266 close(fds[0]);
267 close(fds[1]);
268
269 fds[0] = -1;
270 fds[1] = -1;
271
272 return (-1);
273 }
274
275 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
276 {
277 close(fds[0]);
278 close(fds[1]);
279
280 fds[0] = -1;
281 fds[1] = -1;
282
283 return (-1);
284 }
285
286 /*
287 * Return 0 indicating success...
288 */
289
290 return (0);
291 }
292
293
294 /*
295 * 'cupsdRemoveFile()' - Remove a file securely.
296 */
297
298 int /* O - 0 on success, -1 on error */
299 cupsdRemoveFile(const char *filename) /* I - File to remove */
300 {
301 #ifdef HAVE_REMOVEFILE
302 /*
303 * See if the file exists...
304 */
305
306 if (access(filename, 0))
307 return (0);
308
309 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
310
311 /*
312 * Remove the file...
313 */
314
315 return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS));
316
317 #else
318 int fd; /* File descriptor */
319 struct stat info; /* File information */
320 char buffer[512]; /* Data buffer */
321 int i; /* Looping var */
322
323
324 /*
325 * See if the file exists...
326 */
327
328 if (access(filename, 0))
329 return (0);
330
331 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
332
333 /*
334 * First open the file for writing in exclusive mode.
335 */
336
337 if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
338 return (-1);
339
340 /*
341 * Delete the file now - it will still be around as long as the file is
342 * open...
343 */
344
345 if (unlink(filename))
346 {
347 close(fd);
348 return (-1);
349 }
350
351 /*
352 * Then get the file size...
353 */
354
355 if (fstat(fd, &info))
356 {
357 close(fd);
358 return (-1);
359 }
360
361 /*
362 * Overwrite the file with random data.
363 */
364
365 CUPS_SRAND(time(NULL));
366
367 for (i = 0; i < sizeof(buffer); i ++)
368 buffer[i] = CUPS_RAND();
369 if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
370 {
371 close(fd);
372 return (-1);
373 }
374
375 /*
376 * Close the file, which will lead to the actual deletion, and return...
377 */
378
379 return (close(fd));
380 #endif /* HAVE_REMOVEFILE */
381 }
382
383
384 /*
385 * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending
386 * on the configuration.
387 */
388
389 int /* O - 0 on success, -1 on error */
390 cupsdUnlinkOrRemoveFile(
391 const char *filename) /* I - Filename */
392 {
393 if (Classification)
394 return (cupsdRemoveFile(filename));
395 else
396 return (unlink(filename));
397 }
398
399
400 #ifndef HAVE_REMOVEFILE
401 /*
402 * 'overwrite_data()' - Overwrite the data in a file.
403 */
404
405 static int /* O - 0 on success, -1 on error */
406 overwrite_data(int fd, /* I - File descriptor */
407 const char *buffer, /* I - Buffer to write */
408 int bufsize, /* I - Size of buffer */
409 int filesize) /* I - Size of file */
410 {
411 int bytes; /* Bytes to write/written */
412
413
414 /*
415 * Start at the beginning of the file...
416 */
417
418 if (lseek(fd, 0, SEEK_SET) < 0)
419 return (-1);
420
421 /*
422 * Fill the file with the provided data...
423 */
424
425 while (filesize > 0)
426 {
427 if (filesize > bufsize)
428 bytes = bufsize;
429 else
430 bytes = filesize;
431
432 if ((bytes = write(fd, buffer, (size_t)bytes)) < 0)
433 return (-1);
434
435 filesize -= bytes;
436 }
437
438 /*
439 * Force the changes to disk...
440 */
441
442 return (fsync(fd));
443 }
444 #endif /* HAVE_REMOVEFILE */