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