summaryrefslogtreecommitdiff
path: root/libs/samba/src/main/cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/samba/src/main/cpp')
-rw-r--r--libs/samba/src/main/cpp/jni.hpp2
-rw-r--r--libs/samba/src/main/cpp/samba.cpp141
2 files changed, 142 insertions, 1 deletions
diff --git a/libs/samba/src/main/cpp/jni.hpp b/libs/samba/src/main/cpp/jni.hpp
index 3b5078a..1729828 100644
--- a/libs/samba/src/main/cpp/jni.hpp
+++ b/libs/samba/src/main/cpp/jni.hpp
@@ -51,7 +51,7 @@ class Ref {
T ptr_;
};
-constexpr jint JNI_VERSION = JNI_VERSION_1_2;
+constexpr jint JNI_VERSION = JNI_VERSION_1_4;
JNIEnv* AttachCurrentThread();
diff --git a/libs/samba/src/main/cpp/samba.cpp b/libs/samba/src/main/cpp/samba.cpp
index 1e6b425..4a8af51 100644
--- a/libs/samba/src/main/cpp/samba.cpp
+++ b/libs/samba/src/main/cpp/samba.cpp
@@ -1,7 +1,9 @@
#include <algorithm>
#include <cassert>
+#include <fcntl.h>
#include <jni.h>
#include <memory>
+#include <limits>
#include <optional>
#include <string>
#include <string_view>
@@ -46,6 +48,74 @@ class Dir {
smb2dir* const dir_;
};
+class File {
+ public:
+ File(std::shared_ptr<smb2_context> context, smb2fh* fh) : context_(std::move(context)), fh_(fh) {
+ assert(context_ && fh_);
+ }
+
+ ~File() {
+ smb2_close(context_.get(), fh_);
+ }
+
+ File(const File&) = delete;
+ File& operator=(const File&) = delete;
+
+ int32_t read(uint8_t* data, int32_t size) {
+ if (size <= 0) return 0;
+ int32_t total = 0;
+ while (size > std::numeric_limits<int>::max()) {
+ int ret = smb2_read(context_.get(), fh_, data,
+ std::numeric_limits<int>::max());
+ if (ret < 0) return total ? total : ret;
+ if (ret != std::numeric_limits<int>::max())
+ return total + ret;
+ data += ret;
+ size -= ret;
+ }
+ int ret = smb2_read(context_.get(), fh_, data, size);
+ if (ret < 0) return total ? total : ret;
+ return total + ret;
+ }
+
+ int32_t write(const uint8_t* data, int32_t size) {
+ if (size <= 0) return 0;
+ int32_t total = 0;
+ while (size > std::numeric_limits<int>::max()) {
+ int ret = smb2_write(context_.get(), fh_, data,
+ std::numeric_limits<int>::max());
+ if (ret < 0) return total ? total : ret;
+ if (ret != std::numeric_limits<int>::max())
+ return total + ret;
+ data += ret;
+ size -= ret;
+ }
+ int ret = smb2_write(context_.get(), fh_, data, size);
+ if (ret < 0) return total ? total : ret;
+ return total + ret;
+ }
+
+ int64_t seek(int64_t offset, int32_t native_whence) {
+ int whence;
+ switch (native_whence) {
+ case 0:
+ whence = SEEK_SET;
+ break;
+ case 1:
+ whence = SEEK_CUR;
+ break;
+ default:
+ assert(false);
+ return -1;
+ }
+ return smb2_lseek(context_.get(), fh_, offset, whence, nullptr);
+ }
+
+ private:
+ std::shared_ptr<smb2_context> context_;
+ smb2fh* const fh_;
+};
+
class Url {
public:
explicit Url(smb2_url* url) : url_(url) {
@@ -142,6 +212,23 @@ class Context {
}
}
+ [[nodiscard]] std::unique_ptr<File> OpenFile(const std::string& path, int32_t mode) {
+ int flags;
+ switch (mode) {
+ case 0:
+ flags = O_RDONLY;
+ break;
+ case 1:
+ flags = O_WRONLY | O_CREAT | O_TRUNC;
+ break;
+ default:
+ assert(false);
+ return nullptr;
+ }
+ auto* ptr = smb2_open(context_.get(), path.c_str(), flags);
+ return ptr ? std::make_unique<File>(context_, ptr) : nullptr;
+ }
+
private:
struct ContextDeleter {
void operator()(smb2_context* context) {
@@ -205,6 +292,10 @@ jstring nativeContextReadLink(JNIEnv* env, jclass clazz, jlong ptr, jstring path
return nullptr;
}
+jlong nativeContextOpenFile(JNIEnv* env, jclass clazz, jlong ptr, jstring path, jint mode) {
+ return reinterpret_cast<jlong>(reinterpret_cast<Context*>(ptr)->OpenFile(jni::StringToUTF8(env, jni::ParamRef<jstring>(env, path)), mode).release());
+}
+
void nativeUrlDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
delete reinterpret_cast<Url*>(ptr);
}
@@ -224,6 +315,50 @@ jobjectArray nativeDirList(JNIEnv* env, jclass clazz, jlong ptr) {
return reinterpret_cast<Dir*>(ptr)->List(env, g_DirEntryClass).release();
}
+void nativeFileDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+ delete reinterpret_cast<File*>(ptr);
+}
+
+jint nativeFileRead(JNIEnv* env, jclass clazz, jlong ptr, jbyteArray array, jint offset, jint length) {
+ jboolean is_copy = JNI_FALSE;
+ bool critical = true;
+ auto* data = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(array, &is_copy));
+ if (!data) {
+ critical = false;
+ data = env->GetByteArrayElements(array, &is_copy);
+ if (!data) return -1;
+ }
+ auto ret = reinterpret_cast<File *>(ptr)->read(reinterpret_cast<uint8_t *>(data + offset), length);
+ if (critical) {
+ env->ReleasePrimitiveArrayCritical(array, data, JNI_COMMIT);
+ } else {
+ env->ReleaseByteArrayElements(array, data, JNI_COMMIT);
+ }
+ return ret;
+}
+
+jint nativeFileWrite(JNIEnv* env, jclass clazz, jlong ptr, jbyteArray array, jint offset, jint length) {
+ jboolean is_copy = JNI_FALSE;
+ bool critical = true;
+ auto* data = reinterpret_cast<jbyte*>(env->GetPrimitiveArrayCritical(array, &is_copy));
+ if (!data) {
+ critical = false;
+ data = env->GetByteArrayElements(array, &is_copy);
+ if (!data) return -1;
+ }
+ auto ret = reinterpret_cast<File *>(ptr)->write(reinterpret_cast<uint8_t *>(data + offset), length);
+ if (critical) {
+ env->ReleasePrimitiveArrayCritical(array, data, JNI_ABORT);
+ } else {
+ env->ReleaseByteArrayElements(array, data, JNI_ABORT);
+ }
+ return ret;
+}
+
+jlong nativeFileSeek(JNIEnv* env, jclass clazz, jlong ptr, jlong offset, jint whence) {
+ return reinterpret_cast<File*>(ptr)->seek(offset, whence);
+}
+
jni::GlobalRef<jclass> g_NativeSambaClass(nullptr, nullptr);
jmethodID g_CreateDirEntry;
@@ -244,12 +379,18 @@ void RegisterSamba(JNIEnv* env) {
{ "nativeContextRemoveDir", "(JLjava/lang/String;)Z", reinterpret_cast<void*>(&nativeContextRemoveDir) },
{ "nativeContextUnlink", "(JLjava/lang/String;)Z", reinterpret_cast<void*>(&nativeContextUnlink) },
{ "nativeContextReadLink", "(JLjava/lang/String;)Ljava/lang/String;", reinterpret_cast<void*>(&nativeContextReadLink) },
+ { "nativeContextOpenFile", "(JLjava/lang/String;I)J", reinterpret_cast<void*>(&nativeContextOpenFile) },
{ "nativeUrlDestroy", "(J)V", reinterpret_cast<void*>(&nativeUrlDestroy) },
{ "nativeUrlPath", "(J)Ljava/lang/String;", reinterpret_cast<void*>(&nativeUrlPath) },
{ "nativeDirDestroy", "(J)V", reinterpret_cast<void*>(&nativeDirDestroy) },
{ "nativeDirList", "(J)[Lorg/the_jk/cleversync/io/samba/NativeSamba$DirEntry;", reinterpret_cast<void*>(&nativeDirList) },
+
+ { "nativeFileDestroy", "(J)V", reinterpret_cast<void*>(&nativeFileDestroy) },
+ { "nativeFileRead", "(J[BII)I", reinterpret_cast<void*>(&nativeFileRead) },
+ { "nativeFileSeek", "(JJI)J", reinterpret_cast<void*>(&nativeFileSeek) },
+ { "nativeFileWrite", "(J[BII)I", reinterpret_cast<void*>(&nativeFileWrite) },
};
auto ret = env->RegisterNatives(clazz.get(), methods, sizeof(methods) / sizeof(methods[0]));
ABORT_IF_NOT_OK(ret);