<commit_before>// Copyright (c) 2019 by <NAME>. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/shared_memory_object/shared_memory.hpp"
#include "iceoryx_hoofs/cxx/generic_raii.hpp"
#include "iceoryx_hoofs/cxx/helplets.hpp"
#include "iceoryx_hoofs/platform/fcntl.hpp"
#include "iceoryx_hoofs/platform/mman.hpp"
#include "iceoryx_hoofs/platform/stat.hpp"
#include "iceoryx_hoofs/platform/types.hpp"
#include "iceoryx_hoofs/platform/unistd.hpp"
#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp"

#include <assert.h>
#include <bitset>
#include <limits>

namespace iox
{
namespace posix
{
SharedMemory::SharedMemory(const Name_t& name,
                           const AccessMode accessMode,
                           const Policy policy,
                           const mode_t permissions,
                           const uint64_t size) noexcept
{
    m_isInitialized = true;
    // on qnx the current working directory will be added to the /dev/shmem path if the leading slash is missing
    if (name.empty())
    {
        std::cerr << "No shared memory name specified!" << std::endl;
        m_isInitialized = false;
        m_errorValue = SharedMemoryError::EMPTY_NAME;
    }
    else if (name.c_str()[0] != '/')
    {
        std::cerr << "Shared memory name must start with a leading slash!" << std::endl;
        m_isInitialized = false;
        m_errorValue = SharedMemoryError::NAME_WITHOUT_LEADING_SLASH;
    }

    if (m_isInitialized)
    {
        m_name = name;
        m_isInitialized = open(accessMode, policy, permissions, size);
    }

    if (!m_isInitialized)
    {
        std::cerr << "Unable to create shared memory with the following properties [ name = " << name
                  << ", access mode = " << ACCESS_MODE_STRING[static_cast<uint64_t>(accessMode)]
                  << ", ownership = " << POLICY_STRING[static_cast<uint64_t>(policy)]
                  << ", mode = " << std::bitset<sizeof(mode_t)>(permissions) << ", sizeInBytes = " << size << " ]"
                  << std::endl;
        return;
    }
}

SharedMemory::~SharedMemory() noexcept
{
    destroy();
}

int SharedMemory::getOflagsFor(const AccessMode accessMode, const Policy policy) noexcept
{
    int oflags = 0;
    oflags |= (accessMode == AccessMode::READ_ONLY) ? O_RDONLY : O_RDWR;
    oflags |= (policy != Policy::OPEN) ? O_CREAT | O_EXCL : 0;
    return oflags;
}

void SharedMemory::destroy() noexcept
{
    if (m_isInitialized)
    {
        close();
        unlink();
        reset();
    }
}

void SharedMemory::reset() noexcept
{
    m_isInitialized = false;
    m_name = Name_t();
    m_handle = INVALID_HANDLE;
}

SharedMemory::SharedMemory(SharedMemory&& rhs) noexcept
{
    *this = std::move(rhs);
}

SharedMemory& SharedMemory::operator=(SharedMemory&& rhs) noexcept
{
    if (this != &rhs)
    {
        destroy();

        CreationPattern_t::operator=(std::move(rhs));

        m_name = rhs.m_name;
        m_hasOwnership = std::move(rhs.m_hasOwnership);
        m_handle = std::move(rhs.m_handle);

        rhs.reset();
    }
    return *this;
}

int32_t SharedMemory::getHandle() const noexcept
{
    return m_handle;
}

bool SharedMemory::hasOwnership() const noexcept
{
    return m_hasOwnership;
}

bool SharedMemory::open(const AccessMode accessMode,
                        const Policy policy,
                        const mode_t permissions,
                        const uint64_t size) noexcept
{
    cxx::Expects(size <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()));

    m_hasOwnership =
        (policy == Policy::EXCLUSIVE_CREATE || policy == Policy::PURGE_AND_CREATE || policy == Policy::OPEN_OR_CREATE);

    // the mask will be applied to the permissions, therefore we need to set it to 0
    mode_t umaskSaved = umask(0U);
    {
        cxx::GenericRAII umaskGuard([&] { umask(umaskSaved); });

        if (policy == Policy::PURGE_AND_CREATE)
        {
            IOX_DISCARD_RESULT(posixCall(shm_unlink)(m_name.c_str())
                                   .failureReturnValue(INVALID_HANDLE)
                                   .ignoreErrnos(ENOENT)
                                   .evaluate());
        }

        auto result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, policy), permissions)
                          .failureReturnValue(INVALID_HANDLE)
                          .suppressErrorMessagesForErrnos((policy == Policy::OPEN_OR_CREATE) ? EEXIST : 0)
                          .evaluate();
        if (result.has_error())
        {
            // if it was not possible to create the shm exclusively someone else has the
            // ownership and we just try to open it
            if (policy == Policy::OPEN_OR_CREATE && result.get_error().errnum == EEXIST)
            {
                result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, Policy::OPEN), permissions)
                             .failureReturnValue(INVALID_HANDLE)
                             .evaluate();
                if (!result.has_error())
                {
                    m_handle = result->value;
                    m_hasOwnership = false;
                    return true;
                }
            }

            m_errorValue = this->errnoToEnum(result.get_error().errnum);
            return false;
        }
        m_handle = result->value;
    }

    if (m_hasOwnership)
    {<commit_msg>iox-#33 Adjust ownership handling<commit_after>// Copyright (c) 2019 by <NAME> GmbH. All rights reserved.
// Copyright (c) 2021 by Apex.AI Inc. All rights reserved.
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0

#include "iceoryx_hoofs/internal/posix_wrapper/shared_memory_object/shared_memory.hpp"
#include "iceoryx_hoofs/cxx/generic_raii.hpp"
#include "iceoryx_hoofs/cxx/helplets.hpp"
#include "iceoryx_hoofs/platform/fcntl.hpp"
#include "iceoryx_hoofs/platform/mman.hpp"
#include "iceoryx_hoofs/platform/stat.hpp"
#include "iceoryx_hoofs/platform/types.hpp"
#include "iceoryx_hoofs/platform/unistd.hpp"
#include "iceoryx_hoofs/posix_wrapper/posix_call.hpp"

#include <assert.h>
#include <bitset>
#include <limits>

namespace iox
{
namespace posix
{
SharedMemory::SharedMemory(const Name_t& name,
                           const AccessMode accessMode,
                           const Policy policy,
                           const mode_t permissions,
                           const uint64_t size) noexcept
{
    m_isInitialized = true;
    // on qnx the current working directory will be added to the /dev/shmem path if the leading slash is missing
    if (name.empty())
    {
        std::cerr << "No shared memory name specified!" << std::endl;
        m_isInitialized = false;
        m_errorValue = SharedMemoryError::EMPTY_NAME;
    }
    else if (name.c_str()[0] != '/')
    {
        std::cerr << "Shared memory name must start with a leading slash!" << std::endl;
        m_isInitialized = false;
        m_errorValue = SharedMemoryError::NAME_WITHOUT_LEADING_SLASH;
    }

    if (m_isInitialized)
    {
        m_name = name;
        m_isInitialized = open(accessMode, policy, permissions, size);
    }

    if (!m_isInitialized)
    {
        std::cerr << "Unable to create shared memory with the following properties [ name = " << name
                  << ", access mode = " << ACCESS_MODE_STRING[static_cast<uint64_t>(accessMode)]
                  << ", policy = " << POLICY_STRING[static_cast<uint64_t>(policy)]
                  << ", mode = " << std::bitset<sizeof(mode_t)>(permissions) << ", sizeInBytes = " << size << " ]"
                  << std::endl;
        return;
    }
}

SharedMemory::~SharedMemory() noexcept
{
    destroy();
}

int SharedMemory::getOflagsFor(const AccessMode accessMode, const Policy policy) noexcept
{
    int oflags = 0;
    oflags |= (accessMode == AccessMode::READ_ONLY) ? O_RDONLY : O_RDWR;
    oflags |= (policy != Policy::OPEN) ? O_CREAT | O_EXCL : 0;
    return oflags;
}

void SharedMemory::destroy() noexcept
{
    if (m_isInitialized)
    {
        close();
        unlink();
        reset();
    }
}

void SharedMemory::reset() noexcept
{
    m_isInitialized = false;
    m_name = Name_t();
    m_handle = INVALID_HANDLE;
}

SharedMemory::SharedMemory(SharedMemory&& rhs) noexcept
{
    *this = std::move(rhs);
}

SharedMemory& SharedMemory::operator=(SharedMemory&& rhs) noexcept
{
    if (this != &rhs)
    {
        destroy();

        CreationPattern_t::operator=(std::move(rhs));

        m_name = rhs.m_name;
        m_hasOwnership = std::move(rhs.m_hasOwnership);
        m_handle = std::move(rhs.m_handle);

        rhs.reset();
    }
    return *this;
}

int32_t SharedMemory::getHandle() const noexcept
{
    return m_handle;
}

bool SharedMemory::hasOwnership() const noexcept
{
    return m_hasOwnership;
}

bool SharedMemory::open(const AccessMode accessMode,
                        const Policy policy,
                        const mode_t permissions,
                        const uint64_t size) noexcept
{
    cxx::Expects(size <= static_cast<uint64_t>(std::numeric_limits<int64_t>::max()));

    m_hasOwnership =
        (policy == Policy::EXCLUSIVE_CREATE || policy == Policy::PURGE_AND_CREATE || policy == Policy::OPEN_OR_CREATE);

    // the mask will be applied to the permissions, therefore we need to set it to 0
    mode_t umaskSaved = umask(0U);
    {
        cxx::GenericRAII umaskGuard([&] { umask(umaskSaved); });

        if (policy == Policy::PURGE_AND_CREATE)
        {
            IOX_DISCARD_RESULT(posixCall(shm_unlink)(m_name.c_str())
                                   .failureReturnValue(INVALID_HANDLE)
                                   .ignoreErrnos(ENOENT)
                                   .evaluate());
        }

        auto result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, policy), permissions)
                          .failureReturnValue(INVALID_HANDLE)
                          .suppressErrorMessagesForErrnos((policy == Policy::OPEN_OR_CREATE) ? EEXIST : 0)
                          .evaluate();
        if (result.has_error())
        {
            // if it was not possible to create the shm exclusively someone else has the
            // ownership and we just try to open it
            if (policy == Policy::OPEN_OR_CREATE && result.get_error().errnum == EEXIST)
            {
                m_hasOwnership = false;
                result = posixCall(iox_shm_open)(m_name.c_str(), getOflagsFor(accessMode, Policy::OPEN), permissions)
                             .failureReturnValue(INVALID_HANDLE)
                             .evaluate();
                if (!result.has_error())
                {
                    m_handle = result->value;
                    return true;
                }
            }

            m_errorValue = this->errnoToEnum(result.get_error().errnum);
            return false;
        }
        m_handle = result->value;
    }

    if (m_hasOwnership)
    {
{'fraction_non_alphanumeric': 0.1110016420361248, 'fraction_numerical': 0.005747126436781609, 'mean_word_length': 2.344590884129599, 'pattern_counts': {'":': 0, '<': 87, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 6, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1794831', 'n_tokens_mistral': 3708, 'n_tokens_neox': 3588, 'n_words': 850}