summaryrefslogtreecommitdiffstats
path: root/src/lib-storage/index/maildir/maildir-filename.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib-storage/index/maildir/maildir-filename.c')
-rw-r--r--src/lib-storage/index/maildir/maildir-filename.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/lib-storage/index/maildir/maildir-filename.c b/src/lib-storage/index/maildir/maildir-filename.c
new file mode 100644
index 0000000..9deba82
--- /dev/null
+++ b/src/lib-storage/index/maildir/maildir-filename.c
@@ -0,0 +1,143 @@
+/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "time-util.h"
+#include "hostpid.h"
+#include "maildir-storage.h"
+#include "maildir-filename.h"
+
+const char *maildir_filename_generate(void)
+{
+ static struct timeval last_tv = { 0, 0 };
+ struct timeval tv;
+
+ /* use secs + usecs to guarantee uniqueness within this process. */
+ if (timeval_cmp(&ioloop_timeval, &last_tv) > 0)
+ tv = ioloop_timeval;
+ else {
+ tv = last_tv;
+ if (++tv.tv_usec == 1000000) {
+ tv.tv_sec++;
+ tv.tv_usec = 0;
+ }
+ }
+ last_tv = tv;
+
+ return t_strdup_printf("%s.M%sP%s.%s",
+ dec2str(tv.tv_sec), dec2str(tv.tv_usec),
+ my_pid, my_hostname);
+}
+
+bool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r)
+{
+ uoff_t size = 0;
+
+ for (; *fname != '\0'; fname++) {
+ i_assert(*fname != '/');
+ if (*fname == ',' && fname[1] == type && fname[2] == '=') {
+ fname += 3;
+ break;
+ }
+ }
+
+ if (*fname == '\0')
+ return FALSE;
+
+ while (*fname >= '0' && *fname <= '9') {
+ size = size * 10 + (*fname - '0');
+ fname++;
+ }
+
+ if (*fname != MAILDIR_INFO_SEP &&
+ *fname != MAILDIR_EXTRA_SEP &&
+ *fname != '\0')
+ return FALSE;
+
+ *size_r = size;
+ return TRUE;
+}
+
+/* a char* hash function from ASU -- from glib */
+unsigned int ATTR_NO_SANITIZE_INTEGER
+maildir_filename_base_hash(const char *s)
+{
+ unsigned int g, h = 0;
+
+ while (*s != MAILDIR_INFO_SEP && *s != '\0') {
+ i_assert(*s != '/');
+ h = (h << 4) + *s;
+ if ((g = h & 0xf0000000UL) != 0) {
+ h = h ^ (g >> 24);
+ h = h ^ g;
+ }
+
+ s++;
+ }
+
+ return h;
+}
+
+int maildir_filename_base_cmp(const char *fname1, const char *fname2)
+{
+ while (*fname1 == *fname2 && *fname1 != MAILDIR_INFO_SEP &&
+ *fname1 != '\0') {
+ i_assert(*fname1 != '/');
+ fname1++; fname2++;
+ }
+
+ if ((*fname1 == '\0' || *fname1 == MAILDIR_INFO_SEP) &&
+ (*fname2 == '\0' || *fname2 == MAILDIR_INFO_SEP))
+ return 0;
+ return *fname1 - *fname2;
+}
+
+static bool maildir_fname_get_usecs(const char *fname, int *usecs_r)
+{
+ int usecs = 0;
+
+ /* Assume we already read the timestamp. Next up is
+ ".<uniqueness>.<host>". Find usecs inside the uniqueness. */
+ if (*fname != '.')
+ return FALSE;
+
+ fname++;
+ while (*fname != '\0' && *fname != '.' && *fname != MAILDIR_INFO_SEP) {
+ if (*fname++ == 'M') {
+ while (*fname >= '0' && *fname <= '9') {
+ usecs = usecs * 10 + (*fname - '0');
+ fname++;
+ }
+ *usecs_r = usecs;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+int maildir_filename_sort_cmp(const char *fname1, const char *fname2)
+{
+ const char *s1, *s2;
+ time_t secs1 = 0, secs2 = 0;
+ int ret, usecs1, usecs2;
+
+ /* sort primarily by the timestamp in file name */
+ for (s1 = fname1; *s1 >= '0' && *s1 <= '9'; s1++)
+ secs1 = secs1 * 10 + (*s1 - '0');
+ for (s2 = fname2; *s2 >= '0' && *s2 <= '9'; s2++)
+ secs2 = secs2 * 10 + (*s2 - '0');
+
+ ret = (int)((long)secs1 - (long)secs2);
+ if (ret == 0) {
+ /* sort secondarily by microseconds, if they exist */
+ if (maildir_fname_get_usecs(s1, &usecs1) &&
+ maildir_fname_get_usecs(s2, &usecs2))
+ ret = usecs1 - usecs2;
+
+ if (ret == 0) {
+ /* fallback to comparing the base file name */
+ ret = maildir_filename_base_cmp(s1, s2);
+ }
+ }
+ return ret;
+}