1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
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;
}
|