Commit e1d5ec9d authored by Julius Athenstaedt's avatar Julius Athenstaedt
Browse files

add missing python binding functions

parent c0c0711f
Loading
Loading
Loading
Loading
+237 −4
Original line number Diff line number Diff line
@@ -8,12 +8,141 @@ PYBIND11_MODULE(gkfs_python, m) {
    m.doc() = "Python bindings for GekkoFS POSIX interface";

    m.def("gkfs_open", &gkfs::syscall::gkfs_open);

    m.def("gkfs_create", &gkfs::syscall::gkfs_create);

    m.def("gkfs_libcremove", &gkfs::syscall::gkfs_libcremove);

    m.def("gkfs_remove", &gkfs::syscall::gkfs_remove);
    m.def("gkfs_access", &gkfs::syscall::gkfs_access, py::arg("path"),
          py::arg("mask"), py::arg("follow_links") = true);

    // Wrap gkfs_stat manually (complex signature)
    m.def("gkfs_rmdir", &gkfs::syscall::gkfs_rmdir);

    m.def("gkfs_write", [](int fd, py::bytes data) -> ssize_t {
        py::buffer_info info(py::buffer(data).request());
        ssize_t ret = gkfs::syscall::gkfs_write(fd, info.ptr, info.size);
        if(ret < 0)
            throw std::runtime_error("gkfs_write failed");
        return ret;
    });

    m.def("gkfs_read", [](int fd, size_t count) -> py::bytes {
        std::vector<char> buf(count);
        ssize_t ret = gkfs::syscall::gkfs_read(fd, buf.data(), count);
        if(ret < 0)
            throw std::runtime_error("gkfs_read failed");
        return py::bytes(buf.data(), ret);
    });

    m.def("gkfs_close", &gkfs::syscall::gkfs_close);


    m.def(
            "gkfs_lseek",
            [](unsigned int fd, int64_t offset, unsigned int whence) {
                return gkfs::syscall::gkfs_lseek(fd, offset, whence);
            },
            py::arg("fd"), py::arg("offset"), py::arg("whence"));

    m.def(
            "gkfs_pwrite",
            [](int fd, py::bytes data, int64_t offset) {
                std::string buf = data;
                return gkfs::syscall::gkfs_pwrite(fd, buf.data(), buf.size(),
                                                  offset);
            },
            py::arg("fd"), py::arg("data"), py::arg("offset"));

    m.def(
            "gkfs_pread",
            [](int fd, size_t count, int64_t offset) {
                std::string buf(count, '\0');
                ssize_t nread = gkfs::syscall::gkfs_pread(fd, buf.data(), count,
                                                          offset);
                if(nread < 0) {
                    throw std::runtime_error("gkfs_pread failed");
                }
                return py::bytes(buf.data(), nread);
            },
            py::arg("fd"), py::arg("count"), py::arg("offset"));

    m.def(
            "gkfs_readv",
            [](int fd, size_t iovcnt) {
                // TODO better allocation or provide size to calc
                std::vector<char> buffer(4096 * iovcnt);
                std::vector<struct iovec> iov(iovcnt);
                size_t chunk = buffer.size() / iovcnt;

                for(size_t i = 0; i < iovcnt; ++i) {
                    iov[i].iov_base = buffer.data() + i * chunk;
                    iov[i].iov_len = chunk;
                }

                ssize_t nread =
                        gkfs::syscall::gkfs_readv(fd, iov.data(), iovcnt);
                if(nread < 0)
                    throw std::runtime_error("gkfs_readv failed");
                return py::bytes(buffer.data(), nread);
            },
            py::arg("fd"), py::arg("iovcnt"));

    m.def(
            "gkfs_writev",
            [](int fd, const std::vector<py::bytes>& bufs) {
                std::vector<std::string> buf_data;
                std::vector<struct iovec> iov;

                for(const auto& b : bufs) {
                    buf_data.emplace_back(b); // keep data alive
                    struct iovec io{};
                    io.iov_base = (void*) buf_data.back().data();
                    io.iov_len = buf_data.back().size();
                    iov.push_back(io);
                }

                return gkfs::syscall::gkfs_writev(fd, iov.data(), iov.size());
            },
            py::arg("fd"), py::arg("buffers"));

    m.def(
            "gkfs_preadv",
            [](int fd, size_t iovcnt, int64_t offset) {
                std::vector<char> buffer(4096 * iovcnt); // adjust as needed
                std::vector<struct iovec> iov(iovcnt);
                size_t chunk = buffer.size() / iovcnt;

                for(size_t i = 0; i < iovcnt; ++i) {
                    iov[i].iov_base = buffer.data() + i * chunk;
                    iov[i].iov_len = chunk;
                }

                ssize_t nread = gkfs::syscall::gkfs_preadv(fd, iov.data(),
                                                           iovcnt, offset);
                if(nread < 0)
                    throw std::runtime_error("gkfs_preadv failed");
                return py::bytes(buffer.data(), nread);
            },
            py::arg("fd"), py::arg("iovcnt"), py::arg("offset"));

    m.def(
            "gkfs_pwritev",
            [](int fd, const std::vector<py::bytes>& bufs, int64_t offset) {
                std::vector<std::string> buf_data;
                std::vector<struct iovec> iov;

                for(const auto& b : bufs) {
                    buf_data.emplace_back(b);
                    struct iovec io{};
                    io.iov_base = (void*) buf_data.back().data();
                    io.iov_len = buf_data.back().size();
                    iov.push_back(io);
                }

                return gkfs::syscall::gkfs_pwritev(fd, iov.data(), iov.size(),
                                                   offset);
            },
            py::arg("fd"), py::arg("buffers"), py::arg("offset"));

    m.def("gkfs_stat",
          [](const std::string& path, bool follow_links, bool bypass_rename) {
              struct stat buf;
@@ -38,10 +167,102 @@ PYBIND11_MODULE(gkfs_python, m) {
              return std::make_tuple(res, stat_result);
          });

    m.def("gkfs_statx", [](int dirfd, const std::string& path, int flags,
                           unsigned int mask, bool follow_links) {
        struct statx stx;
        memset(&stx, 0, sizeof(stx));
        int ret = gkfs::syscall::gkfs_statx(dirfd, path, flags, mask, &stx,
                                            follow_links);

        py::dict meta;
        if(ret == 0) {
            meta["size"] = stx.stx_size;
            meta["mode"] = stx.stx_mode;
            meta["uid"] = stx.stx_uid;
            meta["gid"] = stx.stx_gid;
            meta["mtime"] = stx.stx_mtime.tv_sec;
            meta["atime"] = stx.stx_atime.tv_sec;
            meta["ctime"] = stx.stx_ctime.tv_sec;
            meta["ino"] = stx.stx_ino;
            meta["nlink"] = stx.stx_nlink;
            meta["dev_major"] = stx.stx_dev_major;
            meta["dev_minor"] = stx.stx_dev_minor;
        }

        return py::make_tuple(ret, meta);
    });

    m.def("gkfs_dup", &gkfs::syscall::gkfs_dup);

    m.def("gkfs_dup2", &gkfs::syscall::gkfs_dup2);

    m.def("gkfs_access", &gkfs::syscall::gkfs_access, py::arg("path"),
          py::arg("mask"), py::arg("follow_links") = true);

    m.def("gkfs_get_file_list", &gkfs::syscall::gkfs_get_file_list);

    m.def("gkfs_close", &gkfs::syscall::gkfs_close);
    m.def("gkfs_opendir", &gkfs::syscall::gkfs_opendir);

    m.def("gkfs_getdents", [](unsigned int fd, unsigned int count) {
        std::vector<char> buf(count);
        int ret = gkfs::syscall::gkfs_getdents(
                fd, reinterpret_cast<struct linux_dirent*>(buf.data()), count);
        if(ret < 0)
            throw std::runtime_error("gkfs_getdents failed");
        return py::bytes(buf.data(), ret);
    });

    m.def("gkfs_getdents64", [](unsigned int fd, unsigned int count) {
        std::vector<char> buf(count);
        int ret = gkfs::syscall::gkfs_getdents64(
                fd, reinterpret_cast<struct linux_dirent64*>(buf.data()),
                count);
        if(ret < 0)
            throw std::runtime_error("gkfs_getdents64 failed");
        return py::bytes(buf.data(), ret);
    });

    m.def("gkfs_truncate", &gkfs::syscall::gkfs_truncate);

#ifdef HAS_SYMLINKS
    m.def("gkfs_mk_symlink", &gkfs::syscall::gkfs_mk_symlink);

    m.def("gkfs_readlink", [](const std::string& path, int bufsize) {
        std::vector<char> buf(bufsize);
        int ret = gkfs::syscall::gkfs_readlink(path, buf.data(), bufsize);
        if(ret < 0)
            throw std::runtime_error("gkfs_readlink failed");
        return std::string(buf.data(), ret);
    });
#endif

#ifdef HAS_RENAME
    m.def("gkfs_rename", &gkfs::syscall::gkfs_rename);
#endif

    m.def("gkfs_fsync", &gkfs::syscall::gkfs_fsync);

    m.def("gkfs_mmap", [](uintptr_t addr, size_t length, int prot, int flags,
                          int fd, off_t offset) {
        void* result = gkfs::syscall::gkfs_mmap(
                reinterpret_cast<void*>(addr), length, prot, flags, fd, offset);
        // if(result == MAP_FAILED) // TODO
        // throw std::runtime_error("gkfs_mmap failed");
        return reinterpret_cast<uintptr_t>(result);
    });

    m.def("gkfs_munmap", [](uintptr_t addr, size_t length) {
        return gkfs::syscall::gkfs_munmap(reinterpret_cast<void*>(addr),
                                          length);
    });

    m.def("gkfs_msync", [](uintptr_t addr, size_t length, int flags) {
        return gkfs::syscall::gkfs_msync(reinterpret_cast<void*>(addr), length,
                                         flags);
    });

    // TODO missing
    // expand_start, expand_status, expand_finalize

    m.def(
            "init",
@@ -54,4 +275,16 @@ PYBIND11_MODULE(gkfs_python, m) {
                return result;
            },
            "Initialize GekkoFS");

    m.def(
            "end",
            []() {
                int result = gkfs_end();
                if(result != 0) {
                    throw std::runtime_error("gkfs_end() failed with code " +
                                             std::to_string(result));
                }
                return result;
            },
            "End GekkoFS");
}