Revert manifest to default one
[external/cups.git] / scheduler / file.c
1 /*
2  * "$Id: file.c 9766 2011-05-11 22:17:34Z mike $"
3  *
4  *   File functions for the CUPS scheduler.
5  *
6  *   Copyright 2007-2011 by Apple Inc.
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  *
17  *   cupsdCleanFiles()           - Clean out old files.
18  *   cupsdCloseCreatedConfFile() - Close a created configuration file and move
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 using the 7-pass US DoD method.
25  *   overwrite_data()            - Overwrite the data in a file.
26  */
27
28 /*
29  * Include necessary headers...
30  */
31
32 #include "cupsd.h"
33 #include <cups/dir.h>
34 #include <fnmatch.h>
35 #ifdef HAVE_REMOVEFILE
36 #  include <removefile.h>
37 #else
38 static int      overwrite_data(int fd, const char *buffer, int bufsize,
39                                int filesize);
40 #endif /* HAVE_REMOVEFILE */
41
42
43 /*
44  * 'cupsdCleanFiles()' - Clean out old files.
45  */
46  
47 void
48 cupsdCleanFiles(const char *path,       /* I - Directory to clean */
49                 const char *pattern)    /* I - Filename pattern or NULL */
50 {
51   cups_dir_t    *dir;                   /* Directory */
52   cups_dentry_t *dent;                  /* Directory entry */
53   char          filename[1024];         /* Filename */
54   int           status;                 /* Status from unlink/rmdir */
55
56
57   cupsdLogMessage(CUPSD_LOG_DEBUG,
58                   "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
59                   pattern ? pattern : "(null)");
60
61   if ((dir = cupsDirOpen(path)) == NULL)
62   {
63     cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
64                     path, strerror(errno));
65     return;
66   }
67
68   cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\"...", path);
69
70   while ((dent = cupsDirRead(dir)) != NULL)
71   {
72     if (pattern && fnmatch(pattern, dent->filename, 0))
73       continue;
74
75     snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
76
77     if (S_ISDIR(dent->fileinfo.st_mode))
78     {
79       cupsdCleanFiles(filename, pattern);
80
81       status = rmdir(filename);
82     }
83     else
84       status = unlink(filename);
85
86     if (status)
87       cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
88                       strerror(errno));
89     else
90       cupsdLogMessage(CUPSD_LOG_DEBUG, "Removed \"%s\"...", filename);
91   }
92
93   cupsDirClose(dir);
94 }
95
96
97 /*
98  * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move
99  *                                 into place.
100  */
101
102 int                                     /* O - 0 on success, -1 on error */
103 cupsdCloseCreatedConfFile(
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
126   if ((cupsdRemoveFile(oldfile) && errno != ENOENT) ||
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
143 void
144 cupsdClosePipe(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
168 cups_file_t *                           /* O - File pointer */
169 cupsdCreateConfFile(
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
206 cups_file_t *                           /* O - File pointer */
207 cupsdOpenConfFile(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
238 int                                     /* O - 0 on success, -1 on error */
239 cupsdOpenPipe(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 /*
288  * 'cupsdRemoveFile()' - Remove a file using the 7-pass US DoD method.
289  */
290
291 int                                     /* O - 0 on success, -1 on error */
292 cupsdRemoveFile(const char *filename)   /* I - File to remove */
293 {
294 #ifdef HAVE_REMOVEFILE
295   return (removefile(filename, NULL, REMOVEFILE_SECURE_7_PASS));
296
297 #else
298   int                   fd;             /* File descriptor */
299   struct stat           info;           /* File information */
300   char                  buffer[512];    /* Data buffer */
301   int                   i;              /* Looping var */
302
303
304  /*
305   * First open the file for writing in exclusive mode.
306   */
307
308   if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
309     return (-1);
310
311  /*
312   * Delete the file now - it will still be around as long as the file is
313   * open...
314   */
315
316   if (unlink(filename))
317   {
318     close(fd);
319     return (-1);
320   }
321
322  /*
323   * Then get the file size...
324   */
325
326   if (fstat(fd, &info))
327   {
328     close(fd);
329     return (-1);
330   }
331
332  /*
333   * Overwrite the file 7 times with 0xF6, 0x00, 0xFF, random, 0x00, 0xFF,
334   * and more random data.
335   */
336
337   memset(buffer, 0xF6, sizeof(buffer));
338   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
339   {
340     close(fd);
341     return (-1);
342   }
343
344   memset(buffer, 0x00, sizeof(buffer));
345   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
346   {
347     close(fd);
348     return (-1);
349   }
350
351   memset(buffer, 0xFF, sizeof(buffer));
352   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
353   {
354     close(fd);
355     return (-1);
356   }
357
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
368   memset(buffer, 0x00, sizeof(buffer));
369   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
370   {
371     close(fd);
372     return (-1);
373   }
374
375   memset(buffer, 0xFF, sizeof(buffer));
376   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
377   {
378     close(fd);
379     return (-1);
380   }
381
382   for (i = 0; i < sizeof(buffer); i ++)
383     buffer[i] = CUPS_RAND();
384   if (overwrite_data(fd, buffer, sizeof(buffer), (int)info.st_size))
385   {
386     close(fd);
387     return (-1);
388   }
389
390  /*
391   * Whew!  Close the file (which will lead to the actual deletion) and
392   * return success...
393   */
394
395   close(fd);
396   return (0);
397 #endif /* HAVE_REMOVEFILE */
398 }
399
400
401 #ifndef HAVE_REMOVEFILE
402 /*
403  * 'overwrite_data()' - Overwrite the data in a file.
404  */
405
406 static int                              /* O - 0 on success, -1 on error */
407 overwrite_data(int        fd,           /* I - File descriptor */
408                const char *buffer,      /* I - Buffer to write */
409                int        bufsize,      /* I - Size of buffer */
410                int        filesize)     /* I - Size of file */
411 {
412   int   bytes;                          /* Bytes to write/written */
413
414
415  /*
416   * Start at the beginning of the file...
417   */
418
419   if (lseek(fd, 0, SEEK_SET) < 0)
420     return (-1);
421
422  /*
423   * Fill the file with the provided data...
424   */
425
426   while (filesize > 0)
427   {
428     if (filesize > bufsize)
429       bytes = bufsize;
430     else
431       bytes = filesize;
432
433     if ((bytes = write(fd, buffer, bytes)) < 0)
434       return (-1);
435
436     filesize -= bytes;
437   }
438
439  /*
440   * Force the changes to disk...
441   */
442
443   return (fsync(fd));
444 }
445 #endif /* HAVE_REMOVEFILE */
446
447
448 /*
449  * End of "$Id: file.c 9766 2011-05-11 22:17:34Z mike $".
450  */