Ejemplo n.º 1
0
static void
mail_transaction_log_mark_corrupted(struct mail_transaction_log_file *file)
{
	unsigned int offset =
		offsetof(struct mail_transaction_log_header, indexid);
	int flags;

	if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(file) ||
	    file->log->index->readonly)
		return;

	/* indexid=0 marks the log file as corrupted. we opened the file with
	   O_APPEND, and now we need to drop it for pwrite() to work (at least
	   in Linux) */
	flags = fcntl(file->fd, F_GETFL, 0);
	if (flags < 0) {
		mail_index_file_set_syscall_error(file->log->index,
			file->filepath, "fcntl(F_GETFL)");
		return;
	}
	if (fcntl(file->fd, F_SETFL, flags & ~O_APPEND) < 0) {
		mail_index_file_set_syscall_error(file->log->index,
			file->filepath, "fcntl(F_SETFL)");
		return;
	}
	if (pwrite_full(file->fd, &file->hdr.indexid,
			sizeof(file->hdr.indexid), offset) < 0) {
		mail_index_file_set_syscall_error(file->log->index,
						  file->filepath, "pwrite()");
	}
}
Ejemplo n.º 2
0
static int mail_index_recreate(struct mail_index *index)
{
	struct mail_index_map *map = index->map;
	struct ostream *output;
	unsigned int base_size;
	const char *path;
	int ret = 0, fd;

	i_assert(!MAIL_INDEX_IS_IN_MEMORY(index));
	i_assert(map->hdr.indexid == index->indexid);
	i_assert((map->hdr.flags & MAIL_INDEX_HDR_FLAG_CORRUPTED) == 0);
	i_assert(index->indexid != 0);

	fd = mail_index_create_tmp_file(index, index->filepath, &path);
	if (fd == -1)
		return -1;

	output = o_stream_create_fd_file(fd, 0, FALSE);
	o_stream_cork(output);

	base_size = I_MIN(map->hdr.base_header_size, sizeof(map->hdr));
	o_stream_nsend(output, &map->hdr, base_size);
	o_stream_nsend(output, CONST_PTR_OFFSET(map->hdr_base, base_size),
		       map->hdr.header_size - base_size);
	o_stream_nsend(output, map->rec_map->records,
		       map->rec_map->records_count * map->hdr.record_size);
	o_stream_nflush(output);
	if (o_stream_nfinish(output) < 0) {
		mail_index_file_set_syscall_error(index, path, "write()");
		ret = -1;
	}
	o_stream_destroy(&output);

	if (ret == 0 && index->fsync_mode != FSYNC_MODE_NEVER) {
		if (fdatasync(fd) < 0) {
			mail_index_file_set_syscall_error(index, path,
							  "fdatasync()");
			ret = -1;
		}
	}

	if (close(fd) < 0) {
		mail_index_file_set_syscall_error(index, path, "close()");
		ret = -1;
	}

	if ((index->flags & MAIL_INDEX_OPEN_FLAG_KEEP_BACKUPS) != 0)
		(void)mail_index_create_backup(index);

	if (ret == 0 && rename(path, index->filepath) < 0) {
		mail_index_set_error(index, "rename(%s, %s) failed: %m",
				     path, index->filepath);
		ret = -1;
	}

	if (ret < 0)
		i_unlink(path);
	return ret;
}
Ejemplo n.º 3
0
static int
mail_transaction_log_refresh(struct mail_transaction_log *log, bool nfs_flush)
{
        struct mail_transaction_log_file *file;
	struct stat st;

	i_assert(log->head != NULL);

	if (MAIL_TRANSACTION_LOG_FILE_IN_MEMORY(log->head))
		return 0;

	if (nfs_flush && log->nfs_flush)
		nfs_flush_file_handle_cache(log->filepath);
	if (nfs_safe_stat(log->filepath, &st) < 0) {
		if (errno != ENOENT) {
			mail_index_file_set_syscall_error(log->index,
							  log->filepath,
							  "stat()");
			return -1;
		}
		/* see if the whole directory got deleted */
		if (nfs_safe_stat(log->index->dir, &st) < 0 &&
		    errno == ENOENT) {
			log->index->index_deleted = TRUE;
			return -1;
		}

		/* the file should always exist at this point. if it doesn't,
		   someone deleted it manually while the index was open. try to
		   handle this nicely by creating a new log file. */
		file = log->head;
		if (mail_transaction_log_create(log, FALSE) < 0)
			return -1;
		i_assert(file->refcount > 0);
		file->refcount--;
		log->index->need_recreate = TRUE;
		return 0;
	} else if (log->head->st_ino == st.st_ino &&
		   CMP_DEV_T(log->head->st_dev, st.st_dev)) {
		/* NFS: log files get rotated to .log.2 files instead
		   of being unlinked, so we don't bother checking if
		   the existing file has already been unlinked here
		   (in which case inodes could match but point to
		   different files) */
		return 0;
	}

	file = mail_transaction_log_file_alloc(log, log->filepath);
	if (mail_transaction_log_file_open(file, FALSE) <= 0) {
		mail_transaction_log_file_free(&file);
		return -1;
	}

	i_assert(!file->locked);

	if (--log->head->refcount == 0)
		mail_transaction_logs_clean(log);
	mail_transaction_log_set_head(log, file);
	return 0;
}
Ejemplo n.º 4
0
static void
log_file_set_syscall_error(struct mail_transaction_log_file *file,
			   const char *function)
{
	mail_index_file_set_syscall_error(file->log->index,
					  file->filepath, function);
}
Ejemplo n.º 5
0
int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
{
	struct mail_transaction_log_file *file;
	const char *path = log->head->filepath;
	struct stat st;
	int ret;

	i_assert(log->head->locked);

	if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
		file = mail_transaction_log_file_alloc_in_memory(log);
		if (reset) {
			file->hdr.prev_file_seq = 0;
			file->hdr.prev_file_offset = 0;
		}
	} else {
                /* we're locked, we shouldn't need to worry about ESTALE
                   problems in here. */
		if (fstat(log->head->fd, &st) < 0) {
			mail_index_file_set_syscall_error(log->index,
				log->head->filepath, "fstat()");
			return -1;
		}

		file = mail_transaction_log_file_alloc(log, path);

		file->st_dev = st.st_dev;
		file->st_ino = st.st_ino;
		file->last_mtime = st.st_mtime;
		file->last_size = st.st_size;

		if ((ret = mail_transaction_log_file_create(file, reset)) < 0) {
			mail_transaction_log_file_free(&file);
			return -1;
		}
		if (ret == 0) {
			mail_index_set_error(log->index,
				"Transaction log %s was recreated while we had it locked - "
				"locking is broken (lock_method=%s)", path,
				file_lock_method_to_str(log->index->lock_method));
			mail_transaction_log_file_free(&file);
			return -1;
		}
		i_assert(file->locked);
	}

	if (--log->head->refcount == 0)
		mail_transaction_logs_clean(log);
	else {
		/* the newly created log file is already locked */
		mail_transaction_log_file_unlock(log->head,
			!log->index->log_sync_locked ? "rotating" :
			"rotating while syncing");
	}
	mail_transaction_log_set_head(log, file);
	return 0;
}
Ejemplo n.º 6
0
int mail_transaction_log_unlink(struct mail_transaction_log *log)
{
	if (unlink(log->filepath) < 0 &&
	    errno != ENOENT && errno != ESTALE) {
		mail_index_file_set_syscall_error(log->index, log->filepath,
						  "unlink()");
		return -1;
	}
	return 0;
}
Ejemplo n.º 7
0
int mail_transaction_log_get_mtime(struct mail_transaction_log *log,
				   time_t *mtime_r)
{
	struct stat st;

	*mtime_r = 0;
	if (stat(log->filepath, &st) < 0) {
		if (errno == ENOENT)
			return 0;

		mail_index_file_set_syscall_error(log->index, log->filepath,
						  "stat()");
		return -1;
	}
	*mtime_r = st.st_mtime;
	return 0;
}
Ejemplo n.º 8
0
int mail_transaction_log_rotate(struct mail_transaction_log *log, bool reset)
{
	struct mail_transaction_log_file *file;
	const char *path = log->head->filepath;
	struct stat st;

	i_assert(log->head->locked);

	if (MAIL_INDEX_IS_IN_MEMORY(log->index)) {
		file = mail_transaction_log_file_alloc_in_memory(log);
		if (reset) {
			file->hdr.prev_file_seq = 0;
			file->hdr.prev_file_offset = 0;
		}
	} else {
                /* we're locked, we shouldn't need to worry about ESTALE
                   problems in here. */
		if (fstat(log->head->fd, &st) < 0) {
			mail_index_file_set_syscall_error(log->index,
				log->head->filepath, "fstat()");
			return -1;
		}

		file = mail_transaction_log_file_alloc(log, path);

		file->st_dev = st.st_dev;
		file->st_ino = st.st_ino;
		file->last_mtime = st.st_mtime;
		file->last_size = st.st_size;

		if (mail_transaction_log_file_create(file, reset) < 0) {
			mail_transaction_log_file_free(&file);
			return -1;
		}
	}

	if (--log->head->refcount == 0)
		mail_transaction_logs_clean(log);
	else
		mail_transaction_log_file_unlock(log->head);
	mail_transaction_log_set_head(log, file);
	return 0;
}