bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "lib.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "ioloop.h"
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen#include "time-util.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "hostpid.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "maildir-storage.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen#include "maildir-filename.h"
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainenconst char *maildir_filename_generate(void)
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen{
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen static struct timeval last_tv = { 0, 0 };
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen struct timeval tv;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen /* use secs + usecs to guarantee uniqueness within this process. */
7ef3553585e556f35d5919589cfdc1de3329e4bbTimo Sirainen if (timeval_cmp(&ioloop_timeval, &last_tv) > 0)
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen tv = ioloop_timeval;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen else {
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen tv = last_tv;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen if (++tv.tv_usec == 1000000) {
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen tv.tv_sec++;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen tv.tv_usec = 0;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen last_tv = tv;
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen return t_strdup_printf("%s.M%sP%s.%s",
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen dec2str(tv.tv_sec), dec2str(tv.tv_usec),
538303a216166f3526c0ae9658c9978275cfa100Timo Sirainen my_pid, my_hostname);
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen}
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainenbool maildir_filename_get_size(const char *fname, char type, uoff_t *size_r)
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen{
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen uoff_t size = 0;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen for (; *fname != '\0'; fname++) {
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen i_assert(*fname != '/');
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen if (*fname == ',' && fname[1] == type && fname[2] == '=') {
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen fname += 3;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen break;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen if (*fname == '\0')
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen return FALSE;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen while (*fname >= '0' && *fname <= '9') {
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen size = size * 10 + (*fname - '0');
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen fname++;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen if (*fname != MAILDIR_INFO_SEP &&
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen *fname != MAILDIR_EXTRA_SEP &&
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen *fname != '\0')
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen return FALSE;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen *size_r = size;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen return TRUE;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen}
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen/* a char* hash function from ASU -- from glib */
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenunsigned int maildir_filename_base_hash(const char *s)
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen{
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen unsigned int g, h = 0;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen while (*s != MAILDIR_INFO_SEP && *s != '\0') {
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen i_assert(*s != '/');
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen h = (h << 4) + *s;
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((g = h & 0xf0000000UL) != 0) {
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen h = h ^ (g >> 24);
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen h = h ^ g;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen s++;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen return h;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen}
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainenint maildir_filename_base_cmp(const char *fname1, const char *fname2)
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen{
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen while (*fname1 == *fname2 && *fname1 != MAILDIR_INFO_SEP &&
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen *fname1 != '\0') {
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen i_assert(*fname1 != '/');
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen fname1++; fname2++;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen }
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen if ((*fname1 == '\0' || *fname1 == MAILDIR_INFO_SEP) &&
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen (*fname2 == '\0' || *fname2 == MAILDIR_INFO_SEP))
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen return 0;
eac60b7aef3924a611656b184412be1e80b2ed5bTimo Sirainen return *fname1 - *fname2;
e8bdf1be00aec45d0c6dd72ad9c8be02a3dfc778Timo Sirainen}
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainenstatic bool maildir_fname_get_usecs(const char *fname, int *usecs_r)
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen{
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen int usecs = 0;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen /* Assume we already read the timestamp. Next up is
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen ".<uniqueness>.<host>". Find usecs inside the uniqueness. */
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen if (*fname != '.')
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen return FALSE;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen fname++;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen while (*fname != '\0' && *fname != '.' && *fname != MAILDIR_INFO_SEP) {
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen if (*fname++ == 'M') {
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen while (*fname >= '0' && *fname <= '9') {
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen usecs = usecs * 10 + (*fname - '0');
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen fname++;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen *usecs_r = usecs;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen return TRUE;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen return FALSE;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen}
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainenint maildir_filename_sort_cmp(const char *fname1, const char *fname2)
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen{
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen const char *s1, *s2;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen time_t secs1 = 0, secs2 = 0;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen int ret, usecs1, usecs2;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen /* sort primarily by the timestamp in file name */
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen for (s1 = fname1; *s1 >= '0' && *s1 <= '9'; s1++)
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen secs1 = secs1 * 10 + (*s1 - '0');
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen for (s2 = fname2; *s2 >= '0' && *s2 <= '9'; s2++)
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen secs2 = secs2 * 10 + (*s2 - '0');
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen ret = (int)((long)secs1 - (long)secs2);
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen if (ret == 0) {
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen /* sort secondarily by microseconds, if they exist */
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen if (maildir_fname_get_usecs(s1, &usecs1) &&
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen maildir_fname_get_usecs(s2, &usecs2))
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen ret = usecs1 - usecs2;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen if (ret == 0) {
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen /* fallback to comparing the base file name */
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen ret = maildir_filename_base_cmp(s1, s2);
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen }
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen return ret;
65d89650662f7f1681a3431c585bfc9721a85149Timo Sirainen}