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