summaryrefslogtreecommitdiffstats
path: root/src/lib/unlink-old-files.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/lib/unlink-old-files.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/src/lib/unlink-old-files.c b/src/lib/unlink-old-files.c
new file mode 100644
index 0000000..4074327
--- /dev/null
+++ b/src/lib/unlink-old-files.c
@@ -0,0 +1,73 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "str.h"
+#include "unlink-old-files.h"
+
+#include <signal.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <utime.h>
+
+static int
+unlink_old_files_real(const char *dir, const char *prefix, time_t min_time)
+{
+ DIR *dirp;
+ struct dirent *d;
+ struct stat st;
+ string_t *path;
+ size_t prefix_len, dir_len;
+
+ dirp = opendir(dir);
+ if (dirp == NULL) {
+ if (errno != ENOENT)
+ i_error("opendir(%s) failed: %m", dir);
+ return -1;
+ }
+
+ /* update atime immediately, so if this scanning is done based on
+ atime it won't be done by multiple processes if the scan is slow */
+ if (utime(dir, NULL) < 0 && errno != ENOENT)
+ i_error("utime(%s) failed: %m", dir);
+
+ path = t_str_new(256);
+ str_printfa(path, "%s/", dir);
+ dir_len = str_len(path);
+
+ prefix_len = strlen(prefix);
+ while ((d = readdir(dirp)) != NULL) {
+ if (d->d_name[0] == '.' &&
+ (d->d_name[1] == '\0' ||
+ (d->d_name[1] == '.' && d->d_name[2] == '\0'))) {
+ /* skip . and .. */
+ continue;
+ }
+ if (strncmp(d->d_name, prefix, prefix_len) != 0)
+ continue;
+
+ str_truncate(path, dir_len);
+ str_append(path, d->d_name);
+ if (stat(str_c(path), &st) < 0) {
+ if (errno != ENOENT)
+ i_error("stat(%s) failed: %m", str_c(path));
+ } else if (!S_ISDIR(st.st_mode) && st.st_ctime < min_time) {
+ i_unlink_if_exists(str_c(path));
+ }
+ }
+
+ if (closedir(dirp) < 0)
+ i_error("closedir(%s) failed: %m", dir);
+ return 0;
+}
+
+int unlink_old_files(const char *dir, const char *prefix, time_t min_time)
+{
+ int ret;
+
+ T_BEGIN {
+ ret = unlink_old_files_real(dir, prefix, min_time);
+ } T_END;
+ return ret;
+}