Skip to content
Commits on Source (8)
......@@ -31,10 +31,18 @@ int gkfs_create(const std::string& path, mode_t mode);
int gkfs_remove(const std::string& path);
// Implementation of access,
// Follow links is true by default
int gkfs_access(const std::string& path, int mask, bool follow_links = true);
// Implementation of stat,
// Follow links is true by default
int gkfs_stat(const std::string& path, struct stat* buf, bool follow_links = true);
// Implementation of statx, it uses the normal stat and maps the information to the statx structure
// Follow links is true by default
int gkfs_statx(int dirfd, const std::string& path, int flags, unsigned int mask,struct statx* buf, bool follow_links = true );
int gkfs_statfs(struct statfs* buf);
int gkfs_statvfs(struct statvfs* buf);
......@@ -76,6 +84,9 @@ ssize_t gkfs_pread_ws(int fd, void* buf, size_t count, off64_t offset);
ssize_t gkfs_read(int fd, void* buf, size_t count);
ssize_t gkfs_readv(int fd, const struct iovec* iov, int iovcnt);
ssize_t gkfs_preadv(int fd, const struct iovec* iov, int iovcnt, off_t offset);
int gkfs_opendir(const std::string& path);
......
......@@ -30,6 +30,8 @@ int hook_close(int fd);
int hook_stat(const char* path, struct stat* buf);
int hook_statx(int dirfd, const char* path, int flags, unsigned int mask,struct statx* buf);
int hook_lstat(const char* path, struct stat* buf);
int hook_fstat(unsigned int fd, struct stat* buf);
......@@ -40,6 +42,11 @@ int hook_read(unsigned int fd, void* buf, size_t count);
int hook_pread(unsigned int fd, char* buf, size_t count, loff_t pos);
int hook_readv(unsigned long fd, const struct iovec * iov, unsigned long iovcnt);
int hook_preadv(unsigned long fd, const struct iovec * iov, unsigned long iovcnt,
unsigned long pos_l, unsigned long pos_h);
int hook_write(unsigned int fd, const char* buf, size_t count);
int hook_pwrite(unsigned int fd, const char* buf, size_t count, loff_t pos);
......
......@@ -1012,7 +1012,7 @@ struct get_metadentry_size {
// Mercury callback to serialize output arguments
constexpr static const auto mercury_out_proc_cb =
HG_GEN_PROC_NAME(rpc_err_out_t);
HG_GEN_PROC_NAME(rpc_get_metadentry_size_out_t);
class input {
......
......@@ -59,7 +59,6 @@ struct linux_dirent64 {
char d_name[1]; // originally `char d_name[0]` in kernel, but ISO C++ forbids zero-size array 'd_name'
};
namespace {
int check_parent_dir(const std::string& path) {
......@@ -233,6 +232,43 @@ int gkfs_stat(const string& path, struct stat* buf, bool follow_links) {
return 0;
}
int gkfs_statx(int dirfs, const std::string& path, int flags, unsigned int mask, struct statx* buf, bool follow_links) {
auto md = gkfs::util::get_metadata(path, follow_links);
if (!md) {
return -1;
}
struct stat tmp{};
gkfs::util::metadata_to_stat(path, *md, tmp);
buf->stx_mask = 0;
buf->stx_blksize = tmp.st_blksize;
buf->stx_attributes = 0;
buf->stx_nlink = tmp.st_nlink;
buf->stx_uid = tmp.st_uid;
buf->stx_gid = tmp.st_gid;
buf->stx_mode = tmp.st_mode;
buf->stx_ino = tmp.st_ino;
buf->stx_size = tmp.st_size;
buf->stx_blocks = tmp.st_blocks;
buf->stx_attributes_mask = 0;
buf->stx_atime.tv_sec = tmp.st_atim.tv_sec;
buf->stx_atime.tv_nsec = tmp.st_atim.tv_nsec;
buf->stx_mtime.tv_sec = tmp.st_mtim.tv_sec;
buf->stx_mtime.tv_nsec = tmp.st_mtim.tv_nsec;
buf->stx_ctime.tv_sec = tmp.st_ctim.tv_sec;
buf->stx_ctime.tv_nsec = tmp.st_ctim.tv_nsec;
buf->stx_btime = buf->stx_atime;
return 0;
}
int gkfs_statfs(struct statfs* buf) {
auto blk_stat = gkfs::rpc::forward_get_chunk_stat();
buf->f_type = 0;
......@@ -283,10 +319,16 @@ off_t gkfs_lseek(shared_ptr<gkfs::filemap::OpenFile> gkfs_fd, off_t offset, unsi
case SEEK_END: {
off64_t file_size;
auto err = gkfs::rpc::forward_get_metadentry_size(gkfs_fd->path(), file_size);
if (err < 0) {
errno = err; // Negative numbers are explicitly for error codes
return -1;
}
if (offset < 0 and file_size < -offset) {
errno = EINVAL;
return -1;
}
gkfs_fd->pos(file_size + offset);
break;
}
......@@ -485,6 +527,49 @@ ssize_t gkfs_read(int fd, void* buf, size_t count) {
return ret;
}
ssize_t gkfs_preadv(int fd, const struct iovec* iov, int iovcnt, off_t offset) {
auto file = CTX->file_map()->get(fd);
auto pos = offset; // keep truck of current position
ssize_t read = 0;
ssize_t ret;
for (int i = 0; i < iovcnt; ++i) {
auto count = (iov + i)->iov_len;
if (count == 0) {
continue;
}
auto buf = (iov + i)->iov_base;
ret = gkfs_pread(file, reinterpret_cast<char*>(buf), count, pos);
if (ret == -1) {
break;
}
read += ret;
pos += ret;
if (static_cast<size_t>(ret) < count) {
break;
}
}
if (read == 0) {
return -1;
}
return read;
}
ssize_t gkfs_readv(int fd, const struct iovec* iov, int iovcnt) {
auto gkfs_fd = CTX->file_map()->get(fd);
auto pos = gkfs_fd->pos(); // retrieve the current offset
auto ret = gkfs_preadv(fd, iov, iovcnt, pos);
assert(ret != 0);
if (ret < 0) {
return -1;
}
gkfs_fd->pos(pos + ret);
return ret;
}
ssize_t gkfs_pread_ws(int fd, void* buf, size_t count, off64_t offset) {
auto gkfs_fd = CTX->file_map()->get(fd);
return gkfs_pread(gkfs_fd, reinterpret_cast<char*>(buf), count, offset);
......
......@@ -98,6 +98,39 @@ int hook_stat(const char* path, struct stat* buf) {
return syscall_no_intercept(SYS_stat, rel_path.c_str(), buf);
}
int hook_statx(int dirfd, const char* path, int flags, unsigned int mask, struct ::statx* buf) {
LOG(DEBUG, "{}() called with dirfd: '{}', path: \"{}\", flags: '{}', mask: '{}', buf: '{}'",
__func__, dirfd, path, flags, mask, fmt::ptr(buf));
std::string resolved;
auto rstatus = CTX->relativize_fd_path(dirfd, path, resolved);
switch (rstatus) {
case gkfs::preload::RelativizeStatus::fd_unknown:
return syscall_no_intercept(SYS_statx, dirfd, path, flags, mask, buf);
case gkfs::preload::RelativizeStatus::external:
return syscall_no_intercept(SYS_statx, dirfd, resolved.c_str(), flags, mask, buf);
case gkfs::preload::RelativizeStatus::fd_not_a_dir:
return -ENOTDIR;
case gkfs::preload::RelativizeStatus::internal:
return with_errno(gkfs::syscall::gkfs_statx(dirfd, resolved.c_str() , flags, mask, buf));
default:
LOG(ERROR, "{}() relativize status unknown: {}", __func__);
return -EINVAL;
}
return syscall_no_intercept(SYS_statx, dirfd, path, flags, mask, buf);
}
int hook_lstat(const char* path, struct stat* buf) {
LOG(DEBUG, "{}() called with path: \"{}\", buf: {}",
......@@ -176,6 +209,30 @@ int hook_pread(unsigned int fd, char* buf, size_t count, loff_t pos) {
return syscall_no_intercept(SYS_pread64, fd, buf, count, pos);
}
int hook_readv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt) {
LOG(DEBUG, "{}() called with fd: {}, iov: {}, iovcnt: {}",
__func__, fd, fmt::ptr(iov), iovcnt);
if (CTX->file_map()->exist(fd)) {
return with_errno(gkfs::syscall::gkfs_readv(fd, iov, iovcnt));
}
return syscall_no_intercept(SYS_readv, fd, iov, iovcnt);
}
int hook_preadv(unsigned long fd, const struct iovec* iov, unsigned long iovcnt,
unsigned long pos_l, unsigned long pos_h) {
LOG(DEBUG, "{}() called with fd: {}, iov: {}, iovcnt: {}, "
"pos_l: {}," "pos_h: {}",
__func__, fd, fmt::ptr(iov), iovcnt, pos_l, pos_h);
if (CTX->file_map()->exist(fd)) {
return with_errno(gkfs::syscall::gkfs_preadv(fd, iov, iovcnt, pos_l));
}
return syscall_no_intercept(SYS_preadv, fd, iov, iovcnt, pos_l);
}
int hook_write(unsigned int fd, const char* buf, size_t count) {
LOG(DEBUG, "{}() called with fd: {}, buf: {}, count {}",
......@@ -220,7 +277,7 @@ int hook_pwritev(unsigned long fd, const struct iovec* iov, unsigned long iovcnt
if (CTX->file_map()->exist(fd)) {
return with_errno(gkfs::syscall::gkfs_pwritev(fd, iov, iovcnt, pos_l));
}
return syscall_no_intercept(SYS_pwritev, fd, iov, iovcnt);
return syscall_no_intercept(SYS_pwritev, fd, iov, iovcnt, pos_l);
}
int hook_unlinkat(int dirfd, const char* cpath, int flags) {
......@@ -760,4 +817,4 @@ int hook_fstatfs(unsigned int fd, struct statfs* buf) {
}
} // namespace hook
} // namespace gkfs
\ No newline at end of file
} // namespace gkfs
......@@ -466,6 +466,16 @@ int hook(long syscall_number,
reinterpret_cast<struct stat*>(arg1));
break;
#ifdef SYS_statx
case SYS_statx:
*result = gkfs::hook::hook_statx(static_cast<int>(arg0),
reinterpret_cast<char*>(arg1),
static_cast<int>(arg2),
static_cast<unsigned int>(arg3),
reinterpret_cast<struct statx*>(arg4));
break;
#endif
case SYS_lstat:
*result = gkfs::hook::hook_lstat(reinterpret_cast<char*>(arg0),
reinterpret_cast<struct stat*>(arg1));
......@@ -496,6 +506,20 @@ int hook(long syscall_number,
static_cast<loff_t>(arg3));
break;
case SYS_readv:
*result = gkfs::hook::hook_readv(static_cast<unsigned long>(arg0),
reinterpret_cast<const struct iovec*>(arg1),
static_cast<unsigned long>(arg2));
break;
case SYS_preadv:
*result = gkfs::hook::hook_preadv(static_cast<unsigned long>(arg0),
reinterpret_cast<const struct iovec*>(arg1),
static_cast<unsigned long>(arg2),
static_cast<unsigned long>(arg3),
static_cast<unsigned long>(arg4));
break;
case SYS_pwrite64:
*result = gkfs::hook::hook_pwrite(static_cast<unsigned int>(arg0),
reinterpret_cast<const char*>(arg1),
......@@ -914,4 +938,4 @@ void stop_interception() {
}
} // namespace preload
} // namespace gkfs
\ No newline at end of file
} // namespace gkfs
......@@ -16,6 +16,27 @@ gkfs_add_python_test(
SOURCE directories/test_directories.py
)
gkfs_add_python_test(
NAME test_status
PYTHON_VERSION 3.6
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/integration
SOURCE status/test_status.py
)
gkfs_add_python_test(
NAME test_operations
PYTHON_VERSION 3.6
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/integration
SOURCE operations/
)
gkfs_add_python_test(
NAME test_lseek
PYTHON_VERSION 3.6
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/tests/integration
SOURCE position/test_lseek.py
)
gkfs_add_python_test(
NAME test_shell
PYTHON_VERSION 3.6
......@@ -41,6 +62,31 @@ if(GKFS_INSTALL_TESTS)
PATTERN ".pytest_cache" EXCLUDE
)
install(DIRECTORY status
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration
FILES_MATCHING
REGEX ".*\\.py"
PATTERN "__pycache__" EXCLUDE
PATTERN ".pytest_cache" EXCLUDE
)
install(DIRECTORY operations
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration
FILES_MATCHING
REGEX ".*\\.py"
PATTERN "__pycache__" EXCLUDE
PATTERN ".pytest_cache" EXCLUDE
)
install(DIRECTORY position
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration
FILES_MATCHING
REGEX ".*\\.py"
PATTERN "__pycache__" EXCLUDE
PATTERN ".pytest_cache" EXCLUDE
)
install(DIRECTORY shell
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/gkfs/tests/integration
FILES_MATCHING
......
......@@ -12,12 +12,20 @@ add_executable(gkfs.io
gkfs.io/open.cpp
gkfs.io/opendir.cpp
gkfs.io/read.cpp
gkfs.io/readv.cpp
gkfs.io/pread.cpp
gkfs.io/preadv.cpp
gkfs.io/readdir.cpp
gkfs.io/reflection.hpp
gkfs.io/rmdir.cpp
gkfs.io/serialize.hpp
gkfs.io/stat.cpp
gkfs.io/write.cpp
gkfs.io/pwrite.cpp
gkfs.io/writev.cpp
gkfs.io/pwritev.cpp
gkfs.io/statx.cpp
gkfs.io/lseek.cpp
)
include(FetchContent)
......
......@@ -29,6 +29,15 @@ opendir_init(CLI::App& app);
void
read_init(CLI::App& app);
void
pread_init(CLI::App& app);
void
readv_init(CLI::App& app);
void
preadv_init(CLI::App& app);
void
readdir_init(CLI::App& app);
......@@ -41,4 +50,19 @@ stat_init(CLI::App& app);
void
write_init(CLI::App& app);
void
pwrite_init(CLI::App& app);
void
writev_init(CLI::App& app);
void
pwritev_init(CLI::App& app);
void
statx_init(CLI::App& app);
void
lseek_init(CLI::App& app);
#endif // IO_COMMANDS_HPP
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct lseek_options {
bool verbose;
std::string pathname;
::off_t offset;
int whence;
REFL_DECL_STRUCT(lseek_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(::off_t, offset),
REFL_DECL_MEMBER(int, whence)
);
};
struct lseek_output {
::off_t retval;
int errnum;
REFL_DECL_STRUCT(lseek_output,
REFL_DECL_MEMBER(::off_t, retval),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const lseek_output& out) {
record = serialize(out);
}
std::string
whence2str(int whence) {
switch (whence) {
case SEEK_SET : return "SEEK_SET";
case SEEK_CUR : return "SEEK_CUR";
case SEEK_END : return "SEEK_END";
default : return "UNKNOWN";
}
return "UNKNOWN";
}
void
lseek_exec(const lseek_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_RDONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("open(pathname=\"{}\") = {}, errno: {} [{}]\n",
opts.pathname, fd, errno, ::strerror(errno));
return;
}
json out = lseek_output{fd, errno};
fmt::print("{}\n", out.dump(2));
return;
}
int rv = ::lseek(fd, opts.offset, opts.whence);
if(opts.verbose) {
fmt::print("lseek(pathname=\"{}\", offset='{}', whence='{}') = {}, errno: {} [{}]\n",
opts.pathname, opts.offset, whence2str(opts.whence), rv, errno, ::strerror(errno));
return;
}
json out = lseek_output{rv, errno};
fmt::print("{}\n", out.dump(2));
}
void
lseek_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<lseek_options>();
auto* cmd = app.add_subcommand(
"lseek",
"Execute the lseek() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human writeable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"offset",
opts->offset,
"offset used"
)
->required()
->type_name("");
cmd->add_option(
"whence",
opts->whence,
"Whence the action is done"
)
->required()
->type_name("");
cmd->callback([opts]() {
lseek_exec(*opts);
});
}
......@@ -24,10 +24,18 @@ init_commands(CLI::App& app) {
opendir_init(app);
mkdir_init(app);
read_init(app);
pread_init(app);
readv_init(app);
preadv_init(app);
readdir_init(app);
rmdir_init(app);
stat_init(app);
write_init(app);
pwrite_init(app);
writev_init(app);
pwritev_init(app);
statx_init(app);
lseek_init(app);
}
......
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct pread_options {
bool verbose;
std::string pathname;
::size_t count;
::size_t offset;
REFL_DECL_STRUCT(pread_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(::size_t, count),
REFL_DECL_MEMBER(::size_t, offset)
);
};
struct pread_output {
::ssize_t retval;
io::buffer buf;
int errnum;
REFL_DECL_STRUCT(pread_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(void*, buf),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const pread_output& out) {
record = serialize(out);
}
void
pread_exec(const pread_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_RDONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("pread(pathname=\"{}\", count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count, opts.offset, fd, errno, ::strerror(errno));
return;
}
json out = pread_output{fd, nullptr, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf(opts.count);
int rv = ::pread(fd, buf.data(), opts.count, opts.offset);
if(opts.verbose) {
fmt::print("pread(pathname=\"{}\", count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count, opts.offset, rv, errno, ::strerror(errno));
return;
}
json out = pread_output{rv, (rv != -1 ? buf : nullptr), errno};
fmt::print("{}\n", out.dump(2));
}
void
pread_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<pread_options>();
auto* cmd = app.add_subcommand(
"pread",
"Execute the pread() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human readable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"count",
opts->count,
"Number of bytes to read"
)
->required()
->type_name("");
cmd->add_option(
"offset",
opts->offset,
"Offset to read"
)
->required()
->type_name("");
cmd->callback([opts]() {
pread_exec(*opts);
});
}
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct preadv_options {
bool verbose;
std::string pathname;
::size_t count_0;
::size_t count_1;
::size_t offset;
REFL_DECL_STRUCT(preadv_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(::size_t, count_0),
REFL_DECL_MEMBER(::size_t, count_1),
REFL_DECL_MEMBER(::size_t, offset)
);
};
struct preadv_output {
::ssize_t retval;
io::buffer buf_0;
io::buffer buf_1;
int errnum;
REFL_DECL_STRUCT(preadv_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(void*, buf_0),
REFL_DECL_MEMBER(void*, buf_1),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const preadv_output& out) {
record = serialize(out);
}
void
preadv_exec(const preadv_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_RDONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("preadv(pathname=\"{}\", count_0={}, count_1={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count_0, opts.count_1, opts.offset, fd, errno, ::strerror(errno));
return;
}
json out = preadv_output{fd, nullptr, nullptr, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf_0(opts.count_0);
io::buffer buf_1(opts.count_1);
struct iovec iov[2];
iov[0].iov_base = buf_0.data();
iov[1].iov_base = buf_1.data();
iov[0].iov_len = opts.count_0;
iov[1].iov_len = opts.count_1;
int rv = ::preadv(fd, iov, 2, opts.offset);
if(opts.verbose) {
fmt::print("preadv(pathname=\"{}\", count_0={}, count_1={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count_0, opts.count_1, opts.offset, rv, errno, ::strerror(errno));
return;
}
json out = preadv_output{rv, (rv != -1 ? buf_0 : nullptr), (rv != -1 ? buf_1 : nullptr), errno};
fmt::print("{}\n", out.dump(2));
}
void
preadv_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<preadv_options>();
auto* cmd = app.add_subcommand(
"preadv",
"Execute the preadv() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human readable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"count_0",
opts->count_0,
"Number of bytes to read to buffer 0"
)
->required()
->type_name("");
cmd->add_option(
"count_1",
opts->count_1,
"Number of bytes to read to buffer 1"
)
->required()
->type_name("");
cmd->add_option(
"offset",
opts->offset,
"Offset to read"
)
->required()
->type_name("");
cmd->callback([opts]() {
preadv_exec(*opts);
});
}
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct pwrite_options {
bool verbose;
std::string pathname;
std::string data;
::size_t count;
::size_t offset;
REFL_DECL_STRUCT(pwrite_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(std::string, data),
REFL_DECL_MEMBER(::size_t, count),
REFL_DECL_MEMBER(::size_t, offset)
);
};
struct pwrite_output {
::ssize_t retval;
int errnum;
REFL_DECL_STRUCT(pwrite_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const pwrite_output& out) {
record = serialize(out);
}
void
pwrite_exec(const pwrite_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_WRONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("pwrite(pathname=\"{}\", buf=\"{}\" count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.data, opts.count, opts.offset, fd, errno, ::strerror(errno));
return;
}
json out = pwrite_output{fd, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf(opts.data);
int rv = ::pwrite(fd, buf.data(), opts.count, opts.offset);
if(opts.verbose) {
fmt::print("pwrite(pathname=\"{}\", count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count, opts.offset, rv, errno, ::strerror(errno));
return;
}
json out = pwrite_output{rv, errno};
fmt::print("{}\n", out.dump(2));
}
void
pwrite_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<pwrite_options>();
auto* cmd = app.add_subcommand(
"pwrite",
"Execute the pwrite() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human writeable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"data",
opts->data,
"Data to write"
)
->required()
->type_name("");
cmd->add_option(
"count",
opts->count,
"Number of bytes to write"
)
->required()
->type_name("");
cmd->add_option(
"offset",
opts->offset,
"Offset to read"
)
->required()
->type_name("");
cmd->callback([opts]() {
pwrite_exec(*opts);
});
}
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct pwritev_options {
bool verbose;
std::string pathname;
std::string data_0, data_1;
::size_t count;
::size_t offset;
REFL_DECL_STRUCT(pwritev_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(std::string, data_0),
REFL_DECL_MEMBER(std::string, data_1),
REFL_DECL_MEMBER(::size_t, count),
REFL_DECL_MEMBER(::size_t, offset)
);
};
struct pwritev_output {
::ssize_t retval;
int errnum;
REFL_DECL_STRUCT(pwritev_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const pwritev_output& out) {
record = serialize(out);
}
void
pwritev_exec(const pwritev_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_WRONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("pwritev(pathname=\"{}\", buf_0=\"{}\" buf_1=\"{}\" count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.data_0, opts.data_1, opts.count, opts.offset, fd, errno, ::strerror(errno));
return;
}
json out = pwritev_output{fd, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf_0(opts.data_0);
io::buffer buf_1(opts.data_1);
struct iovec iov[2];
iov[0].iov_base = buf_0.data();
iov[1].iov_base = buf_1.data();
iov[0].iov_len = buf_0.size();
iov[1].iov_len = buf_1.size();
int rv = ::pwritev(fd, iov, opts.count, opts.offset);
if(opts.verbose) {
fmt::print("pwritev(pathname=\"{}\", count={}, offset={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count, opts.offset, rv, errno, ::strerror(errno));
return;
}
json out = pwritev_output{rv, errno};
fmt::print("{}\n", out.dump(2));
}
void
pwritev_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<pwritev_options>();
auto* cmd = app.add_subcommand(
"pwritev",
"Execute the pwritev() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human writeable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"data_0",
opts->data_0,
"Data 0 to write"
)
->required()
->type_name("");
cmd->add_option(
"data_1",
opts->data_1,
"Data 1 to write"
)
->required()
->type_name("");
cmd->add_option(
"count",
opts->count,
"Number of bytes to write"
)
->required()
->type_name("");
cmd->add_option(
"offset",
opts->offset,
"Offset to read"
)
->required()
->type_name("");
cmd->callback([opts]() {
pwritev_exec(*opts);
});
}
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct readv_options {
bool verbose;
std::string pathname;
::size_t count_0;
::size_t count_1;
REFL_DECL_STRUCT(readv_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(::size_t, count_0),
REFL_DECL_MEMBER(::size_t, count_1)
);
};
struct readv_output {
::ssize_t retval;
io::buffer buf_0;
io::buffer buf_1;
int errnum;
REFL_DECL_STRUCT(readv_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(void*, buf_0),
REFL_DECL_MEMBER(void*, buf_1),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const readv_output& out) {
record = serialize(out);
}
void
readv_exec(const readv_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_RDONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("readv(pathname=\"{}\", count_0={}, count_1={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count_0, opts.count_1, fd, errno, ::strerror(errno));
return;
}
json out = readv_output{fd, nullptr, nullptr, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf_0(opts.count_0);
io::buffer buf_1(opts.count_1);
struct iovec iov[2];
iov[0].iov_base = buf_0.data();
iov[1].iov_base = buf_1.data();
iov[0].iov_len = opts.count_0;
iov[1].iov_len = opts.count_1;
int rv = ::readv(fd, iov, 2);
if(opts.verbose) {
fmt::print("readv(pathname=\"{}\", count_0={}, count_1={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count_0, opts.count_1, rv, errno, ::strerror(errno));
return;
}
json out = readv_output{rv, (rv != -1 ? buf_0 : nullptr), (rv != -1 ? buf_1 : nullptr), errno};
fmt::print("{}\n", out.dump(2));
}
void
readv_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<readv_options>();
auto* cmd = app.add_subcommand(
"readv",
"Execute the readv() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human readable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"count_0",
opts->count_0,
"Number of bytes to read to buffer 0"
)
->required()
->type_name("");
cmd->add_option(
"count_1",
opts->count_1,
"Number of bytes to read to buffer 1"
)
->required()
->type_name("");
cmd->callback([opts]() {
readv_exec(*opts);
});
}
......@@ -105,6 +105,20 @@ struct adl_serializer<struct ::timespec> {
}
};
// ADL specialization for struct ::statx_timestamp type
template <>
struct adl_serializer<struct ::statx_timestamp> {
static void to_json(json& j, const struct ::statx_timestamp opt) {
j = json {
{ "tv_sec", opt.tv_sec },
{ "tv_nsec", opt.tv_nsec }
};
}
};
// ADL specialization for struct ::dirent type
template <>
struct adl_serializer<struct ::dirent> {
......@@ -148,6 +162,37 @@ struct adl_serializer<struct ::stat> {
}
};
// ADL specialization for struct ::statx type
template <>
struct adl_serializer<struct ::statx> {
static void to_json(json& j, const struct ::statx opt) {
j = json {
{ "stx_mask", opt.stx_mask },
{ "stx_blksize", opt.stx_blksize },
{ "stx_attributes", opt.stx_attributes},
{ "stx_nlink", opt.stx_nlink },
{ "stx_uid", opt.stx_uid },
{ "stx_gid", opt.stx_gid },
{ "stx_mode", opt.stx_mode },
{ "stx_ino", opt.stx_ino },
{ "stx_size", opt.stx_size },
{ "stx_blocks", opt.stx_blocks },
{ "stx_attributes_mask", opt.stx_attributes_mask},
{ "stx_atime", opt.stx_atime },
{ "stx_btime", opt.stx_btime },
{ "stx_ctime", opt.stx_ctime },
{ "stx_mtime", opt.stx_mtime },
{ "stx_rdev_major", opt.stx_rdev_major },
{ "stx_rdev_minor", opt.stx_rdev_minor },
{ "stx_dev_major", opt.stx_dev_major },
{ "stx_dev_minor", opt.stx_dev_minor }
};
}
};
} // namespace nlohmann
namespace fmt {
......
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h> /* Definition of AT_* constants */
using json = nlohmann::json;
/* int statx(int dirfd, const char *pathname, int flags,
unsigned int mask, struct statx *statxbuf);
*/
struct statx_options {
bool verbose;
int dirfd;
std::string pathname;
int flags;
unsigned int mask;
REFL_DECL_STRUCT(statx_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(int, dirfd),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(int, flags),
REFL_DECL_MEMBER(unsigned int, mask)
);
};
struct statx_output {
int retval;
int errnum;
struct ::statx statbuf;
REFL_DECL_STRUCT(statx_output,
REFL_DECL_MEMBER(int, retval),
REFL_DECL_MEMBER(int, errnum),
REFL_DECL_MEMBER(struct ::statx, statbuf)
);
};
void
to_json(json& record,
const statx_output& out) {
record = serialize(out);
}
void
statx_exec(const statx_options& opts) {
struct ::statx statbuf;
int rv = ::statx(opts.dirfd, opts.pathname.c_str(), opts.flags, opts.mask, &statbuf);
if(opts.verbose) {
fmt::print("statx(dirfd={}, pathname=\"{}\", flags={}, mask={}) = {}, errno: {} [{}]\n",
opts.dirfd, opts.pathname, opts.flags, opts.mask, rv, errno, ::strerror(errno));
return;
}
json out = statx_output{rv, errno, statbuf};
fmt::print("{}\n", out.dump(2));
}
void
statx_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<statx_options>();
auto* cmd = app.add_subcommand(
"statx",
"Execute the statx() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human readable output"
);
cmd->add_option(
"dirfd",
opts->dirfd,
"file descritor"
)
->required()
->type_name("");
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"flags",
opts->flags,
"Flags"
)
->required()
->type_name("");
cmd->add_option(
"mask",
opts->mask,
"Mask"
)
->required()
->type_name("");
cmd->callback([opts]() {
statx_exec(*opts);
});
}
/*
Copyright 2018-2020, Barcelona Supercomputing Center (BSC), Spain
Copyright 2015-2020, Johannes Gutenberg Universitaet Mainz, Germany
This software was partially supported by the
EC H2020 funded project NEXTGenIO (Project ID: 671951, www.nextgenio.eu).
This software was partially supported by the
ADA-FS project under the SPPEXA project funded by the DFG.
SPDX-License-Identifier: MIT
*/
/* C++ includes */
#include <CLI/CLI.hpp>
#include <nlohmann/json.hpp>
#include <memory>
#include <fmt/format.h>
#include <commands.hpp>
#include <reflection.hpp>
#include <serialize.hpp>
#include <binary_buffer.hpp>
/* C includes */
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/uio.h>
#include <fcntl.h>
#include <unistd.h>
using json = nlohmann::json;
struct writev_options {
bool verbose;
std::string pathname;
std::string data_0, data_1;
::size_t count;
REFL_DECL_STRUCT(writev_options,
REFL_DECL_MEMBER(bool, verbose),
REFL_DECL_MEMBER(std::string, pathname),
REFL_DECL_MEMBER(std::string, data_0),
REFL_DECL_MEMBER(std::string, data_1),
REFL_DECL_MEMBER(::size_t, count)
);
};
struct writev_output {
::ssize_t retval;
int errnum;
REFL_DECL_STRUCT(writev_output,
REFL_DECL_MEMBER(::size_t, retval),
REFL_DECL_MEMBER(int, errnum)
);
};
void
to_json(json& record,
const writev_output& out) {
record = serialize(out);
}
void
writev_exec(const writev_options& opts) {
int fd = ::open(opts.pathname.c_str(), O_WRONLY);
if(fd == -1) {
if(opts.verbose) {
fmt::print("writev(pathname=\"{}\", buf_0=\"{}\" buf_1=\"{}\" count={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.data_0, opts.data_1, opts.count, fd, errno, ::strerror(errno));
return;
}
json out = writev_output{fd, errno};
fmt::print("{}\n", out.dump(2));
return;
}
io::buffer buf_0(opts.data_0);
io::buffer buf_1(opts.data_1);
struct iovec iov[2];
iov[0].iov_base = buf_0.data();
iov[1].iov_base = buf_1.data();
iov[0].iov_len = buf_0.size();
iov[1].iov_len = buf_1.size();
int rv = ::writev(fd, iov, opts.count);
if(opts.verbose) {
fmt::print("writev(pathname=\"{}\", count={}) = {}, errno: {} [{}]\n",
opts.pathname, opts.count, rv, errno, ::strerror(errno));
return;
}
json out = writev_output{rv, errno};
fmt::print("{}\n", out.dump(2));
}
void
writev_init(CLI::App& app) {
// Create the option and subcommand objects
auto opts = std::make_shared<writev_options>();
auto* cmd = app.add_subcommand(
"writev",
"Execute the writev() system call");
// Add options to cmd, binding them to opts
cmd->add_flag(
"-v,--verbose",
opts->verbose,
"Produce human writeable output"
);
cmd->add_option(
"pathname",
opts->pathname,
"Directory name"
)
->required()
->type_name("");
cmd->add_option(
"data_0",
opts->data_0,
"Data 0 to write"
)
->required()
->type_name("");
cmd->add_option(
"data_1",
opts->data_1,
"Data 1 to write"
)
->required()
->type_name("");
cmd->add_option(
"count",
opts->count,
"Number of bytes to write"
)
->required()
->type_name("");
cmd->callback([opts]() {
writev_exec(*opts);
});
}
......@@ -67,6 +67,51 @@ class StructStatSchema(Schema):
'st_gid', 'st_rdev', 'st_size', 'st_blksize', 'st_blocks',
'st_atim', 'st_mtim', 'st_ctim'])(**data)
class StructStatxTimestampSchema(Schema):
"""Schema that deserializes a struct timespec"""
tv_sec = fields.Integer(required=True)
tv_nsec = fields.Integer(required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('StructStatxTimestampSchema',
['tv_sec', 'tv_nsec'])(**data)
class StructStatxSchema(Schema):
"""Schema that deserializes a struct stat"""
stx_mask = fields.Integer(required=True)
stx_blksize = fields.Integer(required=True)
stx_attributes = fields.Integer(required=True)
stx_nlink = fields.Integer(required=True)
stx_uid = fields.Integer(required=True)
stx_gid = fields.Integer(required=True)
stx_mode = fields.Integer(required=True)
stx_ino = fields.Integer(required=True)
stx_size = fields.Integer(required=True)
stx_blocks = fields.Integer(required=True)
stx_attributes_mask = fields.Integer(required=True)
stx_atime = fields.Nested(StructStatxTimestampSchema)
stx_btime = fields.Nested(StructStatxTimestampSchema)
stx_ctime = fields.Nested(StructStatxTimestampSchema)
stx_mtime = fields.Nested(StructStatxTimestampSchema)
stx_rdev_major = fields.Integer(required=True)
stx_rdev_minor = fields.Integer(required=True)
stx_dev_major = fields.Integer(required=True)
stx_dev_minor = fields.Integer(required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('StructStatx',
['stx_mask', 'stx_blksize', 'stx_attributes', 'stx_nlink', 'stx_uid',
'stx_gid', 'stx_mode', 'stx_ino', 'stx_size', 'stx_blocks', 'stx_attributes_mask',
'stx_atime', 'stx_btime', 'stx_ctime', 'stx_mtime', 'stx_rdev_major',
'stx_rdev_minor', 'stx_dev_major', 'stx_dev_minor'])(**data)
class DirentStruct(Schema):
"""Schema that deserializes a struct dirent"""
......@@ -120,6 +165,41 @@ class ReadOutputSchema(Schema):
def make_object(self, data, **kwargs):
return namedtuple('ReadReturn', ['buf', 'retval', 'errno'])(**data)
class PreadOutputSchema(Schema):
"""Schema to deserialize the results of a pread() execution"""
buf = ByteList(allow_none=True)
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('PReadReturn', ['buf', 'retval', 'errno'])(**data)
class ReadvOutputSchema(Schema):
"""Schema to deserialize the results of a read() execution"""
buf_0 = ByteList(allow_none=True)
buf_1 = ByteList(allow_none=True)
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('ReadvReturn', ['buf_0', 'buf_1', 'retval', 'errno'])(**data)
class PreadvOutputSchema(Schema):
"""Schema to deserialize the results of a read() execution"""
buf_0 = ByteList(allow_none=True)
buf_1 = ByteList(allow_none=True)
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('PReadvReturn', ['buf_0', 'buf_1', 'retval', 'errno'])(**data)
class ReaddirOutputSchema(Schema):
"""Schema to deserialize the results of a readdir() execution"""
......@@ -150,6 +230,36 @@ class WriteOutputSchema(Schema):
def make_object(self, data, **kwargs):
return namedtuple('WriteReturn', ['retval', 'errno'])(**data)
class PwriteOutputSchema(Schema):
"""Schema to deserialize the results of a pwrite() execution"""
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('PWriteReturn', ['retval', 'errno'])(**data)
class WritevOutputSchema(Schema):
"""Schema to deserialize the results of a writev() execution"""
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('WritevReturn', ['retval', 'errno'])(**data)
class PwritevOutputSchema(Schema):
"""Schema to deserialize the results of a writev() execution"""
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('PWritevReturn', ['retval', 'errno'])(**data)
class StatOutputSchema(Schema):
"""Schema to deserialize the results of a stat() execution"""
......@@ -162,6 +272,27 @@ class StatOutputSchema(Schema):
return namedtuple('StatReturn', ['retval', 'statbuf', 'errno'])(**data)
class StatxOutputSchema(Schema):
"""Schema to deserialize the results of a stat() execution"""
retval = fields.Integer(required=True)
statbuf = fields.Nested(StructStatxSchema, required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('StatxReturn', ['retval', 'statbuf', 'errno'])(**data)
class LseekOutputSchema(Schema):
"""Schema to deserialize the results of an open() execution"""
retval = fields.Integer(required=True)
errno = Errno(data_key='errnum', required=True)
@post_load
def make_object(self, data, **kwargs):
return namedtuple('LseekReturn', ['retval', 'errno'])(**data)
class IOParser:
OutputSchemas = {
......@@ -169,10 +300,18 @@ class IOParser:
'open' : OpenOutputSchema(),
'opendir' : OpendirOutputSchema(),
'read' : ReadOutputSchema(),
'pread' : PreadOutputSchema(),
'readv' : ReadvOutputSchema(),
'preadv' : PreadvOutputSchema(),
'readdir' : ReaddirOutputSchema(),
'rmdir' : RmdirOutputSchema(),
'write' : WriteOutputSchema(),
'pwrite' : PwriteOutputSchema(),
'writev' : WritevOutputSchema(),
'pwritev' : PwritevOutputSchema(),
'stat' : StatOutputSchema(),
'statx' : StatxOutputSchema(),
'lseek' : LseekOutputSchema(),
}
def parse(self, command, output):
......