dbox-file.c revision bbef9a6fc46440df829571756a7b75a95aba9d36
/* Copyright (c) 2007-2009 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "ioloop.h"
#include "array.h"
#include "hex-dec.h"
#include "hex-binary.h"
#include "hostpid.h"
#include "istream.h"
#include "ostream.h"
#include "file-lock.h"
#include "mkdir-parents.h"
#include "fdatasync-path.h"
#include "eacces-error.h"
#include "str.h"
#include "dbox-storage.h"
#include "dbox-file.h"
#include "dbox-file-maildir.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <ctype.h>
#include <fcntl.h>
#define DBOX_READ_BLOCK_SIZE 4096
char *dbox_generate_tmp_filename(void)
{
static unsigned int create_count = 0;
return i_strdup_printf("temp.%lu.P%sQ%uM%u.%s",
create_count++,
(unsigned int)ioloop_timeval.tv_usec,
}
{
"%s failed for file %s: %m",
}
{
}
static struct dbox_file *
{
unsigned int i, count;
for (i = 0; i < count; i++) {
/* move to last in the array */
return file;
}
}
return NULL;
}
{
}
{
unsigned int i, count;
for (i = 0; i < count; i++)
dbox_file_free(files[i]);
}
{
unsigned int i, count;
for (i = 0; i < count; i++) {
}
}
static void
{
unsigned int i, count;
for (i = 0; i < count;) {
dbox_file_free(files[i]);
if (--close_count == 0)
break;
} else {
i++;
}
}
}
static char *
bool *maildir_file_r)
{
const char *fname;
*maildir_file_r = TRUE;
} else {
*maildir_file_r = FALSE;
}
}
{
const char *dir;
}
{
const char *dir;
}
struct dbox_file *
{
bool maildir;
if (uid != 0) {
} else {
}
return file;
}
struct dbox_file *
{
unsigned int count;
return file;
}
}
file->current_path =
if (file_id != 0)
return file;
}
{
const char *old_path;
bool maildir;
} else {
}
"rename(%s, %s) failed: %m",
return -1;
}
else {
}
return 0;
}
{
unsigned int i, count;
return;
/* don't cache metadata seeks while file isn't being referenced */
/* we can leave this file open for now */
return;
}
/* close the oldest file with refcount=0 */
for (i = 0; i < count; i++) {
break;
}
oldest_file = files[i];
if (oldest_file != file) {
return;
}
/* have to close ourself */
}
}
{
unsigned int pos;
enum dbox_header_key key;
return -1;
}
line += 2;
pos = 2;
file->msg_header_size = 0;
switch (key) {
break;
break;
case DBOX_HEADER_CREATE_STAMP:
break;
}
}
if (file->msg_header_size == 0) {
return -1;
}
return 0;
}
{
const char *line;
unsigned int hdr_size;
int ret;
"EOF while reading file header");
return 0;
}
return -1;
}
T_BEGIN {
} T_END;
if (ret > 0)
return ret;
}
{
const char *path;
/* try the primary path first */
"open(%s) failed: %m", path);
return -1;
}
/* not found */
return 0;
}
/* try the alternative path */
}
return 1;
}
{
int ret;
return 1;
T_BEGIN {
} T_END;
if (ret <= 0) {
if (ret < 0)
return -1;
return 1;
}
}
}
{
int fd;
if (fd == -1) {
"open(%s, O_CREAT) failed: %m", path);
/* no group change */
} else {
"fchown(%s, -1, %ld) failed: %m",
}
/* continue anyway */
}
return fd;
}
{
(unsigned int)sizeof(struct dbox_message_header),
DBOX_HEADER_CREATE_STAMP, (unsigned int)ioloop_time);
}
{
return -1;
return -1;
}
return 0;
}
{
int ret;
T_BEGIN {
} T_END;
return ret;
return 1;
else
}
{
}
}
{
int ret;
if (ret < 0) {
}
return ret;
}
{
i_fatal("dbox file modified while locked");
}
}
}
{
struct dbox_message_header hdr;
const unsigned char *data;
int ret;
if (file->maildir_file) {
return -1;
}
return 1;
}
if (ret <= 0) {
/* EOF, broken offset or file truncated */
return 0;
}
return -1;
}
/* probably broken offset */
return 0;
}
return 0;
}
sizeof(hdr.message_size_hex));
return 1;
}
{
int ret;
*expunged_r = FALSE;
return ret;
}
if (offset == 0)
if (ret <= 0)
return ret;
}
}
return 1;
}
static int
{
const char *line;
int ret;
return ret;
/* skip over the actual metadata */
/* end of metadata */
break;
}
}
return 1;
}
{
}
{
bool expunged;
int ret;
/* first mail. we may not have read the file at all yet,
so set the offset afterwards. */
offset = 0;
} else {
return ret;
}
}
return 0;
}
if (*offset_r == 0)
return ret;
}
static int
{
/* created by an incompatible version, can't append */
return 0;
}
return -1;
}
return 1;
}
{
int ret;
/* creating a new file */
if (dbox_file_create(file) < 0)
return -1;
/* creating a new multi-file. even though we don't
need it locked while writing to it, by the time
we rename() it it needs to be locked. so we might
as well do it here. */
if (ret < 0)
return -1;
"dbox: Couldn't lock created file: %s",
file->current_path);
return -1;
}
}
if (ret <= 0)
return ret;
}
return 1;
}
{
}
{
}
}
{
return -1;
}
return -1;
}
}
return 0;
}
{
struct dbox_metadata_header metadata_hdr;
const unsigned char *data;
int ret;
sizeof(metadata_hdr) - 1);
if (ret <= 0) {
/* EOF, broken offset */
"Unexpected EOF while reading metadata header");
return 0;
}
return -1;
}
sizeof(metadata_hdr.magic_post)) != 0) {
/* probably broken offset */
"metadata header has bad magic value");
return 0;
}
return 1;
}
static int
{
const char *line;
int ret;
else {
}
return ret;
ret = 0;
/* end of metadata */
ret = 1;
break;
}
}
if (ret == 0)
return ret;
}
{
int ret;
return 1;
if (ret <= 0)
return ret;
return 1;
}
enum dbox_metadata_key key)
{
const char *const *metadata;
unsigned int i, count;
if (file->maildir_file)
for (i = 0; i < count; i++) {
return metadata[i] + 1;
}
return NULL;
}
{
bool deleted;
return 0;
return 0;
}
/* first copy the file. make sure to catch every possible error
since we really don't want to break the file. */
"mkdir_parents(%s) failed: %m", dest_dir);
return -1;
}
}
if (out_fd == -1) {
"open(%s, O_CREAT) failed: %m", temp_path);
return -1;
}
if (ret == 0)
if (output->stream_errno != 0) {
"write(%s) failed: %m", temp_path);
ret = -1;
ret = -1;
} else if (ret < 0) {
"o_stream_send_istream(%s, %s) "
"failed with unknown error",
}
"fsync(%s) failed: %m", temp_path);
ret = -1;
}
}
"close(%s) failed: %m", temp_path);
ret = -1;
}
if (ret < 0) {
return -1;
}
/* the temp file was successfully written. rename it now to the
destination file. the destination shouldn't exist, but if it does
its contents should be the same (except for maybe older metadata) */
return -1;
}
if (fdatasync_path(dest_dir) < 0) {
"fdatasync(%s) failed: %m", dest_dir);
return -1;
}
}
/* configuration problem? revert the write */
}
/* who knows what happened to the file. keep both just to be
sure both won't get deleted. */
return -1;
}
/* file was successfully moved - reopen it */
"dbox_file_move(%s): reopening file failed", dest_path);
return -1;
}
return 0;
}
{
sizeof(dbox_msg_hdr->magic_pre));
sizeof(dbox_msg_hdr->message_size_hex));
}