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