X-Git-Url: https://git.mdrn.pl/wl-app.git/blobdiff_plain/53b27422d140022594fc241cca91c3183be57bca..48b2fe9f7c2dc3d9aeaaa6dbfb27c7da4f3235ff:/iOS/Pods/Realm/include/core/realm/util/encrypted_file_mapping.hpp diff --git a/iOS/Pods/Realm/include/core/realm/util/encrypted_file_mapping.hpp b/iOS/Pods/Realm/include/core/realm/util/encrypted_file_mapping.hpp new file mode 100644 index 0000000..e110e97 --- /dev/null +++ b/iOS/Pods/Realm/include/core/realm/util/encrypted_file_mapping.hpp @@ -0,0 +1,176 @@ +/************************************************************************* + * + * Copyright 2016 Realm Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + **************************************************************************/ + +#ifndef REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP +#define REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP + +#include +#include +#include + +#if REALM_ENABLE_ENCRYPTION + +typedef size_t (*Header_to_size)(const char* addr); + +#include + +namespace realm { +namespace util { + +struct SharedFileInfo; +class EncryptedFileMapping; + +class EncryptedFileMapping { +public: + // Adds the newly-created object to file.mappings iff it's successfully constructed + EncryptedFileMapping(SharedFileInfo& file, size_t file_offset, void* addr, size_t size, File::AccessMode access); + ~EncryptedFileMapping(); + + // Default implementations of copy/assign can trigger multiple destructions + EncryptedFileMapping(const EncryptedFileMapping&) = delete; + EncryptedFileMapping& operator=(const EncryptedFileMapping&) = delete; + + // Write all dirty pages to disk and mark them read-only + // Does not call fsync + void flush() noexcept; + + // Sync this file to disk + void sync() noexcept; + + // Make sure that memory in the specified range is synchronized with any + // changes made globally visible through call to write_barrier + void read_barrier(const void* addr, size_t size, UniqueLock& lock, Header_to_size header_to_size); + + // Ensures that any changes made to memory in the specified range + // becomes visible to any later calls to read_barrier() + void write_barrier(const void* addr, size_t size) noexcept; + + // Set this mapping to a new address and size + // Flushes any remaining dirty pages from the old mapping + void set(void* new_addr, size_t new_size, size_t new_file_offset); + + bool contains_page(size_t page_in_file) const; + size_t get_local_index_of_address(const void* addr, size_t offset = 0) const; + +private: + SharedFileInfo& m_file; + + size_t m_page_shift; + size_t m_blocks_per_page; + + void* m_addr = nullptr; + + size_t m_first_page; + + // MUST be of type char because of coherence issues when writing inside mutex and reading outside + // it. FIXME: We're investigating if this is good enough, or if we need further mechanisms + std::vector m_up_to_date_pages; + std::vector m_dirty_pages; + + File::AccessMode m_access; + +#ifdef REALM_DEBUG + std::unique_ptr m_validate_buffer; +#endif + + char* page_addr(size_t local_page_ndx) const noexcept; + + void mark_outdated(size_t local_page_ndx) noexcept; + bool copy_up_to_date_page(size_t local_page_ndx) noexcept; + void refresh_page(size_t local_page_ndx); + void write_page(size_t local_page_ndx) noexcept; + + void validate_page(size_t local_page_ndx) noexcept; + void validate() noexcept; +}; + +inline size_t EncryptedFileMapping::get_local_index_of_address(const void* addr, size_t offset) const +{ + REALM_ASSERT_EX(addr >= m_addr, addr, m_addr); + + size_t local_ndx = ((reinterpret_cast(addr) - reinterpret_cast(m_addr) + offset) >> m_page_shift); + REALM_ASSERT_EX(local_ndx < m_up_to_date_pages.size(), local_ndx, m_up_to_date_pages.size()); + return local_ndx; +} + +inline bool EncryptedFileMapping::contains_page(size_t page_in_file) const +{ + // first check for (page_in_file >= m_first_page) so that the following + // subtraction using unsigned types never wraps under 0 + return page_in_file >= m_first_page && page_in_file - m_first_page < m_up_to_date_pages.size(); +} + +inline void EncryptedFileMapping::read_barrier(const void* addr, size_t size, UniqueLock& lock, + Header_to_size header_to_size) +{ + size_t first_accessed_local_page = get_local_index_of_address(addr); + + // make sure the first page is available + // Checking before taking the lock is important to performance. + if (!m_up_to_date_pages[first_accessed_local_page]) { + if (!lock.holds_lock()) + lock.lock(); + // after taking the lock, we must repeat the check so that we never + // call refresh_page() on a page which is already up to date. + if (!m_up_to_date_pages[first_accessed_local_page]) + refresh_page(first_accessed_local_page); + } + + if (header_to_size) { + + // We know it's an array, and array headers are 8-byte aligned, so it is + // included in the first page which was handled above. + size = header_to_size(static_cast(addr)); + } + + size_t last_idx = get_local_index_of_address(addr, size == 0 ? 0 : size - 1); + size_t up_to_date_pages_size = m_up_to_date_pages.size(); + + // We already checked first_accessed_local_page above, so we start the loop + // at first_accessed_local_page + 1 to check the following page. + for (size_t idx = first_accessed_local_page + 1; idx <= last_idx && idx < up_to_date_pages_size; ++idx) { + if (!m_up_to_date_pages[idx]) { + if (!lock.holds_lock()) + lock.lock(); + // after taking the lock, we must repeat the check so that we never + // call refresh_page() on a page which is already up to date. + if (!m_up_to_date_pages[idx]) + refresh_page(idx); + } + } +} +} +} + +#endif // REALM_ENABLE_ENCRYPTION + +namespace realm { +namespace util { + +/// Thrown by EncryptedFileMapping if a file opened is non-empty and does not +/// contain valid encrypted data +struct DecryptionFailed : util::File::AccessError { + DecryptionFailed() + : util::File::AccessError("Decryption failed", std::string()) + { + } +}; +} +} + +#endif // REALM_UTIL_ENCRYPTED_FILE_MAPPING_HPP