]> git.ipfire.org Git - thirdparty/cups.git/blame - scheduler/file.c
Fix typos in examples - CUPS-Add-Modify-xxx instead of CUPS-Add-xxx.
[thirdparty/cups.git] / scheduler / file.c
CommitLineData
321d8d57
MS
1/*
2 * "$Id$"
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
111 /*
112 * First close the file...
113 */
114
115 if (cupsFileClose(fp))
116 return (-1);
117
118 /*
119 * Then remove "filename.O", rename "filename" to "filename.O", and rename
120 * "filename.N" to "filename".
121 */
122
123 snprintf(newfile, sizeof(newfile), "%s.N", filename);
124 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
125
cb7f98ee 126 if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
321d8d57
MS
127 (rename(filename, oldfile) && errno != ENOENT) ||
128 rename(newfile, filename))
129 {
130 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
131 filename, strerror(errno));
132 return (-1);
133 }
134
135 return (0);
136}
137
138
139/*
140 * 'cupsdClosePipe()' - Close a pipe as necessary.
141 */
142
143void
144cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */
145{
146 /*
147 * Close file descriptors as needed...
148 */
149
150 if (fds[0] >= 0)
151 {
152 close(fds[0]);
153 fds[0] = -1;
154 }
155
156 if (fds[1] >= 0)
157 {
158 close(fds[1]);
159 fds[1] = -1;
160 }
161}
162
163
164/*
165 * 'cupsdCreateConfFile()' - Create a configuration file safely.
166 */
167
168cups_file_t * /* O - File pointer */
169cupsdCreateConfFile(
170 const char *filename, /* I - Filename */
171 mode_t mode) /* I - Permissions */
172{
173 cups_file_t *fp; /* File pointer */
174 char newfile[1024]; /* filename.N */
175
176
177 snprintf(newfile, sizeof(newfile), "%s.N", filename);
178 if ((fp = cupsFileOpen(newfile, "w")) == NULL)
179 {
180 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
181 strerror(errno));
182 }
183 else
184 {
185 if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
186 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
187 newfile, strerror(errno));
188
189 if (fchmod(cupsFileNumber(fp), mode))
190 cupsdLogMessage(CUPSD_LOG_WARN,
191 "Unable to change permissions for \"%s\": %s",
192 newfile, strerror(errno));
193 }
194
195 return (fp);
196}
197
198
199/*
200 * 'cupsdOpenConfFile()' - Open a configuration file.
201 *
202 * This function looks for "filename.O" if "filename" does not exist and does
203 * a rename as needed.
204 */
205
206cups_file_t * /* O - File pointer */
207cupsdOpenConfFile(const char *filename) /* I - Filename */
208{
209 cups_file_t *fp; /* File pointer */
210
211
212 if ((fp = cupsFileOpen(filename, "r")) == NULL)
213 {
214 if (errno == ENOENT)
215 {
216 /*
217 * Try opening the backup file...
218 */
219
220 char oldfile[1024]; /* filename.O */
221
222 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
223 fp = cupsFileOpen(oldfile, "r");
224 }
225 else
226 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
227 strerror(errno));
228 }
229
230 return (fp);
231}
232
233
234/*
235 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
236 */
237
238int /* O - 0 on success, -1 on error */
239cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */
240{
241 /*
242 * Create the pipe...
243 */
244
245 if (pipe(fds))
246 {
247 fds[0] = -1;
248 fds[1] = -1;
249
250 return (-1);
251 }
252
253 /*
254 * Set the "close on exec" flag on each end of the pipe...
255 */
256
257 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
258 {
259 close(fds[0]);
260 close(fds[1]);
261
262 fds[0] = -1;
263 fds[1] = -1;
264
265 return (-1);
266 }
267
268 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
269 {
270 close(fds[0]);
271 close(fds[1]);
272
273 fds[0] = -1;
274 fds[1] = -1;
275
276 return (-1);
277 }
278
279 /*
280 * Return 0 indicating success...
281 */
282
283 return (0);
284}
285
286
287/*
cb7f98ee 288 * 'cupsdRemoveFile()' - Remove a file securely.
321d8d57
MS
289 */
290
291int /* O - 0 on success, -1 on error */
292cupsdRemoveFile(const char *filename) /* I - File to remove */
293{
294#ifdef HAVE_REMOVEFILE
cb7f98ee
MS
295 /*
296 * See if the file exists...
297 */
298
299 if (access(filename, 0))
300 return (0);
301
302 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
303
304 /*
305 * Remove the file...
306 */
307
308 return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS));
321d8d57
MS
309
310#else
311 int fd; /* File descriptor */
312 struct stat info; /* File information */
313 char buffer[512]; /* Data buffer */
314 int i; /* Looping var */
315
316
cb7f98ee
MS
317 /*
318 * See if the file exists...
319 */
320
321 if (access(filename, 0))
322 return (0);
323
324 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
325
321d8d57
MS
326 /*
327 * First open the file for writing in exclusive mode.
328 */
329
330 if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
331 return (-1);
332
333 /*
334 * Delete the file now - it will still be around as long as the file is
335 * open...
336 */
337
338 if (unlink(filename))
339 {
340 close(fd);
341 return (-1);
342 }
343
344 /*
345 * Then get the file size...
346 */
347
348 if (fstat(fd, &info))
349 {
350 close(fd);
351 return (-1);
352 }
353
354 /*
cb7f98ee 355 * Overwrite the file with random data.
321d8d57
MS
356 */
357
321d8d57
MS
358 CUPS_SRAND(time(NULL));
359
360 for (i = 0; i < sizeof(buffer); i ++)
361 buffer[i] = CUPS_RAND();
362 if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
363 {
364 close(fd);
365 return (-1);
366 }
367
321d8d57 368 /*
cb7f98ee 369 * Close the file, which will lead to the actual deletion, and return...
321d8d57
MS
370 */
371
cb7f98ee 372 return (close(fd));
321d8d57
MS
373#endif /* HAVE_REMOVEFILE */
374}
375
376
cb7f98ee
MS
377/*
378 * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending
379 * on the configuration.
380 */
381
382int /* O - 0 on success, -1 on error */
383cupsdUnlinkOrRemoveFile(
384 const char *filename) /* I - Filename */
385{
386 if (Classification)
387 return (cupsdRemoveFile(filename));
388 else
389 return (unlink(filename));
390}
391
392
321d8d57
MS
393#ifndef HAVE_REMOVEFILE
394/*
395 * 'overwrite_data()' - Overwrite the data in a file.
396 */
397
398static int /* O - 0 on success, -1 on error */
399overwrite_data(int fd, /* I - File descriptor */
400 const char *buffer, /* I - Buffer to write */
401 int bufsize, /* I - Size of buffer */
402 int filesize) /* I - Size of file */
403{
404 int bytes; /* Bytes to write/written */
405
406
407 /*
408 * Start at the beginning of the file...
409 */
410
411 if (lseek(fd, 0, SEEK_SET) < 0)
412 return (-1);
413
414 /*
415 * Fill the file with the provided data...
416 */
417
418 while (filesize > 0)
419 {
420 if (filesize > bufsize)
421 bytes = bufsize;
422 else
423 bytes = filesize;
424
425 if ((bytes = write(fd, buffer, bytes)) < 0)
426 return (-1);
427
428 filesize -= bytes;
429 }
430
431 /*
432 * Force the changes to disk...
433 */
434
435 return (fsync(fd));
436}
437#endif /* HAVE_REMOVEFILE */
438
439
440/*
441 * End of "$Id$".
442 */