diff options
Diffstat (limited to 'libs/samba/src/main/cpp/samba.cpp')
| -rw-r--r-- | libs/samba/src/main/cpp/samba.cpp | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/libs/samba/src/main/cpp/samba.cpp b/libs/samba/src/main/cpp/samba.cpp new file mode 100644 index 0000000..5eafacc --- /dev/null +++ b/libs/samba/src/main/cpp/samba.cpp @@ -0,0 +1,155 @@ +#include <cassert> +#include <jni.h> +#include <memory> +#include <string> +#include <string_view> +#include <utility> + +#include "jni.hpp" +#include "libsmb2.h" + +namespace { + +class Dir { + public: + Dir(std::shared_ptr<smb2_context> context, smb2dir* dir) : context_(std::move(context)), dir_(dir) { + assert(context_ && dir_); + } + + ~Dir() { + smb2_closedir(context_.get(), dir_); + } + + Dir(const Dir&) = delete; + Dir& operator=(const Dir&) = delete; + + private: + std::shared_ptr<smb2_context> context_; + smb2dir* const dir_; +}; + +class Url { + public: + explicit Url(smb2_url* url) : url_(url) { + assert(url_); + } + + ~Url() { + smb2_destroy_url(url_); + } + + Url(const Url&) = delete; + Url& operator=(const Url&) = delete; + + [[nodiscard]] const char* path() const { return url_->path; } + [[nodiscard]] const char* server() const { return url_->server; } + [[nodiscard]] const char* share() const { return url_->share; } + [[nodiscard]] const char* user() const { return url_->user; } + + private: + smb2_url* url_; +}; + +class Context { + public: + Context() : context_(smb2_init_context(), ContextDeleter{}) {} + ~Context() = default; + + Context(const Context&) = delete; + Context& operator=(const Context&) = delete; + + [[nodiscard]] std::unique_ptr<Url> ParseUrl(const std::string& url) { + auto* ptr = smb2_parse_url(context_.get(), url.c_str()); + return ptr ? std::make_unique<Url>(ptr): nullptr; + } + + bool Connect(const Url& url) { + return smb2_connect_share(context_.get(), url.server(), url.share(), url.user()) == 0; + } + + [[nodiscard]] std::string_view GetError() { + return smb2_get_error(context_.get()); + } + + [[nodiscard]] std::unique_ptr<Dir> OpenDir(const std::string& path) { + auto* ptr = smb2_opendir(context_.get(), path.c_str()); + return ptr ? std::make_unique<Dir>(context_, ptr) : nullptr; + } + + private: + struct ContextDeleter { + void operator()(smb2_context* context) { + smb2_destroy_context(context); + } + }; + + std::shared_ptr<smb2_context> context_; +}; + +jlong nativeContextNew(JNIEnv* env, jclass clazz) { + return reinterpret_cast<jlong>(new Context()); +} + +void nativeContextDestroy(JNIEnv* env, jclass clazz, jlong ptr) { + delete reinterpret_cast<Context*>(ptr); +} + +jlong nativeContextParseUrl(JNIEnv* env, jclass clazz, jlong ptr, jstring url) { + return reinterpret_cast<jlong>(reinterpret_cast<Context*>(ptr)->ParseUrl(jni::StringToUTF8(env, jni::ParamRef(env, url))).release()); +} + +jboolean nativeContextConnect(JNIEnv* env, jclass clazz, jlong context_ptr, jlong url_ptr) { + auto* url = reinterpret_cast<Url*>(url_ptr); + if (!url) return JNI_FALSE; + return reinterpret_cast<Context*>(context_ptr)->Connect(*url) ? JNI_TRUE : JNI_FALSE; +} + +jstring nativeContextGetError(JNIEnv* env, jclass clazz, jlong ptr) { + return jni::UTF8ToString(env, std::string(reinterpret_cast<Context*>(ptr)->GetError())).release(); +} + +jlong nativeContextOpenDir(JNIEnv* env, jclass clazz, jlong ptr, jstring path) { + return reinterpret_cast<jlong>(reinterpret_cast<Context*>(ptr)->OpenDir(jni::StringToUTF8(env, jni::ParamRef<jstring>(env, path))).release()); +} + +void nativeUrlDestroy(JNIEnv* env, jclass clazz, jlong ptr) { + delete reinterpret_cast<Url*>(ptr); +} + +jstring nativeUrlPath(JNIEnv* env, jclass clazz, jlong ptr) { + return jni::UTF8ToString(env, std::string(reinterpret_cast<Url*>(ptr)->path())).release(); +} + +void nativeDirDestroy(JNIEnv* env, jclass clazz, jlong ptr) { + delete reinterpret_cast<Dir*>(ptr); +} + +void RegisterSamba(JNIEnv* env) { + auto clazz = jni::FindClass(env, "org/the_jk/cleversync/io/samba/NativeSamba"); + ABORT_IF_NULL(env, clazz); + static const JNINativeMethod methods[] = { + { "nativeContextNew", "()J", reinterpret_cast<void*>(&nativeContextNew) }, + { "nativeContextDestroy", "(J)V", reinterpret_cast<void*>(&nativeContextDestroy) }, + { "nativeContextParseUrl", "(JLjava/lang/String;)J", reinterpret_cast<void*>(&nativeContextParseUrl) }, + { "nativeContextConnect", "(JJ)Z", reinterpret_cast<void*>(&nativeContextConnect) }, + { "nativeContextGetError", "(J)Ljava/lang/String;", reinterpret_cast<void*>(&nativeContextGetError) }, + { "nativeContextOpenDir", "(JLjava/lang/String;)J", reinterpret_cast<void*>(&nativeContextOpenDir) }, + + { "nativeUrlDestroy", "(J)V", reinterpret_cast<void*>(&nativeUrlDestroy) }, + { "nativeUrlPath", "(J)Ljava/lang/String;", reinterpret_cast<void*>(&nativeUrlPath) }, + + { "nativeDirDestroy", "(J)V", reinterpret_cast<void*>(&nativeDirDestroy) }, + }; + auto ret = env->RegisterNatives(clazz.get(), methods, sizeof(methods) / sizeof(methods[0])); + ABORT_IF_NOT_OK(ret); +} + +} // namespace + +jint JNI_OnLoad(JavaVM *vm, void *reserved) { + auto* env = jni::OnLoad(vm); + + RegisterSamba(env); + + return jni::JNI_VERSION; +} |
