summaryrefslogtreecommitdiff
path: root/libs/samba/src/main/cpp/samba.cpp
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@spawned.biz>2024-07-22 23:06:16 +0200
committerJoel Klinghed <the_jk@spawned.biz>2024-07-23 00:04:58 +0200
commit09bc93ed756361d396890c389b01315cdb5e32fd (patch)
tree3a2718a2b5a3584a489d009a532526239f6b45a5 /libs/samba/src/main/cpp/samba.cpp
parent42564c71cfb70c28831c662a3b6bf4084e079353 (diff)
Add initial code for samba implementation based on libsmb2
Diffstat (limited to 'libs/samba/src/main/cpp/samba.cpp')
-rw-r--r--libs/samba/src/main/cpp/samba.cpp155
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;
+}