From 16d2b1750a78527a5524bfc3171a42f67c323508 Mon Sep 17 00:00:00 2001 From: Joel Klinghed Date: Fri, 23 Aug 2024 00:24:18 +0200 Subject: samba: Add support for read/write file --- libs/samba/src/main/cpp/samba.cpp | 141 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) (limited to 'libs/samba/src/main/cpp/samba.cpp') 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 #include +#include #include #include +#include #include #include #include @@ -46,6 +48,74 @@ class Dir { smb2dir* const dir_; }; +class File { + public: + File(std::shared_ptr 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::max()) { + int ret = smb2_read(context_.get(), fh_, data, + std::numeric_limits::max()); + if (ret < 0) return total ? total : ret; + if (ret != std::numeric_limits::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::max()) { + int ret = smb2_write(context_.get(), fh_, data, + std::numeric_limits::max()); + if (ret < 0) return total ? total : ret; + if (ret != std::numeric_limits::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 context_; + smb2fh* const fh_; +}; + class Url { public: explicit Url(smb2_url* url) : url_(url) { @@ -142,6 +212,23 @@ class Context { } } + [[nodiscard]] std::unique_ptr 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(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(reinterpret_cast(ptr)->OpenFile(jni::StringToUTF8(env, jni::ParamRef(env, path)), mode).release()); +} + void nativeUrlDestroy(JNIEnv* env, jclass clazz, jlong ptr) { delete reinterpret_cast(ptr); } @@ -224,6 +315,50 @@ jobjectArray nativeDirList(JNIEnv* env, jclass clazz, jlong ptr) { return reinterpret_cast(ptr)->List(env, g_DirEntryClass).release(); } +void nativeFileDestroy(JNIEnv* env, jclass clazz, jlong ptr) { + delete reinterpret_cast(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(env->GetPrimitiveArrayCritical(array, &is_copy)); + if (!data) { + critical = false; + data = env->GetByteArrayElements(array, &is_copy); + if (!data) return -1; + } + auto ret = reinterpret_cast(ptr)->read(reinterpret_cast(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(env->GetPrimitiveArrayCritical(array, &is_copy)); + if (!data) { + critical = false; + data = env->GetByteArrayElements(array, &is_copy); + if (!data) return -1; + } + auto ret = reinterpret_cast(ptr)->write(reinterpret_cast(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(ptr)->seek(offset, whence); +} + jni::GlobalRef g_NativeSambaClass(nullptr, nullptr); jmethodID g_CreateDirEntry; @@ -244,12 +379,18 @@ void RegisterSamba(JNIEnv* env) { { "nativeContextRemoveDir", "(JLjava/lang/String;)Z", reinterpret_cast(&nativeContextRemoveDir) }, { "nativeContextUnlink", "(JLjava/lang/String;)Z", reinterpret_cast(&nativeContextUnlink) }, { "nativeContextReadLink", "(JLjava/lang/String;)Ljava/lang/String;", reinterpret_cast(&nativeContextReadLink) }, + { "nativeContextOpenFile", "(JLjava/lang/String;I)J", reinterpret_cast(&nativeContextOpenFile) }, { "nativeUrlDestroy", "(J)V", reinterpret_cast(&nativeUrlDestroy) }, { "nativeUrlPath", "(J)Ljava/lang/String;", reinterpret_cast(&nativeUrlPath) }, { "nativeDirDestroy", "(J)V", reinterpret_cast(&nativeDirDestroy) }, { "nativeDirList", "(J)[Lorg/the_jk/cleversync/io/samba/NativeSamba$DirEntry;", reinterpret_cast(&nativeDirList) }, + + { "nativeFileDestroy", "(J)V", reinterpret_cast(&nativeFileDestroy) }, + { "nativeFileRead", "(J[BII)I", reinterpret_cast(&nativeFileRead) }, + { "nativeFileSeek", "(JJI)J", reinterpret_cast(&nativeFileSeek) }, + { "nativeFileWrite", "(J[BII)I", reinterpret_cast(&nativeFileWrite) }, }; auto ret = env->RegisterNatives(clazz.get(), methods, sizeof(methods) / sizeof(methods[0])); ABORT_IF_NOT_OK(ret); -- cgit v1.2.3-70-g09d2