Skip to content

Commit

Permalink
Merge pull request #1968 from ApexAI/iox-1962-posix-file-wrapper
Browse files Browse the repository at this point in the history
Iox 1962 posix file wrapper
  • Loading branch information
elfenpiff authored Apr 17, 2023
2 parents 15da211 + 8a17931 commit e7b572b
Show file tree
Hide file tree
Showing 61 changed files with 1,644 additions and 36 deletions.
2 changes: 2 additions & 0 deletions iceoryx_hoofs/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ cc_library(
"filesystem/source/*.cpp",
"memory/source/*.cpp",
"posix/design/source/*.cpp",
"posix/filesystem/source/*.cpp",
"posix/time/source/*.cpp",
"posix/vocabulary/source/*.cpp",
"primitives/source/*.cpp",
Expand All @@ -56,6 +57,7 @@ cc_library(
"legacy/include/",
"memory/include/",
"posix/design/include/",
"posix/filesystem/include/",
"posix/time/include/",
"posix/vocabulary/include/",
"primitives/include/",
Expand Down
3 changes: 3 additions & 0 deletions iceoryx_hoofs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ iox_add_library(
${PROJECT_SOURCE_DIR}/reporting/include

${PROJECT_SOURCE_DIR}/posix/design/include
${PROJECT_SOURCE_DIR}/posix/filesystem/include
${PROJECT_SOURCE_DIR}/posix/time/include
${PROJECT_SOURCE_DIR}/posix/vocabulary/include

Expand All @@ -81,6 +82,7 @@ iox_add_library(
reporting/include/

posix/design/include/
posix/filesystem/include/
posix/time/include/
posix/vocabulary/include/
FILES
Expand Down Expand Up @@ -116,6 +118,7 @@ iox_add_library(
utility/source/unique_id.cpp

posix/design/source/file_management_interface.cpp
posix/filesystem/source/file.cpp
posix/time/source/adaptive_wait.cpp
posix/time/source/deadline_timer.cpp
posix/vocabulary/source/file_name.cpp
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,14 @@ class SharedMemoryObject : public FileManagementInterface<SharedMemoryObject>
/// existing shared memory was opened.
bool hasOwnership() const noexcept;


friend class SharedMemoryObjectBuilder;

private:
SharedMemoryObject(SharedMemory&& sharedMemory, MemoryMap&& memoryMap, const uint64_t memorySizeInBytes) noexcept;

friend struct FileManagementInterface<SharedMemoryObject>;
int get_file_handle() const noexcept;

private:
uint64_t m_memorySizeInBytes;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ inline constexpr const char* asStringLiteral(const AccessMode mode) noexcept
return "AccessMode::READ_ONLY";
case AccessMode::READ_WRITE:
return "AccessMode::READ_WRITE";
case AccessMode::WRITE_ONLY:
return "AccessMode::WRITE_ONLY";
}

return "AccessMode::UNDEFINED_VALUE";
Expand Down
7 changes: 6 additions & 1 deletion iceoryx_hoofs/include/iceoryx_hoofs/posix_wrapper/types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ namespace posix
enum class AccessMode : uint64_t
{
READ_ONLY = 0U,
READ_WRITE = 1U
READ_WRITE = 1U,
WRITE_ONLY = 2U
};

/// @brief describes how the shared memory is opened or created
Expand Down Expand Up @@ -57,6 +58,10 @@ int convertToOflags(const AccessMode accessMode) noexcept;
/// @param[in] openMode the openMode which should be converted
int convertToOflags(const OpenMode openMode) noexcept;

/// @brief converts the AccessMode into the corresponding PROT_** flags.
/// @param[in] accessMode the accessMode which should be converted
int convertToProtFlags(const AccessMode accessMode) noexcept;

/// @brief converts the AccessMode and OpenMode into the corresponding O_** flags
/// @param[in] accessMode the accessMode which should be converted
/// @param[in] openMode the openMode which should be converted
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ template <typename Derived>
inline expected<Ownership, FileStatError> FileManagementInterface<Derived>::get_ownership() const noexcept
{
const auto& derived_this = *static_cast<const Derived*>(this);
auto result = details::get_file_status(derived_this.getFileHandle());
auto result = details::get_file_status(derived_this.get_file_handle());
if (result.has_error())
{
return iox::error<FileStatError>(result.get_error());
Expand All @@ -37,7 +37,7 @@ template <typename Derived>
inline expected<access_rights, FileStatError> FileManagementInterface<Derived>::get_permissions() const noexcept
{
const auto& derived_this = *static_cast<const Derived*>(this);
auto result = details::get_file_status(derived_this.getFileHandle());
auto result = details::get_file_status(derived_this.get_file_handle());
if (result.has_error())
{
return iox::error<FileStatError>(result.get_error());
Expand All @@ -54,7 +54,7 @@ template <typename Derived>
inline expected<FileSetOwnerError> FileManagementInterface<Derived>::set_ownership(const Ownership ownership) noexcept
{
const auto& derived_this = *static_cast<const Derived*>(this);
auto result = details::set_owner(derived_this.getFileHandle(), ownership.uid(), ownership.gid());
auto result = details::set_owner(derived_this.get_file_handle(), ownership.uid(), ownership.gid());
if (result.has_error())
{
return iox::error<FileSetOwnerError>(result.get_error());
Expand All @@ -68,14 +68,27 @@ inline expected<FileSetPermissionError>
FileManagementInterface<Derived>::set_permissions(const access_rights permissions) noexcept
{
const auto& derived_this = *static_cast<const Derived*>(this);
auto result = details::set_permissions(derived_this.getFileHandle(), permissions);
auto result = details::set_permissions(derived_this.get_file_handle(), permissions);
if (result.has_error())
{
return iox::error<FileSetPermissionError>(result.get_error());
}

return iox::success<>();
}

template <typename Derived>
inline expected<uint64_t, FileStatError> FileManagementInterface<Derived>::get_size() const noexcept
{
const auto& derived_this = *static_cast<const Derived*>(this);
auto result = details::get_file_status(derived_this.get_file_handle());
if (result.has_error())
{
return iox::error<FileStatError>(result.get_error());
}

return iox::success<uint64_t>(static_cast<uint64_t>(result->st_size));
}
} // namespace iox

#endif
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ class Ownership
/// with existing user and group
static optional<Ownership> from_user_and_group(const UserName& user_name, const GroupName& group_name) noexcept;

/// @brief Returns the user and group owner of the current process.
static Ownership from_process() noexcept;

private:
template <typename>
friend struct FileManagementInterface;
Expand All @@ -96,13 +99,13 @@ class Ownership

/// @brief Abstract implementation to manage things common to all file descriptor
/// based constructs like ownership and permissions.
/// @note Can be used by every class which provide the method 'getFileHandle'
/// @note Can be used by every class which provides the method 'get_file_handle'
/// via inheritance.
/// @code
/// class MyResourceBasedOnFileDescriptor: public FileManagementInterface<MyResourceBasedOnFileDescriptor> {
/// public:
/// // must be implemented
/// int getFileHandle() const noexcept;
/// int get_file_handle() const noexcept;
/// };
/// @endcode
template <typename Derived>
Expand All @@ -125,6 +128,10 @@ struct FileManagementInterface
/// @param[in] permissions the new permissions of the file descriptor
/// @return On failure a 'FileSetPermissionError' describing the error.
expected<FileSetPermissionError> set_permissions(const access_rights permissions) noexcept;

/// @brief Returns the size of the corresponding file.
/// @return On failure a 'FileStatError' describing the error otherwise the size.
expected<uint64_t, FileStatError> get_size() const noexcept;
};
} // namespace iox

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,12 @@ optional<Ownership> Ownership::from_user_and_group(const UserName& user_name, co
return Ownership(user.getID(), group.getID());
}

Ownership Ownership::from_process() noexcept
{
return Ownership(posix::PosixUser::getUserOfCurrentProcess().getID(),
posix::PosixGroup::getGroupOfCurrentProcess().getID());
}

Ownership::Ownership(const uid_t uid, const gid_t gid) noexcept
: m_uid{uid}
, m_gid{gid}
Expand Down
193 changes: 193 additions & 0 deletions iceoryx_hoofs/posix/filesystem/include/iox/file.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
// Copyright (c) 2023 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/posix_wrapper/types.hpp"
#include "iox/builder.hpp"
#include "iox/file_management_interface.hpp"
#include "iox/file_path.hpp"
#include "iox/filesystem.hpp"

#ifndef IOX_HOOFS_POSIX_FILESYSTEM_FILE_HPP
#define IOX_HOOFS_POSIX_FILESYSTEM_FILE_HPP

namespace iox
{
/// @brief Describes failures which can occur when a file is opened or created.
enum class FileCreationError
{
PermissionDenied,
Interrupt,
IsDirectory,
TooManySymbolicLinksEncountered,
ProcessLimitOfOpenFileDescriptorsReached,
SystemLimitOfOpenFileDescriptorsReached,
DoesNotExist,
AlreadyExists,
InsufficientMemory,
FileTooLarge,
CurrentlyInUse,
CannotBePurged,
UnknownError
};

/// @brief Describes failures which can occur when a file is read.
enum class FileReadError
{
OffsetFailure,
Interrupt,
FileUnsuitableForReading,
IoFailure,
OperationWouldBlock,
IsDirectory,
NotOpenedForReading,
UnknownError
};

/// @brief Describes failures which can occur when a file is written to.
enum class FileWriteError
{
OffsetFailure,
OperationWouldBlock,
DiskQuotaExhausted,
FileSizeExceedsMaximumSupportedSize,
Interrupt,
FileUnsuitableForWriting,
IoFailure,
NoSpaceLeftOnDevice,
PreventedByFileSeal,
NotOpenedForWriting,
UnknownError
};

/// @brief Describes failures which can occur when the files metadata is accessed.
enum class FileAccessError
{
InsufficientPermissions,
TooManySymbolicLinksEncountered,
IoFailure,
InsufficientKernelMemory,
UnknownError
};

/// @brief Describes failures which can occur when a file is removed.
enum class FileRemoveError
{
PermissionDenied,
CurrentlyInUse,
IoFailure,
TooManySymbolicLinksEncountered,
InsufficientKernelMemory,
IsDirectory,
ReadOnlyFilesystem,
UnknownError
};

/// @brief Describes failures which can occur when a file offset is changed.
enum class FileOffsetError
{
FileOffsetOverflow,
OffsetBeyondFileLimits,
SeekingNotSupportedByFileType,
OffsetAtWrongPosition,
UnknownError,
};

/// @brief Represents a file. It supports various read and write functionalities
/// and can verify the existance of a file as well as remove existing files.
class File : public FileManagementInterface<File>
{
public:
File(const File&) noexcept = delete;
File& operator=(const File&) noexcept = delete;

File(File&& rhs) noexcept;
File& operator=(File&& rhs) noexcept;
~File() noexcept;

/// @brief Returns the underlying native file handle.
int get_file_handle() const noexcept;

/// @brief Reads the contents of the file and writes it into the provided buffer.
/// @param[in] buffer pointer to the memory.
/// @param[in] buffer_len the storage size of the provided memory.
/// @returns The amount of bytes read, at most buffer_len.
expected<uint64_t, FileReadError> read(uint8_t* const buffer, const uint64_t buffer_len) const noexcept;

/// @brief Reads the contents of the file from a given offset and writes it into the provided buffer.
/// If the offset is out of bounds it will read nothing.
/// @param[in] offset starting point from which the reading shall begin.
/// @param[in] buffer pointer to the memory.
/// @param[in] buffer_len the storage size of the provided memory.
/// @returns The amount of bytes read, at most buffer_len.
expected<uint64_t, FileReadError>
read_at(const uint64_t offset, uint8_t* const buffer, const uint64_t buffer_len) const noexcept;

/// @brief Writes the provided buffer into the file.
/// @param[in] buffer pointer to the memory which shall be stored inside the file.
/// @param[in] buffer_len length of the memory.
/// @returns The amount of bytes written, at most buffer_len.
expected<uint64_t, FileWriteError> write(const uint8_t* const buffer, const uint64_t buffer_len) const noexcept;

/// @brief Writes the provided buffer into the file starting from the given offset. If the offset
/// is out of bounds the file will be filled with zeroes until the offset.
/// @param[in] offset starting point from which the writing shall begin.
/// @param[in] buffer pointer to the memory which shall be stored inside the file.
/// @param[in] buffer_len length of the memory.
/// @returns The amount of bytes written, at most buffer_len.
expected<uint64_t, FileWriteError>
write_at(const uint64_t offset, const uint8_t* const buffer, const uint64_t buffer_len) const noexcept;

/// @brief Returns true if the provided file exists, otherwise false.
/// @param[in] file the path to the file
static expected<bool, FileAccessError> does_exist(const FilePath& file) noexcept;

/// @brief Removes an existing file.
/// @param[in] file the path to the file which shall be removed
/// @returns true if the file did exist and was removed, otherwise false
static expected<bool, FileRemoveError> remove(const FilePath& file) noexcept;

private:
friend class FileBuilder;
explicit File(const int file_descriptor, const posix::AccessMode access_mode) noexcept;
void close_fd() noexcept;

expected<FileOffsetError> set_offset(const uint64_t offset) const noexcept;

private:
static constexpr int INVALID_FILE_DESCRIPTOR{-1};

int m_file_descriptor{INVALID_FILE_DESCRIPTOR};
posix::AccessMode m_access_mode{posix::AccessMode::READ_ONLY};
};

class FileBuilder
{
private:
using AccessMode = posix::AccessMode;
using OpenMode = posix::OpenMode;

IOX_BUILDER_PARAMETER(Ownership, owner, Ownership::from_process())
IOX_BUILDER_PARAMETER(access_rights, permissions, perms::owner_read)
IOX_BUILDER_PARAMETER(AccessMode, access_mode, AccessMode::READ_ONLY)
IOX_BUILDER_PARAMETER(OpenMode, open_mode, OpenMode::OPEN_EXISTING)

public:
expected<File, FileCreationError> create(const FilePath& name) noexcept;
expected<File, FileCreationError> open(const FilePath& name) noexcept;
};
} // namespace iox

#endif
Loading

0 comments on commit e7b572b

Please sign in to comment.