*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
+ * the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
*/
#ifdef HAVE_CONFIG_H
#include <glib.h>
#include <glib/gi18n.h>
-#include <sys/mman.h>
+#ifdef _WIN32
+# include <w32lib.h>
+# define MAP_FAILED ((char *) -1)
+#else
+# include <sys/mman.h>
+#endif
#include <sys/types.h>
#include <sys/stat.h>
#include "procmsg.h"
#include "codeconv.h"
#include "timing.h"
+#include "tags.h"
#ifdef HAVE_FWRITE_UNLOCKED
#define SC_FWRITE fwrite_unlocked
((x[2]&0xff) << 16) | \
((x[3]&0xff) << 24))
+#ifdef G_OS_WIN32
+static gboolean msgcache_use_mmap_read = FALSE;
+#else
static gboolean msgcache_use_mmap_read = TRUE;
+#endif
static gboolean msgcache_use_mmap_write = FALSE;
#else
((x[2]&0xff) << 16) | \
((x[3]&0xff) << 24))
+#ifdef G_OS_WIN32
+static gboolean msgcache_use_mmap_read = FALSE;
+#else
static gboolean msgcache_use_mmap_read = TRUE;
+#endif
static gboolean msgcache_use_mmap_write = FALSE;
#endif
if (mode == DATA_WRITE) {
int w_err = 0, wrote = 0;
- if ((fp = g_fopen(file, "w+")) == NULL) {
+ if ((fp = g_fopen(file, "wb")) == NULL) {
FILE_OP_ERROR(file, "fopen");
return NULL;
}
return len;
}
-gchar *strconv_strdup_convert(StringConverter *conv, gchar *srcstr)
-{
- return g_strdup(srcstr);
-}
-
-gchar *strconv_charset_convert(StringConverter *conv, gchar *srcstr)
+static gchar *strconv_charset_convert(StringConverter *conv, gchar *srcstr)
{
CharsetConverter *charsetconv = (CharsetConverter *) conv;
return conv_codeset_strdup(srcstr, charsetconv->srccharset, charsetconv->dstcharset);
}
-void strconv_charset_free(StringConverter *conv)
+static void strconv_charset_free(StringConverter *conv)
{
CharsetConverter *charsetconv = (CharsetConverter *) conv;
tmp_flags |= MSG_DRAFT;
}
- if (msgcache_read_cache_data_str(fp, &srccharset, NULL) < 0)
+ if (msgcache_read_cache_data_str(fp, &srccharset, NULL) < 0) {
+ fclose(fp);
return NULL;
+ }
dstcharset = CS_UTF_8;
if (srccharset == NULL || dstcharset == NULL) {
conv = NULL;
map_len = st.st_size;
else
map_len = -1;
- if (map_len > 0)
+ if (map_len > 0) {
+#ifdef G_OS_WIN32
+ cache_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail;
+ cache_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail:
+ ;
+#else
cache_data = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
+#endif
+ }
} else {
cache_data = NULL;
}
if(msginfo->msgid)
g_hash_table_insert(cache->msgid_table, msginfo->msgid, msginfo);
}
-
+
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+#else
munmap(cache_data, map_len);
+#endif
} else {
while (fread(&num, sizeof(num), 1, fp) == 1) {
if (swapping)
map_len = st.st_size;
else
map_len = -1;
- if (map_len > 0)
+ if (map_len > 0) {
+#ifdef G_OS_WIN32
+ cache_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail2;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail2;
+ cache_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail2:
+ ;
+#else
cache_data = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
+#endif
+ }
} else {
cache_data = NULL;
}
msginfo->flags.perm_flags = perm_flags;
}
}
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+#else
munmap(cache_data, map_len);
+#endif
} else {
while (fread(&num, sizeof(num), 1, fp) == 1) {
if (swapping)
fclose(fp);
}
+void msgcache_read_tags(MsgCache *cache, const gchar *tags_file)
+{
+ FILE *fp;
+ MsgInfo *msginfo;
+ guint32 num;
+ gint map_len = -1;
+ char *cache_data = NULL;
+ struct stat st;
+
+ swapping = TRUE;
+
+ /* In case we can't open the mark file with MARK_VERSION, check if we can open it with the
+ * swapped MARK_VERSION. As msgcache_open_data_file swaps it too, if this succeeds,
+ * it means it's the old version (not little-endian) on a big-endian machine. The code has
+ * no effect on x86 as their file doesn't change. */
+
+ if ((fp = msgcache_open_data_file(tags_file, TAGS_VERSION, DATA_READ, NULL, 0)) == NULL) {
+ /* see if it isn't swapped ? */
+ if ((fp = msgcache_open_data_file(tags_file, bswap_32(TAGS_VERSION), DATA_READ, NULL, 0)) == NULL)
+ return;
+ else
+ swapping = FALSE; /* yay */
+ }
+ debug_print("reading %sswapped tags file.\n", swapping?"":"un");
+
+ if (msgcache_use_mmap_read) {
+ if (fstat(fileno(fp), &st) >= 0)
+ map_len = st.st_size;
+ else
+ map_len = -1;
+ if (map_len > 0) {
+#ifdef G_OS_WIN32
+ cache_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail6;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail6;
+ cache_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail6:
+ ;
+#else
+ cache_data = mmap(NULL, map_len, PROT_READ, MAP_PRIVATE, fileno(fp), 0);
+#endif
+ }
+ } else {
+ cache_data = NULL;
+ }
+ if (cache_data != NULL && cache_data != MAP_FAILED) {
+ int rem_len = map_len-ftell(fp);
+ char *walk_data = cache_data+ftell(fp);
+
+ while(rem_len > 0) {
+ gint id = -1;
+ GET_CACHE_DATA_INT(num);
+ msginfo = g_hash_table_lookup(cache->msgnum_table, &num);
+ if(msginfo) {
+ g_slist_free(msginfo->tags);
+ msginfo->tags = NULL;
+ do {
+ GET_CACHE_DATA_INT(id);
+ if (id > 0) {
+ msginfo->tags = g_slist_prepend(
+ msginfo->tags,
+ GINT_TO_POINTER(id));
+ }
+ } while (id > 0);
+ msginfo->tags = g_slist_reverse(msginfo->tags);
+ }
+ }
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+#else
+ munmap(cache_data, map_len);
+#endif
+ } else {
+ while (fread(&num, sizeof(num), 1, fp) == 1) {
+ gint id = -1;
+ if (swapping)
+ num = bswap_32(num);
+ msginfo = g_hash_table_lookup(cache->msgnum_table, &num);
+ if(msginfo) {
+ g_slist_free(msginfo->tags);
+ msginfo->tags = NULL;
+ do {
+ if (fread(&id, sizeof(id), 1, fp) != 1)
+ id = -1;
+ if (swapping)
+ id = bswap_32(id);
+ if (id > 0) {
+ msginfo->tags = g_slist_prepend(
+ msginfo->tags,
+ GINT_TO_POINTER(id));
+ }
+ } while (id > 0);
+ msginfo->tags = g_slist_reverse(msginfo->tags);
+ }
+ }
+ }
+ fclose(fp);
+}
+
static int msgcache_write_cache(MsgInfo *msginfo, FILE *fp)
{
MsgTmpFlags flags = msginfo->flags.tmp_flags & MSG_CACHED_FLAG_MASK;
return w_err ? -1 : wrote;
}
+static int msgcache_write_tags(MsgInfo *msginfo, FILE *fp)
+{
+ GSList *cur = msginfo->tags;
+ int w_err = 0, wrote = 0;
+
+ WRITE_CACHE_DATA_INT(msginfo->msgnum, fp);
+ for (; cur; cur = cur->next) {
+ gint id = GPOINTER_TO_INT(cur->data);
+ if (tags_get_tag(id) != NULL) {
+ WRITE_CACHE_DATA_INT(id, fp);
+ }
+ }
+ WRITE_CACHE_DATA_INT(-1, fp);
+
+ return w_err ? -1 : wrote;
+}
+
static int msgcache_write_mmap_flags(MsgInfo *msginfo, char *walk_data)
{
MsgPermFlags flags = msginfo->flags.perm_flags;
return wrote;
}
+static int msgcache_write_mmap_tags(MsgInfo *msginfo, char *walk_data)
+{
+ GSList *cur = msginfo->tags;
+ int wrote = 0;
+
+ PUT_CACHE_DATA_INT(msginfo->msgnum);
+ for (; cur; cur = cur->next) {
+ gint id = GPOINTER_TO_INT(cur->data);
+ if (tags_get_tag(id) != NULL) {
+ PUT_CACHE_DATA_INT(id);
+ }
+ }
+ PUT_CACHE_DATA_INT(-1);
+ return wrote;
+}
+
struct write_fps
{
FILE *cache_fp;
FILE *mark_fp;
+ FILE *tags_fp;
char *cache_data;
char *mark_data;
+ char *tags_data;
int error;
guint cache_size;
guint mark_size;
+ guint tags_size;
};
static void msgcache_write_func(gpointer key, gpointer value, gpointer user_data)
write_fps->error = 1;
else
write_fps->mark_size += tmp;
+ tmp = msgcache_write_tags(msginfo, write_fps->tags_fp);
+ if (tmp < 0)
+ write_fps->error = 1;
+ else
+ write_fps->tags_size += tmp;
}
static void msgcache_write_mmap_func(gpointer key, gpointer value, gpointer user_data)
tmp = msgcache_write_mmap_flags(msginfo, write_fps->mark_data);
write_fps->mark_size += tmp;
write_fps->mark_data += tmp;
+ tmp = msgcache_write_mmap_tags(msginfo, write_fps->tags_data);
+ write_fps->tags_size += tmp;
+ write_fps->tags_data += tmp;
}
-gint msgcache_write(const gchar *cache_file, const gchar *mark_file, MsgCache *cache)
+gint msgcache_write(const gchar *cache_file, const gchar *mark_file, const gchar *tags_file, MsgCache *cache)
{
struct write_fps write_fps;
- gchar *new_cache, *new_mark;
+ gchar *new_cache, *new_mark, *new_tags;
int w_err = 0, wrote = 0;
gint map_len = -1;
char *cache_data = NULL;
char *mark_data = NULL;
+ char *tags_data = NULL;
+
START_TIMING("");
g_return_val_if_fail(cache_file != NULL, -1);
g_return_val_if_fail(mark_file != NULL, -1);
+ g_return_val_if_fail(tags_file != NULL, -1);
g_return_val_if_fail(cache != NULL, -1);
new_cache = g_strconcat(cache_file, ".new", NULL);
new_mark = g_strconcat(mark_file, ".new", NULL);
+ new_tags = g_strconcat(tags_file, ".new", NULL);
write_fps.error = 0;
write_fps.cache_size = 0;
write_fps.mark_size = 0;
+ write_fps.tags_size = 0;
+
write_fps.cache_fp = msgcache_open_data_file(new_cache, CACHE_VERSION,
DATA_WRITE, NULL, 0);
if (write_fps.cache_fp == NULL) {
g_free(new_cache);
g_free(new_mark);
+ g_free(new_tags);
return -1;
}
g_unlink(new_cache);
g_free(new_cache);
g_free(new_mark);
+ g_free(new_tags);
return -1;
}
g_unlink(new_cache);
g_free(new_cache);
g_free(new_mark);
+ g_free(new_tags);
+ return -1;
+ }
+
+ write_fps.tags_fp = msgcache_open_data_file(new_tags, TAGS_VERSION,
+ DATA_WRITE, NULL, 0);
+ if (write_fps.tags_fp == NULL) {
+ fclose(write_fps.cache_fp);
+ fclose(write_fps.mark_fp);
+ g_unlink(new_cache);
+ g_unlink(new_mark);
+ g_free(new_cache);
+ g_free(new_mark);
+ g_free(new_tags);
return -1;
}
write_fps.cache_size = ftell(write_fps.cache_fp);
write_fps.mark_size = ftell(write_fps.mark_fp);
+ write_fps.tags_size = ftell(write_fps.tags_fp);
+
if (msgcache_use_mmap_write && cache->memusage > 0) {
map_len = cache->memusage;
if (ftruncate(fileno(write_fps.cache_fp), (off_t)map_len) == 0) {
+
+#ifdef G_OS_WIN32
+ cache_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(write_fps.cache_fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail3;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail3;
+ cache_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail3:
+ ;
+#else
cache_data = mmap(NULL, map_len, PROT_WRITE, MAP_SHARED,
fileno(write_fps.cache_fp), 0);
+#endif
}
if (cache_data != NULL && cache_data != MAP_FAILED) {
if (ftruncate(fileno(write_fps.mark_fp), (off_t)map_len) == 0) {
+#ifdef G_OS_WIN32
+ mark_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(write_fps.mark_fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail4;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail4;
+ mark_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail4:
+ ;
+#else
mark_data = mmap(NULL, map_len, PROT_WRITE, MAP_SHARED,
fileno(write_fps.mark_fp), 0);
+#endif
}
if (mark_data == NULL || mark_data == MAP_FAILED) {
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+#else
munmap(cache_data, map_len);
+#endif
cache_data = NULL;
+ } else {
+ if (ftruncate(fileno(write_fps.tags_fp), (off_t)map_len) == 0) {
+#ifdef G_OS_WIN32
+ tags_data = NULL;
+ HANDLE hFile, hMapping;
+ hFile = (HANDLE) _get_osfhandle (fileno(write_fps.tags_fp));
+ if (hFile == (HANDLE) -1)
+ goto w32_fail5;
+ hMapping = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 0, NULL);
+ if (!hMapping)
+ goto w32_fail5;
+ tags_data = (unsigned char *)MapViewOfFile(hMapping, FILE_MAP_COPY, 0, 0, 0);
+ w32_fail5:
+ ;
+#else
+ tags_data = mmap(NULL, map_len, PROT_WRITE, MAP_SHARED,
+ fileno(write_fps.tags_fp), 0);
+#endif
+ }
+ if (tags_data == NULL || tags_data == MAP_FAILED) {
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+ UnmapViewOfFile((void*) mark_data);
+#else
+ munmap(cache_data, map_len);
+ munmap(mark_data, map_len);
+#endif
+ cache_data = NULL;
+ mark_data = NULL;
+ }
}
}
}
if (cache_data != NULL && cache_data != MAP_FAILED) {
write_fps.cache_data = cache_data + ftell(write_fps.cache_fp);
write_fps.mark_data = mark_data + ftell(write_fps.mark_fp);
+ write_fps.tags_data = mark_data + ftell(write_fps.tags_fp);
g_hash_table_foreach(cache->msgnum_table, msgcache_write_mmap_func, (gpointer)&write_fps);
+#ifdef G_OS_WIN32
+ UnmapViewOfFile((void*) cache_data);
+ UnmapViewOfFile((void*) mark_data);
+ UnmapViewOfFile((void*) tags_data);
+#else
munmap(cache_data, map_len);
munmap(mark_data, map_len);
+ munmap(tags_data, map_len);
+#endif
ftruncate(fileno(write_fps.cache_fp), write_fps.cache_size);
ftruncate(fileno(write_fps.mark_fp), write_fps.mark_size);
+ ftruncate(fileno(write_fps.tags_fp), write_fps.tags_size);
} else {
#ifdef HAVE_FWRITE_UNLOCKED
flockfile(write_fps.cache_fp);
flockfile(write_fps.mark_fp);
+ flockfile(write_fps.tags_fp);
#endif
g_hash_table_foreach(cache->msgnum_table, msgcache_write_func, (gpointer)&write_fps);
#ifdef HAVE_FWRITE_UNLOCKED
funlockfile(write_fps.mark_fp);
funlockfile(write_fps.cache_fp);
+ funlockfile(write_fps.tags_fp);
#endif
}
fflush(write_fps.cache_fp);
fflush(write_fps.mark_fp);
+ fflush(write_fps.tags_fp);
#if 0
fsync(fileno(write_fps.cache_fp));
fsync(fileno(write_fps.mark_fp));
+ fsync(fileno(write_fps.tags_fp));
#endif
fclose(write_fps.cache_fp);
fclose(write_fps.mark_fp);
+ fclose(write_fps.tags_fp);
if (write_fps.error != 0) {
g_unlink(new_cache);
g_unlink(new_mark);
+ g_unlink(new_tags);
g_free(new_cache);
g_free(new_mark);
+ g_free(new_tags);
return -1;
} else {
move_file(new_cache, cache_file, TRUE);
move_file(new_mark, mark_file, TRUE);
+ move_file(new_tags, tags_file, TRUE);
cache->last_access = time(NULL);
}
g_free(new_cache);
g_free(new_mark);
+ g_free(new_tags);
debug_print("done.\n");
END_TIMING();
return 0;