<commit_before>/*
 * Parcelkeeper - support daemon for the OpenISR (R) system virtual disk
 *
 * Copyright (C) 2006-2007 Carnegie Mellon University
 *
 * This software is distributed under the terms of the Eclipse Public License,
 * Version 1.0 which can be found in the file named LICENSE.Eclipse.  ANY USE,
 * REPRODUCTION OR DISTRIBUTION OF THIS SOFTWARE CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THIS AGREEMENT
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include "defs.h"

#define CA_MAGIC 0x51528038
#define CA_VERSION 1
#define CA_INDEX_VERSION 1

/* All u32's in network byte order */
struct ca_header {
	uint32_t magic;
	uint32_t entries;
	uint32_t offset;  /* beginning of data, in 512-byte blocks */
	uint32_t flags;
	uint32_t reserved_1;
	uint8_t version;
	uint8_t reserved_2[491];
};

enum shm_chunk_status {
	SHM_NOT_PRESENT,
	SHM_PRESENT,
	SHM_ACCESSED,
	SHM_DIRTY
};

off64_t cache_chunk_to_offset(unsigned chunk)
{
	return (off64_t)parcel.chunksize * chunk + state.offset;
}

static pk_err_t create_cache_file(long page_size)
{
	struct ca_header hdr = {0};
	int fd;

	fd=open(config.cache_file, O_CREAT|O_EXCL|O_RDWR, 0600);
	if (fd == -1) {
		pk_log(LOG_ERROR, "couldn't create cache file");
		return PK_IOERR;
	}
	/* There's a race condition in the way the loop driver
	   interacts with the memory management system for (at least)
	   underlying file systems that provide the prepare_write and
	   commit_write address space operations.  This can cause data
	   not to be properly written to disk if I/O submitted to the
	   loop driver spans multiple page-cache pages and is not
	   aligned on page cache boundaries.  We therefore need to
	   make sure that our header is a multiple of the page size.
	   We assume that the page size is at least sizeof(hdr) bytes. */
	state.offset=page_size;
	state.cache_flags=0;
	hdr.magic=htonl(CA_MAGIC);
	hdr.entries=htonl(parcel.chunks);
	hdr.offset=htonl(state.offset >> 9);
	hdr.flags=htonl(state.cache_flags);
	hdr.version=CA_VERSION;
	if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
		pk_log(LOG_ERROR, "Couldn't write cache file header");
		return PK_IOERR;
	}
	if (ftruncate(fd, cache_chunk_to_offset(parcel.chunks))) {
		pk_log(LOG_ERROR, "couldn't extend cache file");
		return PK_IOERR;
	}

	pk_log(LOG_INFO, "Created cache file");
	state.cache_fd=fd;
	return PK_SUCCESS;
}

static pk_err_t open_cache_file(long page_size)
{
	struct ca_header hdr;
	int fd;

	fd=open(config.cache_file, O_RDWR);
	if (fd == -1) {
		pk_log(LOG_ERROR, "couldn't open cache file");
		return PK_IOERR;
	}
	if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
		pk_log(LOG_ERROR, "Couldn't read cache file header");
		return PK_IOERR;
	}
	if (ntohl(hdr.magic) != CA_MAGIC) {
		pk_log(LOG_ERROR, "Invalid magic number reading cache file");
		return PK_BADFORMAT;
	}
	if (hdr.version != CA_VERSION) {
		pk_log(LOG_ERROR, "Invalid version reading cache file: "
					"expected %d, found %d", CA_VERSION,
					hdr.version);
		return PK_BADFORMAT;
	}
	if (ntohl(hdr.entries) != parcel.chunks) {
		pk_log(LOG_ERROR, "Invalid chunk count reading cache file: "
					"expected %u, found %u",
					parcel.chunks, ntohl(hdr.entries));
		return PK_BADFORMAT;
	}
	state.cache_flags=ntohl(hdr.flags);
	state.offset=ntohl(hdr.offset) << 9;
	if (state.offset % page_size != 0) {
		/* This may occur with old cache files, or with cache files
		   copied from another system with a different page size. */
		pk_log(LOG_ERROR, "Cache file's header length %u is not "
					"a multiple of the page size %ld",
					state.offset, page_size);
		pk_log(LOG_ERROR, "Data corruption may occur.  If it does, "
					"checkin will be disallowed");
	}

	pk_log(LOG_INFO, "Read cache header");
	state.cache_fd=fd;
	return PK_SUCCESS;
}

static pk_err_t cache_set_flags(unsigned flags)
{
	unsigned tmp;

	if (!(config.flags & WANT_LOCK)) {
		/* Catch misuse of this function */
		pk_log(LOG_ERROR, "Refusing to set cache flags when lock "
					"not held");
		return PK_BUSY;
	}
	if (!state.cache_fd) {
		pk_log(LOG_ERROR, "Cache file not open; can't set flags");
		return PK_IOERR;
	}

	tmp=htonl(flags);
	if (pwrite(state.cache_fd, &tmp, sizeof(tmp),
				offsetof(struct ca_header, flags))
				!= sizeof(tmp)) {
		pk_log(LOG_ERROR, "Couldn't write new flags to cache file");
		return PK_IOERR;
	}
	if (fdatasync(state.cache_fd)) {
		pk_log(LOG_ERROR, "Couldn't sync cache file");
		return PK_IOERR;
	}
	state.cache_flags=flags;
	return PK_SUCCESS;
}

pk_err_t cache_set_flag(unsigned flag)
{
	return cache_set_flags(state.cache_flags | flag);
}

pk_err_t cache_clear_flag(unsigned flag)
{
	return cache_set_flags(state.cache_flags & ~flag);
}

int cache_test_flag(unsigned flag)
{
	return ((state.cache_flags & flag) == flag);
}

static pk_err_t create_cache_index(void)
{
	pk_err_t ret;

again:<commit_msg>pk: Log message when setting damaged flag<commit_after>/*
 * Parcelkeeper - support daemon for the OpenISR (R) system virtual disk
 *
 * Copyright (C) 2006-2007 Carnegie Mellon University
 *
 * This software is distributed under the terms of the Eclipse Public License,
 * Version 1.0 which can be found in the file named LICENSE.Eclipse.  ANY USE,
 * REPRODUCTION OR DISTRIBUTION OF THIS SOFTWARE CONSTITUTES RECIPIENT'S
 * ACCEPTANCE OF THIS AGREEMENT
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <errno.h>
#include "defs.h"

#define CA_MAGIC 0x51528038
#define CA_VERSION 1
#define CA_INDEX_VERSION 1

/* All u32's in network byte order */
struct ca_header {
	uint32_t magic;
	uint32_t entries;
	uint32_t offset;  /* beginning of data, in 512-byte blocks */
	uint32_t flags;
	uint32_t reserved_1;
	uint8_t version;
	uint8_t reserved_2[491];
};

enum shm_chunk_status {
	SHM_NOT_PRESENT,
	SHM_PRESENT,
	SHM_ACCESSED,
	SHM_DIRTY
};

off64_t cache_chunk_to_offset(unsigned chunk)
{
	return (off64_t)parcel.chunksize * chunk + state.offset;
}

static pk_err_t create_cache_file(long page_size)
{
	struct ca_header hdr = {0};
	int fd;

	fd=open(config.cache_file, O_CREAT|O_EXCL|O_RDWR, 0600);
	if (fd == -1) {
		pk_log(LOG_ERROR, "couldn't create cache file");
		return PK_IOERR;
	}
	/* There's a race condition in the way the loop driver
	   interacts with the memory management system for (at least)
	   underlying file systems that provide the prepare_write and
	   commit_write address space operations.  This can cause data
	   not to be properly written to disk if I/O submitted to the
	   loop driver spans multiple page-cache pages and is not
	   aligned on page cache boundaries.  We therefore need to
	   make sure that our header is a multiple of the page size.
	   We assume that the page size is at least sizeof(hdr) bytes. */
	state.offset=page_size;
	state.cache_flags=0;
	hdr.magic=htonl(CA_MAGIC);
	hdr.entries=htonl(parcel.chunks);
	hdr.offset=htonl(state.offset >> 9);
	hdr.flags=htonl(state.cache_flags);
	hdr.version=CA_VERSION;
	if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
		pk_log(LOG_ERROR, "Couldn't write cache file header");
		return PK_IOERR;
	}
	if (ftruncate(fd, cache_chunk_to_offset(parcel.chunks))) {
		pk_log(LOG_ERROR, "couldn't extend cache file");
		return PK_IOERR;
	}

	pk_log(LOG_INFO, "Created cache file");
	state.cache_fd=fd;
	return PK_SUCCESS;
}

static pk_err_t open_cache_file(long page_size)
{
	struct ca_header hdr;
	int fd;

	fd=open(config.cache_file, O_RDWR);
	if (fd == -1) {
		pk_log(LOG_ERROR, "couldn't open cache file");
		return PK_IOERR;
	}
	if (read(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
		pk_log(LOG_ERROR, "Couldn't read cache file header");
		return PK_IOERR;
	}
	if (ntohl(hdr.magic) != CA_MAGIC) {
		pk_log(LOG_ERROR, "Invalid magic number reading cache file");
		return PK_BADFORMAT;
	}
	if (hdr.version != CA_VERSION) {
		pk_log(LOG_ERROR, "Invalid version reading cache file: "
					"expected %d, found %d", CA_VERSION,
					hdr.version);
		return PK_BADFORMAT;
	}
	if (ntohl(hdr.entries) != parcel.chunks) {
		pk_log(LOG_ERROR, "Invalid chunk count reading cache file: "
					"expected %u, found %u",
					parcel.chunks, ntohl(hdr.entries));
		return PK_BADFORMAT;
	}
	state.cache_flags=ntohl(hdr.flags);
	state.offset=ntohl(hdr.offset) << 9;
	if (state.offset % page_size != 0) {
		/* This may occur with old cache files, or with cache files
		   copied from another system with a different page size. */
		pk_log(LOG_ERROR, "Cache file's header length %u is not "
					"a multiple of the page size %ld",
					state.offset, page_size);
		pk_log(LOG_ERROR, "Data corruption may occur.  If it does, "
					"checkin will be disallowed");
	}

	pk_log(LOG_INFO, "Read cache header");
	state.cache_fd=fd;
	return PK_SUCCESS;
}

static pk_err_t cache_set_flags(unsigned flags)
{
	unsigned tmp;

	if (!(config.flags & WANT_LOCK)) {
		/* Catch misuse of this function */
		pk_log(LOG_ERROR, "Refusing to set cache flags when lock "
					"not held");
		return PK_BUSY;
	}
	if (!state.cache_fd) {
		pk_log(LOG_ERROR, "Cache file not open; can't set flags");
		return PK_IOERR;
	}

	tmp=htonl(flags);
	if (pwrite(state.cache_fd, &tmp, sizeof(tmp),
				offsetof(struct ca_header, flags))
				!= sizeof(tmp)) {
		pk_log(LOG_ERROR, "Couldn't write new flags to cache file");
		return PK_IOERR;
	}
	if (fdatasync(state.cache_fd)) {
		pk_log(LOG_ERROR, "Couldn't sync cache file");
		return PK_IOERR;
	}
	state.cache_flags=flags;
	return PK_SUCCESS;
}

pk_err_t cache_set_flag(unsigned flag)
{
	if ((flag & CA_F_DAMAGED) == CA_F_DAMAGED)
		pk_log(LOG_ERROR, "Setting damaged flag on local cache");
	return cache_set_flags(state.cache_flags | flag);
}

pk_err_t cache_clear_flag(unsigned flag)
{
	return cache_set_flags(state.cache_flags & ~flag);
}

int cache_test_flag(unsigned flag)
{
	return ((state.cache_flags & flag) == flag);
}

static pk_err_t create_cache_index(void)
{
	pk_err_t ret;

again:
{'fraction_non_alphanumeric': 0.11236399604352126, 'fraction_numerical': 0.011473788328387734, 'mean_word_length': 4.398291510945008, 'pattern_counts': {'":': 0, '<': 27, '<?xml version=': 0, '>': 27, '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': '3584035', 'n_tokens_mistral': 3996, 'n_tokens_neox': 3714, 'n_words': 1042}