<commit_before>/* Copyright 2012-2013 Peter Goodman, all rights reserved. */
/*
 * state.cc
 *
 *  Created on: 2012-11-19
 *      Author: pag
 *     Version: $Id$
 */

#include "granary/globals.h"
#include "granary/state.h"

extern "C" {

    /// Get access to the CPU-private state.
    extern granary::cpu_state **kernel_get_cpu_state(granary::cpu_state *[]);

    /// Used to run a function on each CPU.
    extern void kernel_run_on_each_cpu(void (*func)(void));

    /// Call a function where all CPUs are synchronised.
    void kernel_run_synchronised(void (*func)(void));

    /// Mark a page as being only readable.
    void kernel_make_page_read_only(void *addr);
}

namespace granary {

    enum {
        MAX_NUM_CPUS = 256
    };

    /// Manually manage our own per-cpu state.
    cpu_state *CPU_STATES[MAX_NUM_CPUS] = {nullptr};

#if CONFIG_CHECK_CPU_ACCESS_SAFE
    /// Check that it's safe to access CPU-private state.
    __attribute__((noinline))
    void check_cpu_access_safety(void) {
        const eflags flags = granary_load_flags();
        if(flags.interrupt) {
            granary_break_on_curiosity();
        }
    }
#endif

    extern "C" uint64_t *granary_get_private_stack_top(void)
    {
#if CONFIG_CHECK_CPU_ACCESS_SAFE
        check_cpu_access_safety();
#endif
        return (uint64_t *) &((*kernel_get_cpu_state(CPU_STATES))->percpu_stack.top);
    }

    namespace detail {
        struct dummy_thread_state : public client::thread_state {
            uint64_t dummy_val;
        };
    }

    /// Figure out the size of the CPU state.
    enum {
        DUMMY_THREAD_STATE_SIZE = sizeof(detail::dummy_thread_state),
        ALIGNED_THREAD_STATE_SIZE = sizeof(granary::thread_state)
                                  + ALIGN_TO(sizeof(granary::thread_state), 8),
        THREAD_STATE_SIZE = (sizeof(uint64_t) == DUMMY_THREAD_STATE_SIZE)
                          ? 0
                          : ALIGNED_THREAD_STATE_SIZE
    };

    /// Gets a handle to the current CPU state.
    cpu_state_handle::cpu_state_handle(void) throw()
        : state(*kernel_get_cpu_state(CPU_STATES))
    { }

    /// Represents CPU state that is actually allocated and has two poisoned
    /// pages around it.
    struct poison {
        char poison[PAGE_SIZE];
    } __attribute__((packed, aligned(CONFIG_MEMORY_PAGE_SIZE)));

    struct poisoned_cpu_state {
        poison before;
        cpu_state state;
        poison after;
    } __attribute__((aligned(CONFIG_MEMORY_PAGE_SIZE)));

    /// Allocate and initialise state for each CPU.
    static void alloc_cpu_state(void) {
        cpu_state **state_ptr(kernel_get_cpu_state(CPU_STATES));
        poisoned_cpu_state *poisoned_state(
            allocate_memory<poisoned_cpu_state>());

        *state_ptr = &(poisoned_state->state);

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
        // Get a copy of the native IDTR.
        get_idtr(&(poisoned_state->state.native_idtr));
#endif

#if CONFIG_INSTRUMENT_HOST
        /// Get a copy of the native MSR_LSTAR model-specific register.
        poisoned_state->state.native_msr_lstar = get_msr(MSR_LSTAR);
#endif
    }

    /// Initialise the CPU state.
    void cpu_state::init_early(void) throw() {
        kernel_run_on_each_cpu(alloc_cpu_state);
    }

    /// Initialise the IDTR and MSR_LSTAR for each CPU.
    static void set_percpu(void) {
        cpu_state_handle cpu;

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
        set_idtr(&(cpu->idtr));
#endif

#if CONFIG_INSTRUMENT_HOST
        set_msr(MSR_LSTAR, cpu->msr_lstar);
#endif

        UNUSED(cpu);
    }

    void cpu_state::init_late(void) throw() {
        eflags flags;

        enum {
            NEG_OFFSET = offsetof(poisoned_cpu_state, state),
            POS_OFFSET = offsetof(poisoned_cpu_state, after) - NEG_OFFSET
        };

        for(unsigned i(0); i < MAX_NUM_CPUS; ++i) {

            if(!CPU_STATES[i]) {
                continue;
            }

            // Page protect the poisoned pages around the CPU state.
            kernel_make_page_read_only(
                unsafe_cast<char *>(CPU_STATES[i]) - NEG_OFFSET);
            kernel_make_page_read_only(
                unsafe_cast<char *>(CPU_STATES[i]) + POS_OFFSET);

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
#   if CONFIG_ENABLE_INTERRUPT_DELAY
            // Allocate space for interrupt delay handlers.
            CPU_STATES[i]->interrupt_delay_handler = reinterpret_cast<app_pc>(
                global_state::FRAGMENT_ALLOCATOR-> \
                    allocate_untyped(16, INTERRUPT_DELAY_CODE_SIZE));
#   endif
            // Create this CPUs IDT and vector entry points.
            flags = granary_disable_interrupts();
            CPU_STATES[i]->idtr = create_idt(CPU_STATES[i]->native_idtr);
            granary_store_flags(flags);
#endif
#if CONFIG_INSTRUMENT_HOST
            // Create this CPUs SYSCALL entry point.
            flags = granary_disable_interrupts();
            CPU_STATES[i]->msr_lstar = create_syscall_entrypoint(
                CPU_STATES[i]->native_msr_lstar);
            granary_store_flags(flags);
#endif

            // Page protect the IDTs.
            kernel_make_page_read_only(CPU_STATES[i]->idtr.base);
        }

        kernel_run_on_each_cpu(set_percpu);

        // Performed initialisation, where all CPUs are first synchronised.
        if(should_init_sync()) {
            kernel_run_synchronised(&init_sync);
        }

        UNUSED(flags);
    }

    /// Note: thread_state_handle::thread_state_handle and ::init are in the
    ///       OS-specific state.cc file.
}
<commit_msg>Free transient allocators around IDT and SYSCALL entrypoint creation.<commit_after>/* Copyright 2012-2013 Peter Goodman, all rights reserved. */
/*
 * state.cc
 *
 *  Created on: 2012-11-19
 *      Author: pag
 *     Version: $Id$
 */

#include "granary/globals.h"
#include "granary/state.h"

extern "C" {

    /// Get access to the CPU-private state.
    extern granary::cpu_state **kernel_get_cpu_state(granary::cpu_state *[]);

    /// Used to run a function on each CPU.
    extern void kernel_run_on_each_cpu(void (*func)(void));

    /// Call a function where all CPUs are synchronised.
    void kernel_run_synchronised(void (*func)(void));

    /// Mark a page as being only readable.
    void kernel_make_page_read_only(void *addr);
}

namespace granary {

    enum {
        MAX_NUM_CPUS = 256
    };

    /// Manually manage our own per-cpu state.
    cpu_state *CPU_STATES[MAX_NUM_CPUS] = {nullptr};

#if CONFIG_CHECK_CPU_ACCESS_SAFE
    /// Check that it's safe to access CPU-private state.
    __attribute__((noinline))
    void check_cpu_access_safety(void) {
        const eflags flags = granary_load_flags();
        if(flags.interrupt) {
            granary_break_on_curiosity();
        }
    }
#endif

    extern "C" uint64_t *granary_get_private_stack_top(void)
    {
#if CONFIG_CHECK_CPU_ACCESS_SAFE
        check_cpu_access_safety();
#endif
        return (uint64_t *) &((*kernel_get_cpu_state(CPU_STATES))->percpu_stack.top);
    }

    namespace detail {
        struct dummy_thread_state : public client::thread_state {
            uint64_t dummy_val;
        };
    }

    /// Figure out the size of the CPU state.
    enum {
        DUMMY_THREAD_STATE_SIZE = sizeof(detail::dummy_thread_state),
        ALIGNED_THREAD_STATE_SIZE = sizeof(granary::thread_state)
                                  + ALIGN_TO(sizeof(granary::thread_state), 8),
        THREAD_STATE_SIZE = (sizeof(uint64_t) == DUMMY_THREAD_STATE_SIZE)
                          ? 0
                          : ALIGNED_THREAD_STATE_SIZE
    };

    /// Gets a handle to the current CPU state.
    cpu_state_handle::cpu_state_handle(void) throw()
        : state(*kernel_get_cpu_state(CPU_STATES))
    { }

    /// Represents CPU state that is actually allocated and has two poisoned
    /// pages around it.
    struct poison {
        char poison[PAGE_SIZE];
    } __attribute__((packed, aligned(CONFIG_MEMORY_PAGE_SIZE)));

    struct poisoned_cpu_state {
        poison before;
        cpu_state state;
        poison after;
    } __attribute__((aligned(CONFIG_MEMORY_PAGE_SIZE)));

    /// Allocate and initialise state for each CPU.
    static void alloc_cpu_state(void) {
        cpu_state **state_ptr(kernel_get_cpu_state(CPU_STATES));
        poisoned_cpu_state *poisoned_state(
            allocate_memory<poisoned_cpu_state>());

        *state_ptr = &(poisoned_state->state);

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
        // Get a copy of the native IDTR.
        get_idtr(&(poisoned_state->state.native_idtr));
#endif

#if CONFIG_INSTRUMENT_HOST
        /// Get a copy of the native MSR_LSTAR model-specific register.
        poisoned_state->state.native_msr_lstar = get_msr(MSR_LSTAR);
#endif
    }

    /// Initialise the CPU state.
    void cpu_state::init_early(void) throw() {
        kernel_run_on_each_cpu(alloc_cpu_state);
    }

    /// Initialise the IDTR and MSR_LSTAR for each CPU.
    static void set_percpu(void) {
        cpu_state_handle cpu;

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
        set_idtr(&(cpu->idtr));
#endif

#if CONFIG_INSTRUMENT_HOST
        set_msr(MSR_LSTAR, cpu->msr_lstar);
#endif

        UNUSED(cpu);
    }

    void cpu_state::init_late(void) throw() {
        eflags flags;

        enum {
            NEG_OFFSET = offsetof(poisoned_cpu_state, state),
            POS_OFFSET = offsetof(poisoned_cpu_state, after) - NEG_OFFSET
        };

        for(unsigned i(0); i < MAX_NUM_CPUS; ++i) {

            if(!CPU_STATES[i]) {
                continue;
            }

            // Page protect the poisoned pages around the CPU state.
            kernel_make_page_read_only(
                unsafe_cast<char *>(CPU_STATES[i]) - NEG_OFFSET);
            kernel_make_page_read_only(
                unsafe_cast<char *>(CPU_STATES[i]) + POS_OFFSET);

#if CONFIG_HANDLE_INTERRUPTS || CONFIG_INSTRUMENT_HOST
#   if CONFIG_ENABLE_INTERRUPT_DELAY
            // Allocate space for interrupt delay handlers.
            CPU_STATES[i]->interrupt_delay_handler = reinterpret_cast<app_pc>(
                global_state::FRAGMENT_ALLOCATOR-> \
                    allocate_untyped(16, INTERRUPT_DELAY_CODE_SIZE));
#   endif
            // Create this CPUs IDT and vector entry points.
            flags = granary_disable_interrupts();
            {
                cpu_state_handle cpu;
                cpu.free_transient_allocators();
                CPU_STATES[i]->idtr = create_idt(CPU_STATES[i]->native_idtr);
            }
            granary_store_flags(flags);
#endif
#if CONFIG_INSTRUMENT_HOST
            // Create this CPUs SYSCALL entry point.
            flags = granary_disable_interrupts();
            {
                cpu_state_handle cpu;
                cpu.free_transient_allocators();
                CPU_STATES[i]->msr_lstar = create_syscall_entrypoint(
                    CPU_STATES[i]->native_msr_lstar);
            }
            granary_store_flags(flags);
#endif

            // Page protect the IDTs.
            kernel_make_page_read_only(CPU_STATES[i]->idtr.base);
        }

        kernel_run_on_each_cpu(set_percpu);

        // Performed initialisation, where all CPUs are first synchronised.
        if(should_init_sync()) {
            kernel_run_synchronised(&init_sync);
        }

        UNUSED(flags);
    }

    /// Note: thread_state_handle::thread_state_handle and ::init are in the
    ///       OS-specific state.cc file.
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/

#ifndef _WIN32

#include "file_mapper.hpp"

#include <cerrno>
#include <sys/mman.h>

#include <tightdb/util/errno.hpp>

#ifdef TIGHTDB_ENABLE_ENCRYPTION

#include "encrypted_file_mapping.hpp"

#include <memory>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>

#include <tightdb/util/errno.hpp>
#include <tightdb/util/shared_ptr.hpp>
#include <tightdb/util/terminate.hpp>
#include <tightdb/util/thread.hpp>

using namespace tightdb;
using namespace tightdb::util;

namespace {
const size_t page_size = 4096;

class SpinLockGuard {
public:
    SpinLockGuard(Atomic<bool>& lock) : m_lock(lock)
    {
        while (m_lock.exchange_acquire(true)) ;
    }

    ~SpinLockGuard()
    {
        m_lock.store_release(false);
    }

private:
    Atomic<bool>& m_lock;
};

// A list of all of the active encrypted mappings for a single file
struct mappings_for_file {
    dev_t device;
    ino_t inode;
    SharedPtr<SharedFileInfo> info;
};

// Group the information we need to map a SIGSEGV address to an
// EncryptedFileMapping for the sake of cache-friendliness with 3+ active
// mappings (and no worse with only two
struct mapping_and_addr {
    SharedPtr<EncryptedFileMapping> mapping;
    void* addr;
    size_t size;
};

Atomic<bool> mapping_lock;
std::vector<mapping_and_addr> mappings_by_addr;
std::vector<mappings_for_file> mappings_by_file;

// The signal handlers which our handlers replaced, if any, for forwarding
// signals for segfaults outside of our encrypted pages
struct sigaction old_segv;
struct sigaction old_bus;

void signal_handler(int code, siginfo_t* info, void* ctx)
{
    SpinLockGuard lock(mapping_lock);
    for (size_t i = 0; i < mappings_by_addr.size(); ++i) {
        mapping_and_addr& m = mappings_by_addr[i];
        if (m.addr > info->si_addr || static_cast<char*>(m.addr) + m.size <= info->si_addr)
            continue;

        m.mapping->handle_access(info->si_addr);
        return;
    }

    // forward unhandled signals
    if (code == SIGSEGV) {
        if (old_segv.sa_sigaction)
            old_segv.sa_sigaction(code, info, ctx);
        else if (old_segv.sa_handler)
            old_segv.sa_handler(code);
        else
            TIGHTDB_TERMINATE("Segmentation fault");
    }
    else if (code == SIGBUS) {
        if (old_bus.sa_sigaction)
            old_bus.sa_sigaction(code, info, ctx);
        else if (old_bus.sa_handler)
            old_bus.sa_handler(code);
        else
            TIGHTDB_TERMINATE("Segmentation fault");
    }
    else
        TIGHTDB_TERMINATE("Segmentation fault");
}

mapping_and_addr* find_mapping_for_addr(void* addr, size_t size)
{
    for (size_t i = 0; i < mappings_by_addr.size(); ++i) {
        mapping_and_addr& m = mappings_by_addr[i];
        if (m.addr == addr && m.size == size)
            return &m;
    }

    return 0;
}

size_t round_up_to_page_size(size_t size)
{
    return (size + page_size - 1) & ~(page_size - 1);
}

void add_mapping(void* addr, size_t size, int fd, File::AccessMode access, const char* encryption_key)
{
    struct stat st;
    if (fstat(fd, &st)) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("fstat() failed: ", err));
    }

    if (st.st_size > 0 && static_cast<size_t>(st.st_size) < page_size)
        throw DecryptionFailed();

    SpinLockGuard lock(mapping_lock);

    static bool has_installed_handler = false;
    if (!has_installed_handler) {
        has_installed_handler = true;

        struct sigaction action;
        action.sa_sigaction = signal_handler;
        action.sa_flags = SA_SIGINFO;

        if (sigaction(SIGSEGV, &action, &old_segv) != 0)
            TIGHTDB_TERMINATE("sigaction SEGV failed");
        if (sigaction(SIGBUS, &action, &old_bus) != 0)
            TIGHTDB_TERMINATE("sigaction SIGBUS");
    }

    std::vector<mappings_for_file>::iterator it;
    for (it = mappings_by_file.begin(); it != mappings_by_file.end(); ++it) {
        if (it->inode == st.st_ino && it->device == st.st_dev)
            break;
    }

    // Get the potential memory allocation out of the way so that mappings_by_addr.push_back can't throw
    mappings_by_addr.reserve(mappings_by_addr.size() + 1);

    if (it == mappings_by_file.end()) {
        mappings_by_file.reserve(mappings_by_file.size() + 1);

        fd = dup(fd);
        if (fd == -1) {
            int err = errno; // Eliminate any risk of clobbering
            throw std::runtime_error(get_errno_msg("dup() failed: ", err));
        }

        mappings_for_file f;
        f.device = st.st_dev;
        f.inode = st.st_ino;
        try {
            f.info = new SharedFileInfo(reinterpret_cast<const uint8_t*>(encryption_key), fd);
        }
        catch (...) {
            ::close(fd);
            throw;
        }

        mappings_by_file.push_back(f); // can't throw due to reserve() above
        it = mappings_by_file.end() - 1;
    }

    try {
        mapping_and_addr m;
        m.addr = addr;
        m.size = size;
        m.mapping = new EncryptedFileMapping(*it->info, addr, size, access);
        mappings_by_addr.push_back(m); // can't throw due to reserve() above
    }
    catch (...) {
        if (it->info->mappings.empty()) {
            ::close(it->info->fd);
            mappings_by_file.erase(it);
        }
        throw;
    }
}

void remove_mapping(void* addr, size_t size)
{
    size = round_up_to_page_size(size);
    SpinLockGuard lock(mapping_lock);
    mapping_and_addr* m = find_mapping_for_addr(addr, size);
    if (!m)
        return;

    mappings_by_addr.erase(mappings_by_addr.begin() + (m - &mappings_by_addr[0]));
    for (std::vector<mappings_for_file>::iterator it = mappings_by_file.begin(); it != mappings_by_file.end(); ++it) {
        if (it->info->mappings.empty()) {
            if(::close(it->info->fd) != 0) {
                int err = errno; // Eliminate any risk of clobbering
                if(err == EBADF || err == EIO) // todo, how do we handle EINTR?
                    throw std::runtime_error(get_errno_msg("close() failed: ", err));
            }
            mappings_by_file.erase(it);
            break;
        }
    }
}

void* mmap_anon(size_t size)
{
    void* addr = ::mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
    if (addr == MAP_FAILED) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("mmap() failed: ", err));
    }
    return addr;
}

} // anonymous namespace
#endif

namespace tightdb {
namespace util {

void* mmap(int fd, size_t size, File::AccessMode access, const char* encryption_key)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    if (encryption_key) {
        size = round_up_to_page_size(size);
        void* addr = mmap_anon(size);
        add_mapping(addr, size, fd, access, encryption_key);
        return addr;
    }
    else
#else
    TIGHTDB_ASSERT(!encryption_key);
    static_cast<void>(encryption_key);
#endif
    {
        int prot = PROT_READ;
        switch (access) {
            case File::access_ReadWrite:
                prot |= PROT_WRITE;
                break;
            case File::access_ReadOnly:
                break;
        }

        void* addr = ::mmap(0, size, prot, MAP_SHARED, fd, 0);
        if (addr != MAP_FAILED)
            return addr;
    }

    int err = errno; // Eliminate any risk of clobbering
    throw std::runtime_error(get_errno_msg("mmap() failed: ", err));
}

void munmap(void* addr, size_t size) TIGHTDB_NOEXCEPT
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    remove_mapping(addr, size);
#endif
    if(::munmap(addr, size) != 0) {
        int err = errno;
        throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
    }
}

void* mremap(int fd, void* old_addr, size_t old_size, File::AccessMode a, size_t new_size)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    {
        SpinLockGuard lock(mapping_lock);
        size_t rounded_old_size = round_up_to_page_size(old_size);
        if (mapping_and_addr* m = find_mapping_for_addr(old_addr, rounded_old_size)) {
            size_t rounded_new_size = round_up_to_page_size(new_size);
            if (rounded_old_size == rounded_new_size)
                return old_addr;

            void* new_addr = mmap_anon(rounded_new_size);
            m->mapping->set(new_addr, rounded_new_size);
            if (::munmap(old_addr, rounded_old_size) != 0) {
                int err = errno;
                throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
            }
            m->addr = new_addr;
            m->size = rounded_new_size;
            return new_addr;
        }
    }
#endif

#ifdef _GNU_SOURCE
    static_cast<void>(fd);
    static_cast<void>(a);
    void* new_addr = ::mremap(old_addr, old_size, new_size, MREMAP_MAYMOVE);
    if (new_addr != MAP_FAILED)
        return new_addr;
    int err = errno; // Eliminate any risk of clobbering
    throw std::runtime_error(get_errno_msg("mremap(): failed: ", err));
#else
    void* new_addr = mmap(fd, new_size, a, nullptr);
    if(::munmap(old_addr, old_size) != 0)
        int err = errno;
        throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
    }
    return new_addr;
#endif
}

void msync(void* addr, size_t size)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    { // first check the encrypted mappings
        SpinLockGuard lock(mapping_lock);
        if (mapping_and_addr* m = find_mapping_for_addr(addr, size)) {
            m->mapping->flush();
            m->mapping->sync();
            return;
        }
    }
#endif

    // not an encrypted mapping
    if (::msync(addr, size, MS_SYNC) != 0) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("msync() failed: ", err));
    }
}

}
}

#endif // _WIN32
<commit_msg>typo fix<commit_after>/*************************************************************************
 *
 * TIGHTDB CONFIDENTIAL
 * __________________
 *
 *  [2011] - [2012] TightDB Inc
 *  All Rights Reserved.
 *
 * NOTICE:  All information contained herein is, and remains
 * the property of TightDB Incorporated and its suppliers,
 * if any.  The intellectual and technical concepts contained
 * herein are proprietary to TightDB Incorporated
 * and its suppliers and may be covered by U.S. and Foreign Patents,
 * patents in process, and are protected by trade secret or copyright law.
 * Dissemination of this information or reproduction of this material
 * is strictly forbidden unless prior written permission is obtained
 * from TightDB Incorporated.
 *
 **************************************************************************/

#ifndef _WIN32

#include "file_mapper.hpp"

#include <cerrno>
#include <sys/mman.h>

#include <tightdb/util/errno.hpp>

#ifdef TIGHTDB_ENABLE_ENCRYPTION

#include "encrypted_file_mapping.hpp"

#include <memory>
#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>

#include <tightdb/util/errno.hpp>
#include <tightdb/util/shared_ptr.hpp>
#include <tightdb/util/terminate.hpp>
#include <tightdb/util/thread.hpp>

using namespace tightdb;
using namespace tightdb::util;

namespace {
const size_t page_size = 4096;

class SpinLockGuard {
public:
    SpinLockGuard(Atomic<bool>& lock) : m_lock(lock)
    {
        while (m_lock.exchange_acquire(true)) ;
    }

    ~SpinLockGuard()
    {
        m_lock.store_release(false);
    }

private:
    Atomic<bool>& m_lock;
};

// A list of all of the active encrypted mappings for a single file
struct mappings_for_file {
    dev_t device;
    ino_t inode;
    SharedPtr<SharedFileInfo> info;
};

// Group the information we need to map a SIGSEGV address to an
// EncryptedFileMapping for the sake of cache-friendliness with 3+ active
// mappings (and no worse with only two
struct mapping_and_addr {
    SharedPtr<EncryptedFileMapping> mapping;
    void* addr;
    size_t size;
};

Atomic<bool> mapping_lock;
std::vector<mapping_and_addr> mappings_by_addr;
std::vector<mappings_for_file> mappings_by_file;

// The signal handlers which our handlers replaced, if any, for forwarding
// signals for segfaults outside of our encrypted pages
struct sigaction old_segv;
struct sigaction old_bus;

void signal_handler(int code, siginfo_t* info, void* ctx)
{
    SpinLockGuard lock(mapping_lock);
    for (size_t i = 0; i < mappings_by_addr.size(); ++i) {
        mapping_and_addr& m = mappings_by_addr[i];
        if (m.addr > info->si_addr || static_cast<char*>(m.addr) + m.size <= info->si_addr)
            continue;

        m.mapping->handle_access(info->si_addr);
        return;
    }

    // forward unhandled signals
    if (code == SIGSEGV) {
        if (old_segv.sa_sigaction)
            old_segv.sa_sigaction(code, info, ctx);
        else if (old_segv.sa_handler)
            old_segv.sa_handler(code);
        else
            TIGHTDB_TERMINATE("Segmentation fault");
    }
    else if (code == SIGBUS) {
        if (old_bus.sa_sigaction)
            old_bus.sa_sigaction(code, info, ctx);
        else if (old_bus.sa_handler)
            old_bus.sa_handler(code);
        else
            TIGHTDB_TERMINATE("Segmentation fault");
    }
    else
        TIGHTDB_TERMINATE("Segmentation fault");
}

mapping_and_addr* find_mapping_for_addr(void* addr, size_t size)
{
    for (size_t i = 0; i < mappings_by_addr.size(); ++i) {
        mapping_and_addr& m = mappings_by_addr[i];
        if (m.addr == addr && m.size == size)
            return &m;
    }

    return 0;
}

size_t round_up_to_page_size(size_t size)
{
    return (size + page_size - 1) & ~(page_size - 1);
}

void add_mapping(void* addr, size_t size, int fd, File::AccessMode access, const char* encryption_key)
{
    struct stat st;
    if (fstat(fd, &st)) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("fstat() failed: ", err));
    }

    if (st.st_size > 0 && static_cast<size_t>(st.st_size) < page_size)
        throw DecryptionFailed();

    SpinLockGuard lock(mapping_lock);

    static bool has_installed_handler = false;
    if (!has_installed_handler) {
        has_installed_handler = true;

        struct sigaction action;
        action.sa_sigaction = signal_handler;
        action.sa_flags = SA_SIGINFO;

        if (sigaction(SIGSEGV, &action, &old_segv) != 0)
            TIGHTDB_TERMINATE("sigaction SEGV failed");
        if (sigaction(SIGBUS, &action, &old_bus) != 0)
            TIGHTDB_TERMINATE("sigaction SIGBUS");
    }

    std::vector<mappings_for_file>::iterator it;
    for (it = mappings_by_file.begin(); it != mappings_by_file.end(); ++it) {
        if (it->inode == st.st_ino && it->device == st.st_dev)
            break;
    }

    // Get the potential memory allocation out of the way so that mappings_by_addr.push_back can't throw
    mappings_by_addr.reserve(mappings_by_addr.size() + 1);

    if (it == mappings_by_file.end()) {
        mappings_by_file.reserve(mappings_by_file.size() + 1);

        fd = dup(fd);
        if (fd == -1) {
            int err = errno; // Eliminate any risk of clobbering
            throw std::runtime_error(get_errno_msg("dup() failed: ", err));
        }

        mappings_for_file f;
        f.device = st.st_dev;
        f.inode = st.st_ino;
        try {
            f.info = new SharedFileInfo(reinterpret_cast<const uint8_t*>(encryption_key), fd);
        }
        catch (...) {
            ::close(fd);
            throw;
        }

        mappings_by_file.push_back(f); // can't throw due to reserve() above
        it = mappings_by_file.end() - 1;
    }

    try {
        mapping_and_addr m;
        m.addr = addr;
        m.size = size;
        m.mapping = new EncryptedFileMapping(*it->info, addr, size, access);
        mappings_by_addr.push_back(m); // can't throw due to reserve() above
    }
    catch (...) {
        if (it->info->mappings.empty()) {
            ::close(it->info->fd);
            mappings_by_file.erase(it);
        }
        throw;
    }
}

void remove_mapping(void* addr, size_t size)
{
    size = round_up_to_page_size(size);
    SpinLockGuard lock(mapping_lock);
    mapping_and_addr* m = find_mapping_for_addr(addr, size);
    if (!m)
        return;

    mappings_by_addr.erase(mappings_by_addr.begin() + (m - &mappings_by_addr[0]));
    for (std::vector<mappings_for_file>::iterator it = mappings_by_file.begin(); it != mappings_by_file.end(); ++it) {
        if (it->info->mappings.empty()) {
            if(::close(it->info->fd) != 0) {
                int err = errno; // Eliminate any risk of clobbering
                if(err == EBADF || err == EIO) // todo, how do we handle EINTR?
                    throw std::runtime_error(get_errno_msg("close() failed: ", err));
            }
            mappings_by_file.erase(it);
            break;
        }
    }
}

void* mmap_anon(size_t size)
{
    void* addr = ::mmap(0, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
    if (addr == MAP_FAILED) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("mmap() failed: ", err));
    }
    return addr;
}

} // anonymous namespace
#endif

namespace tightdb {
namespace util {

void* mmap(int fd, size_t size, File::AccessMode access, const char* encryption_key)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    if (encryption_key) {
        size = round_up_to_page_size(size);
        void* addr = mmap_anon(size);
        add_mapping(addr, size, fd, access, encryption_key);
        return addr;
    }
    else
#else
    TIGHTDB_ASSERT(!encryption_key);
    static_cast<void>(encryption_key);
#endif
    {
        int prot = PROT_READ;
        switch (access) {
            case File::access_ReadWrite:
                prot |= PROT_WRITE;
                break;
            case File::access_ReadOnly:
                break;
        }

        void* addr = ::mmap(0, size, prot, MAP_SHARED, fd, 0);
        if (addr != MAP_FAILED)
            return addr;
    }

    int err = errno; // Eliminate any risk of clobbering
    throw std::runtime_error(get_errno_msg("mmap() failed: ", err));
}

void munmap(void* addr, size_t size) TIGHTDB_NOEXCEPT
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    remove_mapping(addr, size);
#endif
    if(::munmap(addr, size) != 0) {
        int err = errno;
        throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
    }
}

void* mremap(int fd, void* old_addr, size_t old_size, File::AccessMode a, size_t new_size)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    {
        SpinLockGuard lock(mapping_lock);
        size_t rounded_old_size = round_up_to_page_size(old_size);
        if (mapping_and_addr* m = find_mapping_for_addr(old_addr, rounded_old_size)) {
            size_t rounded_new_size = round_up_to_page_size(new_size);
            if (rounded_old_size == rounded_new_size)
                return old_addr;

            void* new_addr = mmap_anon(rounded_new_size);
            m->mapping->set(new_addr, rounded_new_size);
            if (::munmap(old_addr, rounded_old_size) != 0) {
                int err = errno;
                throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
            }
            m->addr = new_addr;
            m->size = rounded_new_size;
            return new_addr;
        }
    }
#endif

#ifdef _GNU_SOURCE
    static_cast<void>(fd);
    static_cast<void>(a);
    void* new_addr = ::mremap(old_addr, old_size, new_size, MREMAP_MAYMOVE);
    if (new_addr != MAP_FAILED)
        return new_addr;
    int err = errno; // Eliminate any risk of clobbering
    throw std::runtime_error(get_errno_msg("mremap(): failed: ", err));
#else
    void* new_addr = mmap(fd, new_size, a, nullptr);
    if(::munmap(old_addr, old_size) != 0) {
        int err = errno;
        throw std::runtime_error(get_errno_msg("munmap() failed: ", err));
    }
    return new_addr;
#endif
}

void msync(void* addr, size_t size)
{
#ifdef TIGHTDB_ENABLE_ENCRYPTION
    { // first check the encrypted mappings
        SpinLockGuard lock(mapping_lock);
        if (mapping_and_addr* m = find_mapping_for_addr(addr, size)) {
            m->mapping->flush();
            m->mapping->sync();
            return;
        }
    }
#endif

    // not an encrypted mapping
    if (::msync(addr, size, MS_SYNC) != 0) {
        int err = errno; // Eliminate any risk of clobbering
        throw std::runtime_error(get_errno_msg("msync() failed: ", err));
    }
}

}
}

#endif // _WIN32
<|endoftext|>


<commit_before>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/main_menu.h"

#include <string>
#include <vector>

#include "app/gfx/insets.h"
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "views/background.h"
#include "views/painter.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"

namespace chromeos {

// Initial size of the renderer. This is contained within a window whose size
// is set to the size of the image IDR_MAIN_MENU_BUTTON_DROP_DOWN.
static const int kRendererX = 0;
static const int kRendererY = 25;
static const int kRendererWidth = 250;
static const int kRendererHeight = 400;

// Insets defining the regions that are stretched and titled to create the
// background of the popup. These constants are fed into
// Painter::CreateImagePainter as the insets, see it for details.
static const int kBackgroundImageTop = 27;
static const int kBackgroundImageLeft = 85;
static const int kBackgroundImageBottom = 10;
static const int kBackgroundImageRight = 8;

// Command line switch for specifying url of the page.
static const wchar_t kURLSwitch[] = L"main-menu-url";

// Command line switch for specifying the size of the main menu. The default is
// full screen.
static const wchar_t kMenuSizeSwitch[] = L"main-menu-size";

// URL of the page to load. This is ignored if kURLSwitch is specified.
static const char kMenuURL[] = "http://goto.ext.google.com/crux-home";

// Returns the size of the popup. By default the popup is sized slightly
// larger than full screen, but can be overriden by the command line switch
// kMenuSizeSwitch.
static gfx::Size GetPopupSize() {
  std::wstring cl_size =
      CommandLine::ForCurrentProcess()->GetSwitchValue(kMenuSizeSwitch);
  if (!cl_size.empty()) {
    std::vector<std::string> chunks;
    SplitString(WideToUTF8(cl_size), 'x', &chunks);
    if (chunks.size() == 2)
      return gfx::Size(StringToInt(chunks[0]), StringToInt(chunks[1]));
  }

  gfx::Size size =
      views::Screen::GetMonitorAreaNearestPoint(gfx::Point(0, 0)).size();
  // When full screen we don't want to see the drop shadow. Adjust the width
  // so the drop shadow ends up off screen.
  size.Enlarge(kBackgroundImageRight, kBackgroundImageBottom);
  return size;
}

// Returns the size for the renderer widget host view given the specified
// size of the popup.
static gfx::Size CalculateRWHVSize(const gfx::Size& popup_size) {
  return gfx::Size(popup_size.width() - kRendererX - kBackgroundImageRight,
                   popup_size.height() - kRendererY - kBackgroundImageBottom);
}

// Returns the URL of the menu.
static GURL GetMenuURL() {
  std::wstring url_string =
      CommandLine::ForCurrentProcess()->GetSwitchValue(kURLSwitch);
  if (!url_string.empty())
    return GURL(WideToUTF8(url_string));
  return GURL(kMenuURL);
}

// static
void MainMenu::Show(Browser* browser) {
  MainMenu::Get()->ShowImpl(browser);
}

// static
void MainMenu::ScheduleCreation() {
  MessageLoop::current()->PostDelayedTask(FROM_HERE, new LoadTask(), 5000);
}

MainMenu::~MainMenu() {
  // NOTE: we leak the menu_rvh_ and popup_ as by the time we get here the
  // message loop and notification services have been shutdown.
  // TODO(sky): fix this.
  // menu_rvh_->Shutdown();
  // popup_->CloseNow();
}

MainMenu::MainMenu()
    : browser_(NULL),
      popup_(NULL),
      site_instance_(NULL),
      menu_rvh_(NULL),
      rwhv_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(tab_contents_delegate_(this)),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
      has_shown_(false) {
  SkBitmap* drop_down_image = ResourceBundle::GetSharedInstance().
      GetBitmapNamed(IDR_MAIN_MENU_BUTTON_DROP_DOWN);

  views::WidgetGtk* menu_popup =
      new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP);
  popup_ = menu_popup;
  // The background image has transparency, so we make the window transparent.
  menu_popup->MakeTransparent();
  gfx::Size popup_size = GetPopupSize();
  menu_popup->Init(NULL, gfx::Rect(0, 0, popup_size.width(),
                                   popup_size.height()));

  views::Painter* painter = views::Painter::CreateImagePainter(
      *drop_down_image,
      gfx::Insets(kBackgroundImageTop, kBackgroundImageLeft,
                  kBackgroundImageBottom, kBackgroundImageRight),
      false);
  menu_popup->GetRootView()->set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  GURL menu_url(GetMenuURL());
  DCHECK(BrowserList::begin() != BrowserList::end());
  // TODO(sky): this shouldn't pick a random profile to use.
  Profile* profile = (*BrowserList::begin())->profile();
  site_instance_ = SiteInstance::CreateSiteInstanceForURL(profile, menu_url);
  menu_rvh_ = new RenderViewHost(site_instance_, this, MSG_ROUTING_NONE);

  rwhv_ = new RenderWidgetHostViewGtk(menu_rvh_);
  rwhv_->InitAsChild();
  menu_rvh_->CreateRenderView(profile->GetRequestContext());
  menu_popup->AddChild(rwhv_->GetNativeView());
  gfx::Size rwhv_size = CalculateRWHVSize(popup_size);
  menu_popup->PositionChild(rwhv_->GetNativeView(), kRendererX, kRendererY,
                            rwhv_size.width(), rwhv_size.height());
  rwhv_->SetSize(rwhv_size);
  menu_rvh_->NavigateToURL(menu_url);
}

// static
MainMenu* MainMenu::Get() {
  return Singleton<MainMenu>::get();
}

void MainMenu::ShowImpl(Browser* browser) {
  Cleanup();

  browser_ = browser;

  popup_->Show();

  GtkWidget* rwhv_widget = rwhv_->GetNativeView();

  if (!has_shown_) {
    has_shown_ = true;
    gtk_widget_realize(rwhv_widget);
    g_signal_connect(rwhv_widget, "button-press-event",
                     G_CALLBACK(CallButtonPressEvent), this);
  }

  // Do a mouse grab on the renderer widget host view's widget so that we can
  // close the popup if the user clicks anywhere else. And do a keyboard
  // grab so that we get all key events.
  gdk_pointer_grab(rwhv_widget->window, FALSE,
                   static_cast<GdkEventMask>(
                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
                         GDK_POINTER_MOTION_MASK),
                   NULL, NULL, GDK_CURRENT_TIME);
  gdk_keyboard_grab(rwhv_widget->window, FALSE, GDK_CURRENT_TIME);
}

void MainMenu::Hide() {
  gdk_keyboard_ungrab(GDK_CURRENT_TIME);
  gdk_pointer_ungrab(GDK_CURRENT_TIME);

  popup_->Hide();

  // The stack may have pending_contents_ on it. Delay deleting the
  // pending_contents_ as TabContents doesn't deal well with being deleted
  // while on the stack.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&MainMenu::Cleanup));
}

void MainMenu::Cleanup() {
  pending_contents_.reset(NULL);
  method_factory_.RevokeAll();
}

// static
gboolean MainMenu::CallButtonPressEvent(GtkWidget* widget,
                                        GdkEventButton* event,
                                        MainMenu* menu) {
  return menu->OnButtonPressEvent(widget, event);
}

gboolean MainMenu::OnButtonPressEvent(GtkWidget* widget,
                                      GdkEventButton* event) {
  if (event->x < 0 || event->y < 0 ||
      event->x >= widget->allocation.width ||
      event->y >= widget->allocation.height) {
    // The user clicked outside the bounds of the menu, delete the main which
    // results in closing it.
    Hide();
  }
  return FALSE;
}

void MainMenu::RequestMove(const gfx::Rect& new_bounds) {
  // Invoking PositionChild results in a gtk signal that triggers attempting to
  // to resize the window. We need to set the size request so that it resizes
  // correctly when this happens.
  gtk_widget_set_size_request(popup_->GetNativeView(),
                              new_bounds.width(), new_bounds.height());
  gfx::Size rwhv_size = CalculateRWHVSize(new_bounds.size());
  popup_->PositionChild(rwhv_->GetNativeView(), kRendererX, kRendererY,
                        rwhv_size.width(), rwhv_size.height());
  popup_->SetBounds(new_bounds);
  rwhv_->SetSize(rwhv_size);
}

RendererPreferences MainMenu::GetRendererPrefs(Profile* profile) const {
  return renderer_preferences_util::GetInitedRendererPreferences(profile);
}

void MainMenu::CreateNewWindow(int route_id) {
  if (pending_contents_.get()) {
    NOTREACHED();
    return;
  }

  helper_.CreateNewWindow(route_id, browser_->profile(), site_instance_,
                          DOMUIFactory::GetDOMUIType(GURL(GetMenuURL())),
                          NULL);
  pending_contents_.reset(helper_.GetCreatedWindow(route_id));
  pending_contents_->set_delegate(&tab_contents_delegate_);
}

void MainMenu::ShowCreatedWindow(int route_id,
                                 WindowOpenDisposition disposition,
                                 const gfx::Rect& initial_pos,
                                 bool user_gesture,
                                 const GURL& creator_url) {
  if (disposition == NEW_POPUP) {
    pending_contents_->set_delegate(NULL);
    browser_->GetSelectedTabContents()->AddNewContents(
        pending_contents_.release(), disposition, initial_pos, user_gesture,
        creator_url);
    Hide();
  }
}

void MainMenu::TabContentsDelegateImpl::OpenURLFromTab(
    TabContents* source,
    const GURL& url,
    const GURL& referrer,
    WindowOpenDisposition disposition,
    PageTransition::Type transition) {
  menu_->browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB,
                           PageTransition::LINK);
  menu_->Hide();
}

// LoadTask -------------------------------------------------------------------

void MainMenu::LoadTask::Run() {
  MainMenu::Get();
}

}  // namespace chromeos
<commit_msg>Fixes bug in MainMenu that if there are no browsers around when timer fires we get a crash.<commit_after>// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/main_menu.h"

#include <string>
#include <vector>

#include "app/gfx/insets.h"
#include "app/resource_bundle.h"
#include "base/command_line.h"
#include "base/message_loop.h"
#include "base/string_util.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/browser.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/renderer_host/render_view_host_factory.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "chrome/browser/renderer_host/render_widget_host_view_gtk.h"
#include "chrome/browser/renderer_host/site_instance.h"
#include "chrome/browser/renderer_preferences_util.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/tab_contents/render_view_host_delegate_helper.h"
#include "grit/app_resources.h"
#include "grit/generated_resources.h"
#include "grit/theme_resources.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "views/background.h"
#include "views/painter.h"
#include "views/screen.h"
#include "views/widget/root_view.h"
#include "views/widget/widget_gtk.h"

namespace chromeos {

// Initial size of the renderer. This is contained within a window whose size
// is set to the size of the image IDR_MAIN_MENU_BUTTON_DROP_DOWN.
static const int kRendererX = 0;
static const int kRendererY = 25;
static const int kRendererWidth = 250;
static const int kRendererHeight = 400;

// Insets defining the regions that are stretched and titled to create the
// background of the popup. These constants are fed into
// Painter::CreateImagePainter as the insets, see it for details.
static const int kBackgroundImageTop = 27;
static const int kBackgroundImageLeft = 85;
static const int kBackgroundImageBottom = 10;
static const int kBackgroundImageRight = 8;

// Command line switch for specifying url of the page.
static const wchar_t kURLSwitch[] = L"main-menu-url";

// Command line switch for specifying the size of the main menu. The default is
// full screen.
static const wchar_t kMenuSizeSwitch[] = L"main-menu-size";

// URL of the page to load. This is ignored if kURLSwitch is specified.
static const char kMenuURL[] = "http://goto.ext.google.com/crux-home";

// Returns the size of the popup. By default the popup is sized slightly
// larger than full screen, but can be overriden by the command line switch
// kMenuSizeSwitch.
static gfx::Size GetPopupSize() {
  std::wstring cl_size =
      CommandLine::ForCurrentProcess()->GetSwitchValue(kMenuSizeSwitch);
  if (!cl_size.empty()) {
    std::vector<std::string> chunks;
    SplitString(WideToUTF8(cl_size), 'x', &chunks);
    if (chunks.size() == 2)
      return gfx::Size(StringToInt(chunks[0]), StringToInt(chunks[1]));
  }

  gfx::Size size =
      views::Screen::GetMonitorAreaNearestPoint(gfx::Point(0, 0)).size();
  // When full screen we don't want to see the drop shadow. Adjust the width
  // so the drop shadow ends up off screen.
  size.Enlarge(kBackgroundImageRight, kBackgroundImageBottom);
  return size;
}

// Returns the size for the renderer widget host view given the specified
// size of the popup.
static gfx::Size CalculateRWHVSize(const gfx::Size& popup_size) {
  return gfx::Size(popup_size.width() - kRendererX - kBackgroundImageRight,
                   popup_size.height() - kRendererY - kBackgroundImageBottom);
}

// Returns the URL of the menu.
static GURL GetMenuURL() {
  std::wstring url_string =
      CommandLine::ForCurrentProcess()->GetSwitchValue(kURLSwitch);
  if (!url_string.empty())
    return GURL(WideToUTF8(url_string));
  return GURL(kMenuURL);
}

// static
void MainMenu::Show(Browser* browser) {
  MainMenu::Get()->ShowImpl(browser);
}

// static
void MainMenu::ScheduleCreation() {
  MessageLoop::current()->PostDelayedTask(FROM_HERE, new LoadTask(), 5000);
}

MainMenu::~MainMenu() {
  // NOTE: we leak the menu_rvh_ and popup_ as by the time we get here the
  // message loop and notification services have been shutdown.
  // TODO(sky): fix this.
  // menu_rvh_->Shutdown();
  // popup_->CloseNow();
}

MainMenu::MainMenu()
    : browser_(NULL),
      popup_(NULL),
      site_instance_(NULL),
      menu_rvh_(NULL),
      rwhv_(NULL),
      ALLOW_THIS_IN_INITIALIZER_LIST(tab_contents_delegate_(this)),
      ALLOW_THIS_IN_INITIALIZER_LIST(method_factory_(this)),
      has_shown_(false) {
  SkBitmap* drop_down_image = ResourceBundle::GetSharedInstance().
      GetBitmapNamed(IDR_MAIN_MENU_BUTTON_DROP_DOWN);

  views::WidgetGtk* menu_popup =
      new views::WidgetGtk(views::WidgetGtk::TYPE_POPUP);
  popup_ = menu_popup;
  // The background image has transparency, so we make the window transparent.
  menu_popup->MakeTransparent();
  gfx::Size popup_size = GetPopupSize();
  menu_popup->Init(NULL, gfx::Rect(0, 0, popup_size.width(),
                                   popup_size.height()));

  views::Painter* painter = views::Painter::CreateImagePainter(
      *drop_down_image,
      gfx::Insets(kBackgroundImageTop, kBackgroundImageLeft,
                  kBackgroundImageBottom, kBackgroundImageRight),
      false);
  menu_popup->GetRootView()->set_background(
      views::Background::CreateBackgroundPainter(true, painter));

  GURL menu_url(GetMenuURL());
  DCHECK(BrowserList::begin() != BrowserList::end());
  // TODO(sky): this shouldn't pick a random profile to use.
  Profile* profile = (*BrowserList::begin())->profile();
  site_instance_ = SiteInstance::CreateSiteInstanceForURL(profile, menu_url);
  menu_rvh_ = new RenderViewHost(site_instance_, this, MSG_ROUTING_NONE);

  rwhv_ = new RenderWidgetHostViewGtk(menu_rvh_);
  rwhv_->InitAsChild();
  menu_rvh_->CreateRenderView(profile->GetRequestContext());
  menu_popup->AddChild(rwhv_->GetNativeView());
  gfx::Size rwhv_size = CalculateRWHVSize(popup_size);
  menu_popup->PositionChild(rwhv_->GetNativeView(), kRendererX, kRendererY,
                            rwhv_size.width(), rwhv_size.height());
  rwhv_->SetSize(rwhv_size);
  menu_rvh_->NavigateToURL(menu_url);
}

// static
MainMenu* MainMenu::Get() {
  return Singleton<MainMenu>::get();
}

void MainMenu::ShowImpl(Browser* browser) {
  Cleanup();

  browser_ = browser;

  popup_->Show();

  GtkWidget* rwhv_widget = rwhv_->GetNativeView();

  if (!has_shown_) {
    has_shown_ = true;
    gtk_widget_realize(rwhv_widget);
    g_signal_connect(rwhv_widget, "button-press-event",
                     G_CALLBACK(CallButtonPressEvent), this);
  }

  // Do a mouse grab on the renderer widget host view's widget so that we can
  // close the popup if the user clicks anywhere else. And do a keyboard
  // grab so that we get all key events.
  gdk_pointer_grab(rwhv_widget->window, FALSE,
                   static_cast<GdkEventMask>(
                         GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
                         GDK_POINTER_MOTION_MASK),
                   NULL, NULL, GDK_CURRENT_TIME);
  gdk_keyboard_grab(rwhv_widget->window, FALSE, GDK_CURRENT_TIME);
}

void MainMenu::Hide() {
  gdk_keyboard_ungrab(GDK_CURRENT_TIME);
  gdk_pointer_ungrab(GDK_CURRENT_TIME);

  popup_->Hide();

  // The stack may have pending_contents_ on it. Delay deleting the
  // pending_contents_ as TabContents doesn't deal well with being deleted
  // while on the stack.
  MessageLoop::current()->PostTask(FROM_HERE,
      method_factory_.NewRunnableMethod(&MainMenu::Cleanup));
}

void MainMenu::Cleanup() {
  pending_contents_.reset(NULL);
  method_factory_.RevokeAll();
}

// static
gboolean MainMenu::CallButtonPressEvent(GtkWidget* widget,
                                        GdkEventButton* event,
                                        MainMenu* menu) {
  return menu->OnButtonPressEvent(widget, event);
}

gboolean MainMenu::OnButtonPressEvent(GtkWidget* widget,
                                      GdkEventButton* event) {
  if (event->x < 0 || event->y < 0 ||
      event->x >= widget->allocation.width ||
      event->y >= widget->allocation.height) {
    // The user clicked outside the bounds of the menu, delete the main which
    // results in closing it.
    Hide();
  }
  return FALSE;
}

void MainMenu::RequestMove(const gfx::Rect& new_bounds) {
  // Invoking PositionChild results in a gtk signal that triggers attempting to
  // to resize the window. We need to set the size request so that it resizes
  // correctly when this happens.
  gtk_widget_set_size_request(popup_->GetNativeView(),
                              new_bounds.width(), new_bounds.height());
  gfx::Size rwhv_size = CalculateRWHVSize(new_bounds.size());
  popup_->PositionChild(rwhv_->GetNativeView(), kRendererX, kRendererY,
                        rwhv_size.width(), rwhv_size.height());
  popup_->SetBounds(new_bounds);
  rwhv_->SetSize(rwhv_size);
}

RendererPreferences MainMenu::GetRendererPrefs(Profile* profile) const {
  return renderer_preferences_util::GetInitedRendererPreferences(profile);
}

void MainMenu::CreateNewWindow(int route_id) {
  if (pending_contents_.get()) {
    NOTREACHED();
    return;
  }

  helper_.CreateNewWindow(route_id, browser_->profile(), site_instance_,
                          DOMUIFactory::GetDOMUIType(GURL(GetMenuURL())),
                          NULL);
  pending_contents_.reset(helper_.GetCreatedWindow(route_id));
  pending_contents_->set_delegate(&tab_contents_delegate_);
}

void MainMenu::ShowCreatedWindow(int route_id,
                                 WindowOpenDisposition disposition,
                                 const gfx::Rect& initial_pos,
                                 bool user_gesture,
                                 const GURL& creator_url) {
  if (disposition == NEW_POPUP) {
    pending_contents_->set_delegate(NULL);
    browser_->GetSelectedTabContents()->AddNewContents(
        pending_contents_.release(), disposition, initial_pos, user_gesture,
        creator_url);
    Hide();
  }
}

void MainMenu::TabContentsDelegateImpl::OpenURLFromTab(
    TabContents* source,
    const GURL& url,
    const GURL& referrer,
    WindowOpenDisposition disposition,
    PageTransition::Type transition) {
  menu_->browser_->OpenURL(url, referrer, NEW_FOREGROUND_TAB,
                           PageTransition::LINK);
  menu_->Hide();
}

// LoadTask -------------------------------------------------------------------

void MainMenu::LoadTask::Run() {
  if (BrowserList::begin() == BrowserList::end())
    return;  // No browser are around. Generally only happens during testing.

  MainMenu::Get();
}

}  // namespace chromeos
<|endoftext|>


<commit_before>/*
    Copyright (c) 2006 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "itemdumper.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtGui/QApplication>

#include <kapplication.h>
#include <kcmdlineargs.h>

#include <libakonadi/collectionpathresolver.h>

using namespace Akonadi;

ItemDumper::ItemDumper( const QString &path, const QByteArray &filename, const QByteArray &mimetype )
{
  CollectionPathResolver* resolver = new CollectionPathResolver( path, this );
  Q_ASSERT( resolver->exec() );
  const Collection collection = Collection( resolver->collection() );

  QFile f( filename );
  Q_ASSERT( f.open(QIODevice::ReadOnly) );
  QByteArray data = f.readAll();
  f.close();
  Item item;
  item.setMimeType( mimetype );
  item.setPayload( data );
  ItemAppendJob *job = new ItemAppendJob( item, collection, this );
  connect( job, SIGNAL(result(KJob*)), SLOT(done(KJob*)) );
  job->start();
}

void ItemDumper::done( KJob * job )
{
  if ( job->error() ) {
    qWarning() << "Error while creating item: " << job->errorString();
  } else {
    qDebug() << "Done!";
  }
  qApp->quit();
}

static KCmdLineOptions options[] =
{
  { "path <argument>", "IMAP destination path", 0 },
  { "mimetype <argument>", "Source mimetype", 0 },
  { "file <argument>", "Source file", 0 },
  KCmdLineLastOption
};

int main( int argc, char** argv )
{
  KCmdLineArgs::init( argc, argv, "test", "Test" ,"test app" ,"1.0" );
  KCmdLineArgs::addCmdLineOptions( options );
  KApplication app;
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QByteArray path = args->getOption( "path" );
  QByteArray mimetype = args->getOption( "mimetype" );
  QByteArray file = args->getOption( "file" );
  ItemDumper d( QString::fromUtf8( path ), file, mimetype );
  return app.exec();
}

#include "itemdumper.moc"
<commit_msg>work with all kinds of payloads<commit_after>/*
    Copyright (c) 2006 Volker Krause <vkrause@kde.org>

    This library is free software; you can redistribute it and/or modify it
    under the terms of the GNU Library General Public License as published by
    the Free Software Foundation; either version 2 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
    License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to the
    Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
    02110-1301, USA.
*/

#include "itemdumper.h"
#include <QtCore/QDebug>
#include <QtCore/QFile>
#include <QtGui/QApplication>

#include <kapplication.h>
#include <kcmdlineargs.h>

#include <libakonadi/collectionpathresolver.h>
#include <libakonadi/itemserializer.h>

using namespace Akonadi;

ItemDumper::ItemDumper( const QString &path, const QByteArray &filename, const QByteArray &mimetype )
{
  CollectionPathResolver* resolver = new CollectionPathResolver( path, this );
  Q_ASSERT( resolver->exec() );
  const Collection collection = Collection( resolver->collection() );

  QFile f( filename );
  Q_ASSERT( f.open(QIODevice::ReadOnly) );
  QByteArray data = f.readAll();
  f.close();
  Item item;
  item.setMimeType( mimetype );
  ItemSerializer::deserialize( item, Item::PartBody, data );
  ItemAppendJob *job = new ItemAppendJob( item, collection, this );
  connect( job, SIGNAL(result(KJob*)), SLOT(done(KJob*)) );
  job->start();
}

void ItemDumper::done( KJob * job )
{
  if ( job->error() ) {
    qWarning() << "Error while creating item: " << job->errorString();
  } else {
    qDebug() << "Done!";
  }
  qApp->quit();
}

static KCmdLineOptions options[] =
{
  { "path <argument>", "IMAP destination path", 0 },
  { "mimetype <argument>", "Source mimetype", 0 },
  { "file <argument>", "Source file", 0 },
  KCmdLineLastOption
};

int main( int argc, char** argv )
{
  KCmdLineArgs::init( argc, argv, "test", "Test" ,"test app" ,"1.0" );
  KCmdLineArgs::addCmdLineOptions( options );
  KApplication app;
  KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
  QByteArray path = args->getOption( "path" );
  QByteArray mimetype = args->getOption( "mimetype" );
  QByteArray file = args->getOption( "file" );
  ItemDumper d( QString::fromUtf8( path ), file, mimetype );
  return app.exec();
}

#include "itemdumper.moc"
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        (    0, uint256("0x00000000804bbc6a621a9dbb564ce469f492e1ccf2d70f8a6b241e26a277afa2"))
        (    1, uint256("0x000000000fbc1c60a7610c894f98d102390e9e00cc18caced4eb4198ec0c3645"))
        (   31, uint256("0x00000000045341e3ebdfa180e4a0f1e4da23829609517a3673b4a796714a7593"))
        (  104, uint256("0x000000006afe30806352f2015829527dd91f19fbc2d28f799c3ad61c37746fdb"))
        (  355, uint256("0x0000000000c0e178ddd6a8f15724f37470428c233883c302267299b21fb5d237"))
        (  721, uint256("0x00000000027671a417f3d3eafac6d150f0b2ccba37f0b63f75bc657ec25950ed"))
        ( 2000, uint256("0x000000000283ecd683fe30d4542929a78873df7818029793f84e9c65dc337d94"))
        ( 3000, uint256("0x0000000000317b69ff2a56284442fede7ffa66f75d000f1cf34171ad671db4b6"))
        ( 4000, uint256("0x00000000001190cad5d66d028b6afcf22db58d2b5c17abf2bf2e1353be13097d"))
        ( 4255, uint256("0x000000000018b3ba5b241f3e88b4a88e580f9e7dd0fc7fc786ff22c586e53dd9"))
        ( 5631, uint256("0x00000000001243509866938e344c0010bd88b156da27ef9d707cb1f1698f2a32"))
        ( 6000, uint256("0x00000000000c1abfd7c29d07e23ef52631c6874e42e6a240a4d3678d9c716d81"))
        ( 7395, uint256("0x0000000000005d8e1281d6b28fe6b504ab81e7e3ec561e97b7a98973e449f7fb"))
        ( 8001, uint256("0x00000000001ca63707536b6dfc8ba4c5aa7fce19b6295ef73e195554cdb92d44"))
        ( 8157, uint256("0x00000000001303998da2714abf02159f1421103e77fee3b876d69c0fa7b108d9"))
        (12311, uint256("0x00000000002b5708fefdceb5db42cd2135eaf23f23a95c285e8f310262f8d639"))
        (13224, uint256("0x00000000000765c69f777ccbc44fab23edab9126f1b4ec5078450aebc3809c36"))
        (14401, uint256("0x0000000000388541b88c57883a480fd6cfa7b93f68e0c71538b08b2c4d875fa2"))
        (15238, uint256("0x000000000000ae09d46bc1a9c5ca4c7b5e51bf23d3108926daa140d64355d390"))
        (18426, uint256("0x00000000001fb1c075dbfa27f7ba83928a2d35152ccae59c742f698fb8cb8108"))
        (19114, uint256("0x000000000022224f57adecffdc8f5cffb3b932838310aefdd12aaabcc6122259"))
        (20124, uint256("0x00000000002374e0e1fcee28b520dff3f3e86cb7ff7afdea112aaf2002101900"))
        (21711, uint256("0x00000000002189b0ae139b8c449bbcb99d520b8a798b7e0f0ff8ab8539e9bcb4"))
        (22100, uint256("0x0000000000142ace7d8db003da69191896986c5564e604e3100d14c17daaf90f"))
        (22566, uint256("0x00000000000c28dc052d277d18e104e4e63c53e4018273b3af49f772af205d43"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<commit_msg>[checkpoints] minor: 24076 checkpoint added.<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        (    0, uint256("0x00000000804bbc6a621a9dbb564ce469f492e1ccf2d70f8a6b241e26a277afa2"))
        (    1, uint256("0x000000000fbc1c60a7610c894f98d102390e9e00cc18caced4eb4198ec0c3645"))
        (   31, uint256("0x00000000045341e3ebdfa180e4a0f1e4da23829609517a3673b4a796714a7593"))
        (  104, uint256("0x000000006afe30806352f2015829527dd91f19fbc2d28f799c3ad61c37746fdb"))
        (  355, uint256("0x0000000000c0e178ddd6a8f15724f37470428c233883c302267299b21fb5d237"))
        (  721, uint256("0x00000000027671a417f3d3eafac6d150f0b2ccba37f0b63f75bc657ec25950ed"))
        ( 2000, uint256("0x000000000283ecd683fe30d4542929a78873df7818029793f84e9c65dc337d94"))
        ( 3000, uint256("0x0000000000317b69ff2a56284442fede7ffa66f75d000f1cf34171ad671db4b6"))
        ( 4000, uint256("0x00000000001190cad5d66d028b6afcf22db58d2b5c17abf2bf2e1353be13097d"))
        ( 4255, uint256("0x000000000018b3ba5b241f3e88b4a88e580f9e7dd0fc7fc786ff22c586e53dd9"))
        ( 5631, uint256("0x00000000001243509866938e344c0010bd88b156da27ef9d707cb1f1698f2a32"))
        ( 6000, uint256("0x00000000000c1abfd7c29d07e23ef52631c6874e42e6a240a4d3678d9c716d81"))
        ( 7395, uint256("0x0000000000005d8e1281d6b28fe6b504ab81e7e3ec561e97b7a98973e449f7fb"))
        ( 8001, uint256("0x00000000001ca63707536b6dfc8ba4c5aa7fce19b6295ef73e195554cdb92d44"))
        ( 8157, uint256("0x00000000001303998da2714abf02159f1421103e77fee3b876d69c0fa7b108d9"))
        (12311, uint256("0x00000000002b5708fefdceb5db42cd2135eaf23f23a95c285e8f310262f8d639"))
        (13224, uint256("0x00000000000765c69f777ccbc44fab23edab9126f1b4ec5078450aebc3809c36"))
        (14401, uint256("0x0000000000388541b88c57883a480fd6cfa7b93f68e0c71538b08b2c4d875fa2"))
        (15238, uint256("0x000000000000ae09d46bc1a9c5ca4c7b5e51bf23d3108926daa140d64355d390"))
        (18426, uint256("0x00000000001fb1c075dbfa27f7ba83928a2d35152ccae59c742f698fb8cb8108"))
        (19114, uint256("0x000000000022224f57adecffdc8f5cffb3b932838310aefdd12aaabcc6122259"))
        (20124, uint256("0x00000000002374e0e1fcee28b520dff3f3e86cb7ff7afdea112aaf2002101900"))
        (21711, uint256("0x00000000002189b0ae139b8c449bbcb99d520b8a798b7e0f0ff8ab8539e9bcb4"))
        (22100, uint256("0x0000000000142ace7d8db003da69191896986c5564e604e3100d14c17daaf90f"))
        (22566, uint256("0x00000000000c28dc052d277d18e104e4e63c53e4018273b3af49f772af205d43"))
        (24076, uint256("0x00000000000522702c7f0ee6fa2ce3978cc0f3056ecc73d8cde1035891c5c4d5"))
        ;

    static MapCheckpoints mapCheckpointsTestnet =
        boost::assign::map_list_of
        ( 546, uint256("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        MapCheckpoints::const_iterator i = checkpoints.find(nHeight);
        if (i == checkpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        return checkpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        MapCheckpoints& checkpoints = (fTestNet ? mapCheckpointsTestnet : mapCheckpoints);

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, checkpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        (     0, uint256("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca28fea9b86e9c"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        if (fTestNet) return true; // Testnet has no checkpoints

        MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
        if (i == mapCheckpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        if (fTestNet) return 0;

        return mapCheckpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        if (fTestNet) return NULL;

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<commit_msg>Added checkpoints.<commit_after>// Copyright (c) 2009-2012 The Bitcoin developers
// Copyright (c) 2011-2012 Litecoin Developers
// Copyright (c) 2013 CasinoCoin Developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <boost/assign/list_of.hpp> // for 'map_list_of()'
#include <boost/foreach.hpp>

#include "checkpoints.h"

#include "main.h"
#include "uint256.h"

namespace Checkpoints
{
    typedef std::map<int, uint256> MapCheckpoints;

    //
    // What makes a good checkpoint block?
    // + Is surrounded by blocks with reasonable timestamps
    //   (no blocks before with a timestamp after, none after with
    //    timestamp before)
    // + Contains no strange transactions
    //
    static MapCheckpoints mapCheckpoints =
        boost::assign::map_list_of
        (     0, uint256("0x4f46c9af6d88a14114b7dc53a37d81ba4064cda5ae2ede1213ca28fea9b86e9c"))
	    (     1, uint256("0xd6eea1064e9292f2a38e138bec64797914cff3189fbc6eaa2cc646c1514ccdfe"))
	    (     777, uint256("0x838c9d331811479957009c39d2e1e723d47ebd21453b3ad92bcabd6cb5dd6ab1"))
	    (     7777, uint256("0x09ab8471911e0f19e19ef09e1ae212b389f6be3e62f0c140d58c27084da08907"))
	    (     17777, uint256("0x4dd8c993bdb32b5ff63a1108f86b1cf2b6f3fb3e5a831d3445d944b986addadf"))
	    (     27777, uint256("0xea7623cc7d0db290b4f2bf5b1d5cbf477bf0c019b667d21dbc5e82e12adcf3ae"))
	    (     37777, uint256("0xced9dadf09278f513337ebbeee11804b794faddf8f759e583a1e39b0839c238a"))
        ;

    bool CheckBlock(int nHeight, const uint256& hash)
    {
        if (fTestNet) return true; // Testnet has no checkpoints

        MapCheckpoints::const_iterator i = mapCheckpoints.find(nHeight);
        if (i == mapCheckpoints.end()) return true;
        return hash == i->second;
    }

    int GetTotalBlocksEstimate()
    {
        if (fTestNet) return 0;

        return mapCheckpoints.rbegin()->first;
    }

    CBlockIndex* GetLastCheckpoint(const std::map<uint256, CBlockIndex*>& mapBlockIndex)
    {
        if (fTestNet) return NULL;

        BOOST_REVERSE_FOREACH(const MapCheckpoints::value_type& i, mapCheckpoints)
        {
            const uint256& hash = i.second;
            std::map<uint256, CBlockIndex*>::const_iterator t = mapBlockIndex.find(hash);
            if (t != mapBlockIndex.end())
                return t->second;
        }
        return NULL;
    }
}
<|endoftext|>


<commit_before>#include "dump_reader.hpp"

#include <cstdio>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <leveldb/db.h>
#include <leveldb/options.h>
#include <leveldb/write_batch.h>

#define BATCH_SIZE (10240)

namespace {

struct process
  : public boost::noncopyable {
  explicit process(const std::string &cmd)
    : m_fh(popen(cmd.c_str(), "r")) {
    if (m_fh == NULL) {
      throw std::runtime_error((boost::format("Unable to popen `%1%'.") % cmd).str());
    }
  }

  ~process() {
    if (pclose(m_fh) == -1) {
      std::cerr << "ERROR while closing popen." << std::endl;
      abort();
    }
  }

  size_t read(char *buf, size_t len) {
    size_t n = fread(buf, 1, len, m_fh);
    if (ferror(m_fh) != 0) {
      throw std::runtime_error("Error reading from popen stream.");
    }
    return n;
  }

private:
  FILE *m_fh;
};

template <typename T>
struct to_line_filter
  : public boost::noncopyable {
  to_line_filter(T &source, size_t buffer_size)
    : m_source(source),
      m_buffer(buffer_size, '\0'),
      m_buffer_pos(m_buffer.begin()),
      m_buffer_end(m_buffer_pos) {
  }

  ~to_line_filter() {
  }

  size_t read(std::string &line) {
    line.clear();
    std::string::iterator begin_pos = m_buffer_pos;
    char c = '\0';

    do {
      if (m_buffer_pos == m_buffer_end) {
        line.append(begin_pos, m_buffer_pos);
        if (refill() == 0) {
          return 0;
        }
        begin_pos = m_buffer_pos;
      }

      c = *m_buffer_pos;
      if (c != '\n') {
        ++m_buffer_pos;
      }
    } while (c != '\n');

    line.append(begin_pos, m_buffer_pos);
    ++m_buffer_pos;

    return 1;
  }

private:
  size_t refill() {
    size_t bytes = 0;
    while (bytes < m_buffer.size()) {
      size_t len = m_source.read(&m_buffer[bytes], m_buffer.size() - bytes);
      if (len == 0) {
        break;
      }
      bytes += len;
    }
    m_buffer_pos = m_buffer.begin();
    m_buffer_end = m_buffer.begin() + bytes;
    return bytes;
  }

  T &m_source;
  std::string m_buffer;
  std::string::iterator m_buffer_pos, m_buffer_end;
};

template <typename T>
struct filter_copy_contents
  : public boost::noncopyable {
  explicit filter_copy_contents(T &source)
  : m_source(source),
    m_in_copy(false),
    m_start_prefix("COPY "),
    m_end_line("\\.") {
  }

  ~filter_copy_contents() {
  }

  size_t read(std::string &line) {
    size_t got_data = 0;
    do {
      got_data = m_source.read(line);

      if (got_data == 0) {
        break;
      }

      if (!m_in_copy && (line.compare(0, m_start_prefix.size(), m_start_prefix) == 0)) {
        m_in_copy = true;
        got_data = m_source.read(line);
      }

      if (m_in_copy && (line.compare(m_end_line) == 0)) {
        m_in_copy = false;
      }
    } while (!m_in_copy);

    return got_data;
  }

private:
  T &m_source;
  bool m_in_copy;
  const std::string m_start_prefix, m_end_line;
};

} // anonymous namespace

struct dump_reader::pimpl {
  pimpl(const std::string &cmd, const std::string &table_name)
    : m_proc(cmd),
      m_line_filter(m_proc, 1024 * 1024),
      m_cont_filter(m_line_filter),
      m_db(NULL),
      m_batch(),
      m_batch_size(0),
      m_write_options() {

    leveldb::Options options;
    options.create_if_missing = true;
    options.error_if_exists = true;

    // bigger write buffer, as this is a write-heavy process...
    options.write_buffer_size = 128 * 1024 * 1024;

    leveldb::Status status = leveldb::DB::Open(options, table_name, &m_db);
    if (!status.ok()) {
      throw std::runtime_error((boost::format("Can't open database: %1%") % status.ToString()).str());
    }
  }

  ~pimpl() {
    m_db->CompactRange(NULL, NULL);
    delete m_db;
  }

  void put(const std::string &k, const std::string &v) {
    m_batch.Put(k, v);
    ++m_batch_size;

    if (m_batch_size >= BATCH_SIZE) {
      m_db->Write(m_write_options, &m_batch);
      m_batch.Clear();
      m_batch_size = 0;
    }
  }

  process m_proc;
  to_line_filter<process> m_line_filter;
  filter_copy_contents<to_line_filter<process> > m_cont_filter;

  leveldb::DB *m_db;
  leveldb::WriteBatch m_batch;
  size_t m_batch_size;
  leveldb::WriteOptions m_write_options;
};

dump_reader::dump_reader(const std::string &table_name,
                         const std::string &dump_file)
  : m_impl() {
  std::ostringstream cmd;
  cmd << "pg_restore -a -t " << table_name << " " << dump_file;
  m_impl.reset(new pimpl(cmd.str(), table_name));
}

dump_reader::~dump_reader() {
}

size_t dump_reader::read(std::string &line) {
  return m_impl->m_cont_filter.read(line);
}

void dump_reader::put(const std::string &k, const std::string &v) {
  m_impl->put(k, v);
}
<commit_msg>Flush batch on finish.<commit_after>#include "dump_reader.hpp"

#include <cstdio>
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <boost/noncopyable.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

#include <leveldb/db.h>
#include <leveldb/options.h>
#include <leveldb/write_batch.h>

#define BATCH_SIZE (10240)

namespace {

struct process
  : public boost::noncopyable {
  explicit process(const std::string &cmd)
    : m_fh(popen(cmd.c_str(), "r")) {
    if (m_fh == NULL) {
      throw std::runtime_error((boost::format("Unable to popen `%1%'.") % cmd).str());
    }
  }

  ~process() {
    if (pclose(m_fh) == -1) {
      std::cerr << "ERROR while closing popen." << std::endl;
      abort();
    }
  }

  size_t read(char *buf, size_t len) {
    size_t n = fread(buf, 1, len, m_fh);
    if (ferror(m_fh) != 0) {
      throw std::runtime_error("Error reading from popen stream.");
    }
    return n;
  }

private:
  FILE *m_fh;
};

template <typename T>
struct to_line_filter
  : public boost::noncopyable {
  to_line_filter(T &source, size_t buffer_size)
    : m_source(source),
      m_buffer(buffer_size, '\0'),
      m_buffer_pos(m_buffer.begin()),
      m_buffer_end(m_buffer_pos) {
  }

  ~to_line_filter() {
  }

  size_t read(std::string &line) {
    line.clear();
    std::string::iterator begin_pos = m_buffer_pos;
    char c = '\0';

    do {
      if (m_buffer_pos == m_buffer_end) {
        line.append(begin_pos, m_buffer_pos);
        if (refill() == 0) {
          return 0;
        }
        begin_pos = m_buffer_pos;
      }

      c = *m_buffer_pos;
      if (c != '\n') {
        ++m_buffer_pos;
      }
    } while (c != '\n');

    line.append(begin_pos, m_buffer_pos);
    ++m_buffer_pos;

    return 1;
  }

private:
  size_t refill() {
    size_t bytes = 0;
    while (bytes < m_buffer.size()) {
      size_t len = m_source.read(&m_buffer[bytes], m_buffer.size() - bytes);
      if (len == 0) {
        break;
      }
      bytes += len;
    }
    m_buffer_pos = m_buffer.begin();
    m_buffer_end = m_buffer.begin() + bytes;
    return bytes;
  }

  T &m_source;
  std::string m_buffer;
  std::string::iterator m_buffer_pos, m_buffer_end;
};

template <typename T>
struct filter_copy_contents
  : public boost::noncopyable {
  explicit filter_copy_contents(T &source)
  : m_source(source),
    m_in_copy(false),
    m_start_prefix("COPY "),
    m_end_line("\\.") {
  }

  ~filter_copy_contents() {
  }

  size_t read(std::string &line) {
    size_t got_data = 0;
    do {
      got_data = m_source.read(line);

      if (got_data == 0) {
        break;
      }

      if (!m_in_copy && (line.compare(0, m_start_prefix.size(), m_start_prefix) == 0)) {
        m_in_copy = true;
        got_data = m_source.read(line);
      }

      if (m_in_copy && (line.compare(m_end_line) == 0)) {
        m_in_copy = false;
      }
    } while (!m_in_copy);

    return got_data;
  }

private:
  T &m_source;
  bool m_in_copy;
  const std::string m_start_prefix, m_end_line;
};

} // anonymous namespace

struct dump_reader::pimpl {
  pimpl(const std::string &cmd, const std::string &table_name)
    : m_proc(cmd),
      m_line_filter(m_proc, 1024 * 1024),
      m_cont_filter(m_line_filter),
      m_db(NULL),
      m_batch(),
      m_batch_size(0),
      m_write_options() {

    leveldb::Options options;
    options.create_if_missing = true;
    options.error_if_exists = true;

    // bigger write buffer, as this is a write-heavy process...
    options.write_buffer_size = 128 * 1024 * 1024;

    leveldb::Status status = leveldb::DB::Open(options, table_name, &m_db);
    if (!status.ok()) {
      throw std::runtime_error((boost::format("Can't open database: %1%") % status.ToString()).str());
    }
  }

  ~pimpl() {
    if (m_batch_size > 0) {
      m_db->Write(m_write_options, &m_batch);
      m_batch.Clear();
      m_batch_size = 0;
    }
    m_db->CompactRange(NULL, NULL);
    delete m_db;
  }

  void put(const std::string &k, const std::string &v) {
    m_batch.Put(k, v);
    ++m_batch_size;

    if (m_batch_size >= BATCH_SIZE) {
      m_db->Write(m_write_options, &m_batch);
      m_batch.Clear();
      m_batch_size = 0;
    }
  }

  process m_proc;
  to_line_filter<process> m_line_filter;
  filter_copy_contents<to_line_filter<process> > m_cont_filter;

  leveldb::DB *m_db;
  leveldb::WriteBatch m_batch;
  size_t m_batch_size;
  leveldb::WriteOptions m_write_options;
};

dump_reader::dump_reader(const std::string &table_name,
                         const std::string &dump_file)
  : m_impl() {
  std::ostringstream cmd;
  cmd << "pg_restore -a -t " << table_name << " " << dump_file;
  m_impl.reset(new pimpl(cmd.str(), table_name));
}

dump_reader::~dump_reader() {
}

size_t dump_reader::read(std::string &line) {
  return m_impl->m_cont_filter.read(line);
}

void dump_reader::put(const std::string &k, const std::string &v) {
  m_impl->put(k, v);
}
<|endoftext|>


<commit_before>/*
    This file is part of libkcal.

    Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <stdlib.h>

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>

#include <kdebug.h>

#include "calendar.h"
#include "vcaldrag.h"
#include "vcalformat.h"
#include "icalformat.h"

#include "filestorage.h"

using namespace KCal;

FileStorage::FileStorage( Calendar *cal, const QString &fileName,
                            CalFormat *format )
  : CalStorage( cal ),
    mFileName( fileName ),
    mSaveFormat( format )
{
}

FileStorage::~FileStorage()
{
  delete mSaveFormat;
}

void FileStorage::setFileName( const QString &fileName )
{
  mFileName = fileName;
}

QString FileStorage::fileName()const
{
  return mFileName;
}

void FileStorage::setSaveFormat( CalFormat *format )
{
  delete mSaveFormat;
  mSaveFormat = format;
}

CalFormat *FileStorage::saveFormat()const
{
  return mSaveFormat;
}

bool FileStorage::open()
{
  return true;
}

bool FileStorage::load()
{
//  kdDebug(5800) << "FileStorage::load(): '" << mFileName << "'" << endl;

  // do we want to silently accept this, or make some noise?  Dunno...
  // it is a semantical thing vs. a practical thing.
  if (mFileName.isEmpty()) return false;

  // Always try to load with iCalendar. It will detect, if it is actually a
  // vCalendar file.
  bool success;
  // First try the supplied format. Otherwise fall through to iCalendar, then
  // to vCalendar
  success = saveFormat() && saveFormat()->load( calendar(), mFileName );
  if ( !success ) {
    ICalFormat iCal;

    success = iCal.load( calendar(), mFileName);
    if ( !success ) {
      if ( iCal.exception() ) {
//        kdDebug(5800) << "---Error: " << mFormat->exception()->errorCode() << endl;
        if ( iCal.exception()->errorCode() == ErrorFormat::CalVersion1 ) {
          // Expected non vCalendar file, but detected vCalendar
          kdDebug(5800) << "FileStorage::load() Fallback to VCalFormat" << endl;
          VCalFormat vCal;
          success = vCal.load( calendar(), mFileName );
          calendar()->setProductId( vCal.productId() );
        } else {
          return false;
        }
      } else {
        kdDebug(5800) << "Warning! There should be set an exception." << endl;
        return false;
      }
    } else {
//     kdDebug(5800) << "---Success" << endl;
      calendar()->setProductId( iCal.loadedProductId() );
    }
  }

  calendar()->setModified( false );

  return true;
}

bool FileStorage::save()
{
  if ( mFileName.isEmpty() ) return false;

  CalFormat *format = 0;
  if ( mSaveFormat ) format = mSaveFormat;
  else format = new ICalFormat;

  bool success = format->save( calendar(), mFileName );

  if ( success ) {
    calendar()->setModified( false );
  } else {
    if ( !format->exception() ) {
      kdDebug(5800) << "FileStorage::save(): Error. There should be set an exception."
                << endl;
    } else {
      kdDebug(5800) << "FileStorage::save(): " << format->exception()->message()
                << endl;
    }
  }

  if ( !mSaveFormat ) delete format;

  return success;
}

bool FileStorage::close()
{
  return true;
}
<commit_msg>minor.<commit_after>/*
    This file is part of libkcal.

    Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/

#include <stdlib.h>

#include <qdatetime.h>
#include <qstring.h>
#include <qptrlist.h>

#include <kdebug.h>

#include "calendar.h"
#include "vcaldrag.h"
#include "vcalformat.h"
#include "icalformat.h"

#include "filestorage.h"

using namespace KCal;

FileStorage::FileStorage( Calendar *cal, const QString &fileName,
                            CalFormat *format )
  : CalStorage( cal ),
    mFileName( fileName ),
    mSaveFormat( format )
{
}

FileStorage::~FileStorage()
{
  delete mSaveFormat;
}

void FileStorage::setFileName( const QString &fileName )
{
  mFileName = fileName;
}

QString FileStorage::fileName()const
{
  return mFileName;
}

void FileStorage::setSaveFormat( CalFormat *format )
{
  delete mSaveFormat;
  mSaveFormat = format;
}

CalFormat *FileStorage::saveFormat()const
{
  return mSaveFormat;
}

bool FileStorage::open()
{
  return true;
}

bool FileStorage::load()
{
//  kdDebug(5800) << "FileStorage::load(): '" << mFileName << "'" << endl;

  // do we want to silently accept this, or make some noise?  Dunno...
  // it is a semantical thing vs. a practical thing.
  if (mFileName.isEmpty()) return false;

  // Always try to load with iCalendar. It will detect, if it is actually a
  // vCalendar file.
  bool success;
  // First try the supplied format. Otherwise fall through to iCalendar, then
  // to vCalendar
  success = saveFormat() && saveFormat()->load( calendar(), mFileName );
  if ( !success ) {
    ICalFormat iCal;

    success = iCal.load( calendar(), mFileName);
    if ( !success ) {
      if ( iCal.exception() ) {
//        kdDebug(5800) << "---Error: " << mFormat->exception()->errorCode() << endl;
        if ( iCal.exception()->errorCode() == ErrorFormat::CalVersion1 ) {
          // Expected non vCalendar file, but detected vCalendar
          kdDebug(5800) << "FileStorage::load() Fallback to VCalFormat" << endl;
          VCalFormat vCal;
          success = vCal.load( calendar(), mFileName );
          calendar()->setProductId( vCal.productId() );
        } else {
          return false;
        }
      } else {
        kdDebug(5800) << "Warning! There should be an exception set." << endl;
        return false;
      }
    } else {
//     kdDebug(5800) << "---Success" << endl;
      calendar()->setProductId( iCal.loadedProductId() );
    }
  }

  calendar()->setModified( false );

  return true;
}

bool FileStorage::save()
{
  if ( mFileName.isEmpty() ) return false;

  CalFormat *format = 0;
  if ( mSaveFormat ) format = mSaveFormat;
  else format = new ICalFormat;

  bool success = format->save( calendar(), mFileName );

  if ( success ) {
    calendar()->setModified( false );
  } else {
    if ( !format->exception() ) {
      kdDebug(5800) << "FileStorage::save(): Error. There should be an exception set."
                << endl;
    } else {
      kdDebug(5800) << "FileStorage::save(): " << format->exception()->message()
                << endl;
    }
  }

  if ( !mSaveFormat ) delete format;

  return success;
}

bool FileStorage::close()
{
  return true;
}
<|endoftext|>