Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -62,20 +62,24 @@ install(
# PYBIND11 TARGET
########################

pybind11_add_module(_pycapio src/pycapio.cpp)
file(GLOB PYCAPIO_SOURCES "${CMAKE_SOURCE_DIR}/src/*.cpp")

pybind11_add_module(_pycapio ${PYCAPIO_SOURCES})

# patch server_println by copying server_println.hpp from server/utils/server_println.hpp to posix/utils/server_println.hpp
file(COPY "${capio_SOURCE_DIR}/capio/server/include/utils/server_println.hpp"
DESTINATION "${capio_SOURCE_DIR}/capio/posix/utils/")
message(WARNING "WARN: patch for server_println.hpp copied to posix has been applied!")

target_compile_definitions(_pycapio PRIVATE PYCAPIO_BINDINGS)
target_compile_definitions(_pycapio PRIVATE CAPIO_VERSION="${CMAKE_PROJECT_VERSION}")

message(STATUS "CAPIO_PREFIX = ${capio_SOURCE_DIR}")

target_include_directories(_pycapio PRIVATE
${capio_SOURCE_DIR}/capio
${capio_SOURCE_DIR}/capio/posix
${CMAKE_SOURCE_DIR}/include
)

target_compile_options(
Expand Down
7 changes: 6 additions & 1 deletion include/IOWrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
// TODO: This file should be split into header and source file. however, it is not yet possible
// due to the fact that CAPIO within its POSIX component is a header only target, with global
// variables not declared inline. As soon as the POSIX component is refactored, it will be
// possible to move this file as a .cpp file

#ifndef LIBCAPIO_IOWRAPPER_HPP
#define LIBCAPIO_IOWRAPPER_HPP
#include <cstdint>
Expand Down Expand Up @@ -58,7 +63,7 @@ template <IOMode Mode> class IOWrapper {
const auto write_size = libcapio_write(_file_descriptor, text.data(), text.size());
if (write_size != static_cast<ssize_t>(text.size())) {
throw PyCapioException("write failed: received from libcapio offset: " +
std::to_string(write_size));
std::to_string(write_size));
}
return write_size;
}
Expand Down
125 changes: 23 additions & 102 deletions include/OsPath.hpp
Original file line number Diff line number Diff line change
@@ -1,112 +1,33 @@
#ifndef LIBCAPIO__CAPIOOSPATH_HPP
#define LIBCAPIO__CAPIOOSPATH_HPP
#pragma once

#include <filesystem>
#include <cstdint>
#include <string>
#include <utility>

class OsPath {
public:
/**
* LIBCAPIO METHODS
* LIBCAPIO METHODS
**/

static bool exists(const std::string &path) {
struct stat statbuf{};
if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) {
return false;
}
return true;
}

static bool isfile(const std::string &path) {
struct stat statbuf{};
if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) {
return false;
}

return (statbuf.st_mode & S_IFMT) == S_IFREG;
}

static bool isdir(const std::string &path) { return !isfile(path); }

static uintmax_t getsize(const std::string &path) {
struct stat statbuf{};
if (libcapio_stat(path.c_str(), &statbuf) == -1 && errno == ENOENT) {
return 0;
}
return statbuf.st_size;
}
static bool exists(const std::string &path);
static bool isfile(const std::string &path);
static bool isdir(const std::string &path);
static uintmax_t getsize(const std::string &path);

/**
* NON LIBCAPIO METHODS
* NON LIBCAPIO METHODS
**/

static std::string basename(const std::string &path) {
return std::filesystem::path(path).filename().string();
}

static std::string dirname(const std::string &path) {
return std::filesystem::path(path).parent_path().string();
}

static std::string abspath(const std::string &path) {
return std::filesystem::absolute(path).string();
}

static std::pair<std::string, std::string> splitext(const std::string &path) {
std::filesystem::path p(path);
return {p.stem().string(), p.extension().string()};
}

static bool isabs(const std::string &p) { return std::filesystem::path(p).is_absolute(); }

static std::string normpath(const std::string &p) {
return std::filesystem::path(p).lexically_normal().string();
}

static std::string relpath(const std::string &path, const std::string &start = ".") {
return std::filesystem::relative(path, start).string();
}

static double getmtime(const std::string &path) {
auto ftime = std::filesystem::last_write_time(path);
auto sctp = std::chrono::time_point_cast<std::chrono::seconds>(ftime);
return static_cast<double>(sctp.time_since_epoch().count());
}

static bool samefile(const std::string &p1, const std::string &p2) {
return std::filesystem::equivalent(p1, p2);
}

static std::pair<std::string, std::string> split(const std::string &p) {
std::filesystem::path path(p);
return {path.parent_path().string(), path.filename().string()};
}

// On Unix, normcase simply returns the path unchanged.
static std::string normcase(const std::string &p) { return p; }

static std::string realpath(const std::string &path) {
try {
return std::filesystem::canonical(path).string();
} catch (const std::filesystem::filesystem_error &) {
return "";
}
}

static std::string join(const std::string &path1, const std::string &path2) {
if (path1.empty() && path2.empty()) {
return "";
}
if (path1.empty() && !path2.empty()) {
return path2;
}
if (path2.empty() && !path1.empty()) {
return path1;
}

return std::filesystem::path(path1) / path2;
}
};

#endif // LIBCAPIO__CAPIOOSPATH_HPP
static std::string basename(const std::string &path);
static std::string dirname(const std::string &path);
static std::string abspath(const std::string &path);
static std::pair<std::string, std::string> splitext(const std::string &path);
static bool isabs(const std::string &p);
static std::string normpath(const std::string &p);
static std::string relpath(const std::string &path, const std::string &start = ".");
static double getmtime(const std::string &path);
static bool samefile(const std::string &p1, const std::string &p2);
static std::pair<std::string, std::string> split(const std::string &p);
static std::string normcase(const std::string &p);
static std::string realpath(const std::string &path);
static std::string join(const std::string &path1, const std::string &path2);
};
30 changes: 6 additions & 24 deletions include/PyCapioException.hpp
Original file line number Diff line number Diff line change
@@ -1,36 +1,18 @@
#ifndef PYCAPIO_EXCEPTION_HPP
#define PYCAPIO_EXCEPTION_HPP

#include <exception>
#include <iostream>
#include <ostream>
#include <pybind11/pybind11.h>
#include <pybind11/pytypes.h>
#include <string>

class PyCapioException : public std::exception {
std::string _message;

static std::string capture_python_stack() {
try {
const auto traceback = pybind11::module_::import("traceback");
const auto io = pybind11::module_::import("io");
auto string_io = io.attr("StringIO")();
traceback.attr("print_stack")(pybind11::none(), pybind11::none(), string_io);
return string_io.attr("getvalue")().cast<std::string>();
} catch (const pybind11::error_already_set &e) {
return std::string("[failed to capture Python stack: ") + e.what() + "]";
} catch (...) {
return "[failed to capture Python stack: unknown error]";
}
}
static std::string capture_python_stack();

public:
explicit PyCapioException(const std::string &error_message)
: _message("PyCapioException: " + error_message + "\nPython stack trace:\n" +
capture_python_stack()) {
std::cerr << _message << std::endl;
}
explicit PyCapioException(const std::string &error_message);

[[nodiscard]] const char *what() const noexcept override { return _message.c_str(); }
[[nodiscard]] const char *what() const noexcept override;
};
#endif // PYCAPIO_EXCEPTION_HPP

#endif // PYCAPIO_EXCEPTION_HPP
80 changes: 19 additions & 61 deletions include/ScandirIteratorWrapper.hpp
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#ifndef LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP
#define LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP
#include "libcapio.hpp"
#ifndef LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP
#define LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP

#include <cstdint>
#include <dirent.h>
#include <filesystem>
#include <string>

class CapioDirEntry {
std::filesystem::path base_path;
Expand All @@ -11,24 +13,14 @@ class CapioDirEntry {
unsigned char type_;

public:
CapioDirEntry(const std::filesystem::path &base, const dirent64 &ent)
: base_path(base), name_(ent.d_name), ino_(ent.d_ino), type_(ent.d_type) {}

[[nodiscard]] std::string name() const { return name_; }

[[nodiscard]] std::string path() const { return (base_path / name_).string(); }

[[nodiscard]] uint64_t inode() const { return ino_; }

[[nodiscard]] bool is_dir([[maybe_unused]] bool follow_symlinks = true) const {
return type_ == DT_DIR;
}

[[nodiscard]] bool is_file([[maybe_unused]] bool follow_symlinks = true) const {
return type_ == DT_REG;
}

[[nodiscard]] bool is_symlink() const { return type_ == DT_LNK; }
CapioDirEntry(const std::filesystem::path &base, const dirent64 &ent);

[[nodiscard]] std::string name() const;
[[nodiscard]] std::string path() const;
[[nodiscard]] uint64_t inode() const;
[[nodiscard]] bool is_dir(bool follow_symlinks = true) const;
[[nodiscard]] bool is_file(bool follow_symlinks = true) const;
[[nodiscard]] bool is_symlink() const;
};

class ScandirIteratorWrapper {
Expand All @@ -37,46 +29,12 @@ class ScandirIteratorWrapper {
bool finished = false;

public:
ScandirIteratorWrapper(const std::filesystem::path &path) : path(path) {

if (!libcapio_initialized) {
throw PyCapioException("libcapio not initialized");
}

file_descriptor = libcapio_open(path.string().c_str(), O_RDONLY);
if (file_descriptor < 0) {
throw PyCapioException("libcapio_open failed");
}
}

~ScandirIteratorWrapper() { close(); }

CapioDirEntry next() {
if (finished) {
throw pybind11::stop_iteration();
}

dirent64 ent{};
if (libcapio_readdir(file_descriptor, &ent) == 0) {
finished = true;
throw pybind11::stop_iteration();
}

if (strcmp(ent.d_name, ".") == 0 || strcmp(ent.d_name, "..") == 0) {
return next();
}

return {path, ent};
}

ScandirIteratorWrapper &iter() { return *this; }
explicit ScandirIteratorWrapper(const std::filesystem::path &path);
~ScandirIteratorWrapper();

void close() {
if (file_descriptor != -1) {
libcapio_close(file_descriptor);
file_descriptor = -1;
}
}
CapioDirEntry next();
ScandirIteratorWrapper &iter();
void close();
};

#endif // LIBCAPIO__CAPIOSCANDIRITERATORWRAPPER_HPP
#endif // LIBCAPIO_SCANDIR_ITERATOR_WRAPPER_HPP
Loading
Loading