<commit_before>/* Copyright (C) 2003-2004 <NAME> */

/*
   Locking should never fail or timeout. Exclusive locks must be kept as short
   time as possible. Shared locks can be long living, so if we can't get
   exclusive lock directly within 2 seconds, we'll replace the index file with
   a copy of it. That means the shared lock holders can keep using the old file
   while we're modifying the new file.

   lock_id is used to figure out if acquired lock is still valid. When index
   file is reopened, the lock_id can become invalid. It doesn't matter however,
   as no-one's going to modify the old file anymore.

   lock_id also tells if we're referring to shared or exclusive lock. This
   allows us to drop back to shared locking once all exclusive locks are
   dropped. Shared locks have even numbers, exclusive locks have odd numbers.
   The number is increased by two every time the lock is dropped or index file
   is reopened.
*/

#include "lib.h"
#include "mmap-util.h"
#include "file-lock.h"
#include "write-full.h"
#include "mail-index-private.h"

#include <stdio.h>
#include <sys/stat.h>

int mail_index_map_lock_mprotect(struct mail_index *index,
				 struct mail_index_map *map, int lock_type)
{
	int prot;

	if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
		i_assert(map->mmap_size != 0);
		prot = lock_type == F_UNLCK ? PROT_NONE :
			lock_type == F_WRLCK ? (PROT_READ|PROT_WRITE) :
			PROT_READ;
		if (mprotect(map->mmap_base, map->mmap_size, prot) < 0) {
			mail_index_set_syscall_error(index, "mprotect()");
			return -1;
		}
	}
	return 0;
}

static int mail_index_lock_mprotect(struct mail_index *index, int lock_type)
{
	if (index->map == NULL)
		return 0;

	return mail_index_map_lock_mprotect(index, index->map, lock_type);
}

static int mail_index_lock(struct mail_index *index, int lock_type,
			   unsigned int timeout_secs, int update_index,
			   unsigned int *lock_id_r)
{
	int ret, ret2;

	i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);

	if (lock_type == F_RDLCK && index->lock_type != F_UNLCK) {
		index->shared_lock_count++;
		*lock_id_r = index->lock_id;
		ret = 1;
	} else if (lock_type == F_WRLCK && index->lock_type == F_WRLCK) {
		index->excl_lock_count++;
		*lock_id_r = index->lock_id + 1;
		ret = 1;
	} else {
		ret = 0;
	}

	if (update_index && index->excl_lock_count == 0) {
		if ((ret2 = mail_index_refresh(index)) < 0)
			return -1;
		if (ret > 0 && ret2 == 0)
			return 1;
		ret = 0;
	}

	if (ret > 0)
		return 1;

	if (index->fcntl_locks_disable) {
		/* FIXME: exclusive locking will rewrite the index file every
		   time. shouldn't really be needed.. reading doesn't require
		   locks then, though */
		if (lock_type == F_WRLCK)
			return 0;
		if (update_index && index->lock_type == F_UNLCK) {
			if (mail_index_refresh(index) < 0)
				return -1;
		}
		if (mail_index_lock_mprotect(index, lock_type) < 0)
			return -1;
<commit_msg>mprotect() wasn't always called when index was being locked, and caused crashes.<commit_after>/* Copyright (C) 2003-2004 <NAME> */

/*
   Locking should never fail or timeout. Exclusive locks must be kept as short
   time as possible. Shared locks can be long living, so if we can't get
   exclusive lock directly within 2 seconds, we'll replace the index file with
   a copy of it. That means the shared lock holders can keep using the old file
   while we're modifying the new file.

   lock_id is used to figure out if acquired lock is still valid. When index
   file is reopened, the lock_id can become invalid. It doesn't matter however,
   as no-one's going to modify the old file anymore.

   lock_id also tells if we're referring to shared or exclusive lock. This
   allows us to drop back to shared locking once all exclusive locks are
   dropped. Shared locks have even numbers, exclusive locks have odd numbers.
   The number is increased by two every time the lock is dropped or index file
   is reopened.
*/

#include "lib.h"
#include "mmap-util.h"
#include "file-lock.h"
#include "write-full.h"
#include "mail-index-private.h"

#include <stdio.h>
#include <sys/stat.h>

int mail_index_map_lock_mprotect(struct mail_index *index,
				 struct mail_index_map *map, int lock_type)
{
	int prot;

	if (!MAIL_INDEX_MAP_IS_IN_MEMORY(map)) {
		i_assert(map->mmap_size != 0);
		prot = lock_type == F_UNLCK ? PROT_NONE :
			lock_type == F_WRLCK ? (PROT_READ|PROT_WRITE) :
			PROT_READ;
		if (mprotect(map->mmap_base, map->mmap_size, prot) < 0) {
			mail_index_set_syscall_error(index, "mprotect()");
			return -1;
		}
	}
	return 0;
}

static int mail_index_lock_mprotect(struct mail_index *index, int lock_type)
{
	if (index->map == NULL)
		return 0;

	return mail_index_map_lock_mprotect(index, index->map, lock_type);
}

static int mail_index_lock(struct mail_index *index, int lock_type,
			   unsigned int timeout_secs, int update_index,
			   unsigned int *lock_id_r)
{
	int ret, ret2;

	i_assert(lock_type == F_RDLCK || lock_type == F_WRLCK);

	if (lock_type == F_RDLCK && index->lock_type != F_UNLCK) {
		index->shared_lock_count++;
		*lock_id_r = index->lock_id;
		ret = 1;
	} else if (lock_type == F_WRLCK && index->lock_type == F_WRLCK) {
		index->excl_lock_count++;
		*lock_id_r = index->lock_id + 1;
		ret = 1;
	} else {
		ret = 0;
	}

	if (update_index && index->excl_lock_count == 0) {
		if ((ret2 = mail_index_refresh(index)) < 0)
			return -1;
		if (ret > 0 && ret2 == 0) {
			if (mail_index_lock_mprotect(index, lock_type) < 0)
				return -1;
			return 1;
		}
		ret = 0;
	}

	if (ret > 0)
		return 1;

	if (index->fcntl_locks_disable) {
		/* FIXME: exclusive locking will rewrite the index file every
		   time. shouldn't really be needed.. reading doesn't require
		   locks then, though */
		if (lock_type == F_WRLCK)
			return 0;
		if (update_index && index->lock_type == F_UNLCK) {
			if (mail_index_refresh(index) < 0)
				return -1;
		}
		if (mail_index_lock_mprotect(index, lock_type) < 0)
			return -1;

{'fraction_non_alphanumeric': 0.10593005575266093, 'fraction_numerical': 0.012164216928535226, 'mean_word_length': 3.668769716088328, 'pattern_counts': {'":': 0, '<': 18, '<?xml version=': 0, '>': 41, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3199443', 'n_tokens_mistral': 2317, 'n_tokens_neox': 2069, 'n_words': 679}