#include "webfuse/provider.hpp" #include "webfuse/ws/client.hpp" #include #include #include #include namespace webfuse { class provider::detail { public: detail(filesystem_i & fs, std::string const & ca_path) : fs_(fs) , client(ca_path, [this](auto& reader) { return this->on_message(reader); }) { } ~detail() { } void connect(std::string const & url) { client.connect(url); } void service() { client.service(); } void interrupt() { client.interrupt(); } void set_connection_listener(std::function listener) { client.set_connection_listener(listener); } messagewriter on_message(messagereader & reader) { auto const message_id = reader.read_u32(); auto const req_type = get_request_type(reader.read_u8()); auto const resp_type = get_response_type(req_type); messagewriter writer(resp_type); writer.set_id(message_id); switch (req_type) { case request_type::access: fs_access(reader, writer); break; case request_type::getattr: fs_getattr(reader, writer); break; case request_type::readlink: fs_readlink(reader, writer); break; case request_type::symlink: fs_symlink(reader, writer); break; case request_type::link: fs_link(reader, writer); break; case request_type::rename: fs_rename(reader, writer); break; case request_type::chmod: fs_chmod(reader, writer); break; case request_type::chown: fs_chown(reader, writer); break; case request_type::truncate: fs_truncate(reader, writer); break; case request_type::fsync: fs_fsync(reader, writer); break; case request_type::utimens: fs_utimens(reader, writer); break; case request_type::open: fs_open(reader, writer); break; case request_type::mknod: fs_mknod(reader, writer); break; case request_type::create: fs_create(reader, writer); break; case request_type::release: fs_release(reader, writer); break; case request_type::unlink: fs_unlink(reader, writer); break; case request_type::read: fs_read(reader, writer); break; case request_type::write: fs_write(reader, writer); break; case request_type::mkdir: fs_mkdir(reader, writer); break; case request_type::readdir: fs_readdir(reader, writer); break; case request_type::rmdir: fs_rmdir(reader, writer); break; case request_type::statfs: fs_statfs(reader, writer); break; case request_type::getcreds: fs_get_credentials(reader, writer); break; default: std::cout << "unknown request: " << ((int) req_type) << std::endl; break; } return std::move(writer); } private: void fs_access(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const mode = reader.read_access_mode(); auto const result = fs_.access(path, mode); writer.write_i32(result); } void fs_getattr(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); struct stat buffer; auto const result = fs_.getattr(path, &buffer); writer.write_i32(result); if (0 == result) { writer.write_attr(&buffer); } } void fs_readlink(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); std::string out; auto const result = fs_.readlink(path, out); writer.write_i32(result); if (0 == result) { writer.write_str(out); } } void fs_symlink(messagereader & reader, messagewriter & writer) { auto const from = reader.read_str(); auto const to = reader.read_str(); auto const result = fs_.symlink(from, to); writer.write_i32(result); } void fs_link(messagereader & reader, messagewriter & writer) { auto const from = reader.read_str(); auto const to = reader.read_str(); auto const result = fs_.link(from, to); writer.write_i32(result); } void fs_rename(messagereader & reader, messagewriter & writer) { auto const from = reader.read_str(); auto const to = reader.read_str(); auto const flags = reader.read_u8(); auto const result = fs_.rename(from, to, flags); writer.write_i32(result); } void fs_chmod(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const mode = reader.read_mode(); auto const result = fs_.chmod(path, mode); writer.write_i32(result); } void fs_chown(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const uid = static_cast(reader.read_u32()); auto const gid = static_cast(reader.read_u32()); auto const result = fs_.chown(path, uid, gid); writer.write_i32(result); } void fs_truncate(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const size = reader.read_u64(); auto const handle = reader.read_u64(); auto const result = fs_.truncate(path, size, handle); writer.write_i32(result); } void fs_fsync(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const is_datasync = reader.read_bool(); auto const handle = reader.read_u64(); auto const result = fs_.fsync(path, is_datasync, handle); writer.write_i32(result); } void fs_utimens(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); struct timespec times[2]; reader.read_time(times[0]); reader.read_time(times[1]); auto const handle = reader.read_u64(); auto const result = fs_.utimens(path, times, handle); writer.write_i32(result); } void fs_open(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const flags = reader.read_openflags(); uint64_t handle = static_cast(-1); auto const result = fs_.open(path, flags, handle); writer.write_i32(result); if (result == 0) { writer.write_u64(handle); } } void fs_mknod(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const mode = reader.read_mode(); auto const dev = reader.read_u32(); auto const result = fs_.mknod(path, mode, dev); writer.write_i32(result); } void fs_create(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const mode = reader.read_mode(); uint64_t handle = static_cast(-1); auto const result = fs_.create(path, mode, handle); writer.write_i32(result); if (result == 0) { writer.write_u64(handle); } } void fs_release(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const handle = reader.read_u64(); auto const result = fs_.release(path, handle); writer.write_i32(result); } void fs_unlink(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const result = fs_.unlink(path); writer.write_i32(result); } void fs_read(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const size = reader.read_u32(); auto const offset = reader.read_u64(); auto const handle = reader.read_u64(); std::vector buffer(size); auto const result = fs_.read(path, buffer.data(), size, offset, handle); writer.write_i32(result); if (0 < result) { writer.write_data(buffer.data(), result); } } void fs_write(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const buffer = reader.read_bytes(); auto const offset = reader.read_u64(); auto const handle = reader.read_u64(); auto const result = fs_.write(path, buffer.c_str(), buffer.size(), offset, handle); writer.write_i32(result); } void fs_mkdir(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const mode = reader.read_mode(); auto const result = fs_.mkdir(path, mode); writer.write_i32(result); } void fs_rmdir(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); auto const result = fs_.rmdir(path); writer.write_i32(result); } void fs_readdir(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); std::vector entries; auto const result = fs_.readdir(path, entries); writer.write_i32(result); if (0 == result) { writer.write_strings(entries); } } void fs_statfs(messagereader & reader, messagewriter & writer) { auto const path = reader.read_str(); struct statvfs statistics; memset(reinterpret_cast(&statistics), 0, sizeof(statistics)); auto const result = fs_.statfs(path, &statistics); writer.write_i32(result); if (0 == result) { writer.write_statistics(&statistics); } } void fs_get_credentials(messagereader & reader, messagewriter & writer) { std::string credentials = fs_.get_credentials(); writer.write_str(credentials); } filesystem_i & fs_; ws_client client; }; provider::provider(filesystem_i & fs, std::string const & ca_path) : d(new detail(fs, ca_path)) { } provider::~provider() { delete d; } provider::provider(provider && other) { this->d = other.d; other.d = nullptr; } provider& provider::operator=(provider && other) { if (this != &other) { delete this->d; this->d = other.d; other.d = nullptr; } return *this; } void provider::connect(std::string const & url) { d->connect(url); } void provider::service() { d->service(); } void provider::interrupt() { d->interrupt(); } void provider::set_connection_listener(std::function listener) { d->set_connection_listener(listener); } }