2 * File functions for the CUPS scheduler.
4 * Copyright © 2007-2014 by Apple Inc.
5 * Copyright © 1997-2007 by Easy Software Products, all rights reserved.
7 * Licensed under Apache License v2.0. See the file "LICENSE" for more
12 * Include necessary headers...
18 #ifdef HAVE_REMOVEFILE
19 # include <removefile.h>
21 static int overwrite_data(int fd, const char *buffer, int bufsize,
23 #endif /* HAVE_REMOVEFILE */
27 * 'cupsdCleanFiles()' - Clean out old files.
31 cupsdCleanFiles(const char *path, /* I - Directory to clean */
32 const char *pattern) /* I - Filename pattern or NULL */
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 */
40 cupsdLogMessage(CUPSD_LOG_DEBUG,
41 "cupsdCleanFiles(path=\"%s\", pattern=\"%s\")", path,
42 pattern ? pattern : "(null)");
44 if ((dir = cupsDirOpen(path)) == NULL)
46 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open directory \"%s\" - %s",
47 path, strerror(errno));
51 cupsdLogMessage(CUPSD_LOG_INFO, "Cleaning out old files in \"%s\".", path);
53 while ((dent = cupsDirRead(dir)) != NULL)
55 if (pattern && fnmatch(pattern, dent->filename, 0))
58 snprintf(filename, sizeof(filename), "%s/%s", path, dent->filename);
60 if (S_ISDIR(dent->fileinfo.st_mode))
62 cupsdCleanFiles(filename, pattern);
64 status = rmdir(filename);
67 status = cupsdUnlinkOrRemoveFile(filename);
70 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to remove \"%s\" - %s", filename,
79 * 'cupsdCloseCreatedConfFile()' - Close a created configuration file and move
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 */
88 char newfile[1024], /* filename.N */
89 oldfile[1024]; /* filename.O */
93 * Synchronize changes to disk if SyncOnClose is enabled.
98 if (cupsFileFlush(fp))
100 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to write changes to \"%s\": %s",
101 filename, strerror(errno));
106 if (fsync(cupsFileNumber(fp)))
108 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to sync changes to \"%s\": %s",
109 filename, strerror(errno));
116 * First close the file...
119 if (cupsFileClose(fp))
123 * Then remove "filename.O", rename "filename" to "filename.O", and rename
124 * "filename.N" to "filename".
127 snprintf(newfile, sizeof(newfile), "%s.N", filename);
128 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
130 if ((cupsdUnlinkOrRemoveFile(oldfile) && errno != ENOENT) ||
131 (rename(filename, oldfile) && errno != ENOENT) ||
132 rename(newfile, filename))
134 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to finalize \"%s\": %s",
135 filename, strerror(errno));
144 * 'cupsdClosePipe()' - Close a pipe as necessary.
148 cupsdClosePipe(int *fds) /* I - Pipe file descriptors (2) */
151 * Close file descriptors as needed...
169 * 'cupsdCreateConfFile()' - Create a configuration file safely.
172 cups_file_t * /* O - File pointer */
174 const char *filename, /* I - Filename */
175 mode_t mode) /* I - Permissions */
177 cups_file_t *fp; /* File pointer */
178 char newfile[1024]; /* filename.N */
181 snprintf(newfile, sizeof(newfile), "%s.N", filename);
182 if ((fp = cupsFileOpen(newfile, "w")) == NULL)
184 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to create \"%s\": %s", newfile,
189 if (!getuid() && fchown(cupsFileNumber(fp), getuid(), Group))
190 cupsdLogMessage(CUPSD_LOG_WARN, "Unable to change group for \"%s\": %s",
191 newfile, strerror(errno));
193 if (fchmod(cupsFileNumber(fp), mode))
194 cupsdLogMessage(CUPSD_LOG_WARN,
195 "Unable to change permissions for \"%s\": %s",
196 newfile, strerror(errno));
204 * 'cupsdOpenConfFile()' - Open a configuration file.
206 * This function looks for "filename.O" if "filename" does not exist and does
207 * a rename as needed.
210 cups_file_t * /* O - File pointer */
211 cupsdOpenConfFile(const char *filename) /* I - Filename */
213 cups_file_t *fp; /* File pointer */
216 if ((fp = cupsFileOpen(filename, "r")) == NULL)
221 * Try opening the backup file...
224 char oldfile[1024]; /* filename.O */
226 snprintf(oldfile, sizeof(oldfile), "%s.O", filename);
227 fp = cupsFileOpen(oldfile, "r");
230 cupsdLogMessage(CUPSD_LOG_ERROR, "Unable to open \"%s\": %s", filename,
239 * 'cupsdOpenPipe()' - Create a pipe which is closed on exec.
242 int /* O - 0 on success, -1 on error */
243 cupsdOpenPipe(int *fds) /* O - Pipe file descriptors (2) */
258 * Set the "close on exec" flag on each end of the pipe...
261 if (fcntl(fds[0], F_SETFD, fcntl(fds[0], F_GETFD) | FD_CLOEXEC))
272 if (fcntl(fds[1], F_SETFD, fcntl(fds[1], F_GETFD) | FD_CLOEXEC))
284 * Return 0 indicating success...
292 * 'cupsdRemoveFile()' - Remove a file securely.
295 int /* O - 0 on success, -1 on error */
296 cupsdRemoveFile(const char *filename) /* I - File to remove */
298 #ifdef HAVE_REMOVEFILE
300 * See if the file exists...
303 if (access(filename, 0))
306 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
312 return (removefile(filename, NULL, REMOVEFILE_SECURE_1_PASS));
315 int fd; /* File descriptor */
316 struct stat info; /* File information */
317 char buffer[512]; /* Data buffer */
318 int i; /* Looping var */
322 * See if the file exists...
325 if (access(filename, 0))
328 cupsdLogMessage(CUPSD_LOG_DEBUG, "Securely removing \"%s\".", filename);
331 * First open the file for writing in exclusive mode.
334 if ((fd = open(filename, O_WRONLY | O_EXCL)) < 0)
338 * Delete the file now - it will still be around as long as the file is
342 if (unlink(filename))
349 * Then get the file size...
352 if (fstat(fd, &info))
359 * Overwrite the file with random data.
362 CUPS_SRAND(time(NULL));
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))
373 * Close the file, which will lead to the actual deletion, and return...
377 #endif /* HAVE_REMOVEFILE */
382 * 'cupsdUnlinkOrRemoveFile()' - Unlink or securely remove a file depending
383 * on the configuration.
386 int /* O - 0 on success, -1 on error */
387 cupsdUnlinkOrRemoveFile(
388 const char *filename) /* I - Filename */
391 return (cupsdRemoveFile(filename));
393 return (unlink(filename));
397 #ifndef HAVE_REMOVEFILE
399 * 'overwrite_data()' - Overwrite the data in a file.
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 */
408 int bytes; /* Bytes to write/written */
412 * Start at the beginning of the file...
415 if (lseek(fd, 0, SEEK_SET) < 0)
419 * Fill the file with the provided data...
424 if (filesize > bufsize)
429 if ((bytes = write(fd, buffer, (size_t)bytes)) < 0)
436 * Force the changes to disk...
441 #endif /* HAVE_REMOVEFILE */