A => .gitignore +84 -0
@@ 1,84 @@
+# Built application files
+*.apk
+*.ap_
+*.aab
+
+# Files for the ART/Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+out/
+release/
+
+# Gradle files
+.gradle/
+build/
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+# Android Studio Navigation editor temp files
+.navigation/
+
+# Android Studio captures folder
+captures/
+
+# IntelliJ
+*.iml
+.idea/workspace.xml
+.idea/tasks.xml
+.idea/gradle.xml
+.idea/assetWizardSettings.xml
+.idea/dictionaries
+.idea/libraries
+# Android Studio 3 in .gitignore file.
+.idea/caches
+.idea/modules.xml
+# Comment next line if keeping position of elements in Navigation Editor is relevant for you
+.idea/navEditor.xml
+
+# Keystore files
+# Uncomment the following lines if you do not want to check your keystore files in.
+#*.jks
+#*.keystore
+
+# External native build folder generated in Android Studio 2.2 and later
+.externalNativeBuild
+
+# Google Services (e.g. APIs or Firebase)
+# google-services.json
+
+# Freeline
+freeline.py
+freeline/
+freeline_project_description.json
+
+# fastlane
+fastlane/report.xml
+fastlane/Preview.html
+fastlane/screenshots
+fastlane/test_output
+fastlane/readme.md
+
+# Version control
+vcs.xml
+
+# lint
+lint/intermediates/
+lint/generated/
+lint/outputs/
+lint/tmp/
+# lint/reports/
+
+*.args
A => COMPILING-CEPH.md +15 -0
@@ 1,15 @@
+# Compile instruction for Ceph libraries used in this project
+
+Ceph libraries in this project is built by:
+
+Install android-ndk android-cmake android-aarch64-boost android-aarch64-openssl AUR packages on Archlinux.
+
+Under Ceph 15.2.5 source with ceph.patch applied:
+
+```sh
+mkdir build && cd build
+android-aarch64-cmake -DWITH_MANPAGE=OFF -DWITH_RDMA=OFF -DWITH_LEVELDB=OFF -DWITH_KVS=OFF -DWITH_FUSE=OFF -DWITH_BLUESTORE=OFF -DWITH_XFS=OFF -DWITH_RBD=OFF -DWITH_OPENLDAP=OFF -DWITH_RADOSGW=OFF -DWITH_LZ4=OFF -DWITH_KRBD=OFF -DWITH_LTTNG=OFF -DWITH_MGR=OFF -DWITH_BABELTRACE=OFF -DWITH_CEPHFS=OFF -DWITH_LIBRADOSSTRIPER=OFF -DWITH_TESTS=OFF -DWITH_REENTRANT_STRSIGNAL=ON -DWITH_SYSTEMD=OFF -DWITH_MGR_DASHBOARD_FRONTEND=OFF -DWITH_RADOSGW_KAFKA_ENDPOINT=OFF -D WITH_RADOSGW_AMQP_ENDPOINT=OFF -DWITH_RADOSGW_BEAST_OPENSSL=OFF -DWITH_RADOSGW_BEAST_FRONTEND=OFF -DDEBUG_GATHER=OFF -DWITH_CEPHFS_JAVA=ON -DOPENSSL_INCLUDE_DIR:FILEPATH=/opt/android-libs/aarch64/include/ -DOPENSSL_CRYPTO_LIBRARY=/opt/android-libs/aarch64/lib/libcrypto.so -DWITH_SYSTEM_BOOST=ON -DBoost_INCLUDE_DIR=/opt/android-libs/aarch64/include/ -DBoost_LIBRARY_DIR=/opt/android-libs/aarch64/lib/ -DWITH_BOOST_CONTEXT=OFF ..
+make java
+```
+
+ceph.patch contains some hacks to avoid dependency of unused targets, to use boost::filesystem instead of std::filesystem as needed library is not in NDK yet, and to fix build with Android bionic libc.
A => LICENSE +21 -0
@@ 1,21 @@
+MIT License
+
+Copyright (c) 2020 xdavidwu
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
A => README.md +29 -0
@@ 1,29 @@
+# saf-cephfs
+
+[WIP] Access CephFS from Android Storage Access Framework (SAF), with libcephfs-jni
+
+Currently only for arm64-v8a
+
+## Libraries sources
+
+Native libraries bundled are built from:
+
+* libboost_\*.so: Archlinx User Repository (AUR) package `android-aarch64-boost` (1.71.0-1)
+* libcrypto\_1\_1.so: AUR package `android-aarch64-openssl` (1.1.1.g-1)
+* libc++\_shared.so: copied from NDK r21.d
+* libcrc32.so, libcephfs.so, libceph-common.so, libcephfs\_jni.so, libfmt.so: built from Ceph 15.2.5, see [COMPILING-CEPH.md](COMPILING-CEPH.md) for how I built it
+
+Java libraries com.ceph.\* is copied from Ceph 15.2.5 source code.
+
+## Current features
+
+* Traverse the tree under specified path
+
+## Notes
+
+This is a WIP, and the code is dirty and full of debugging lines.
+Many things still don't work.
+
+### What's tested and worked so far
+
+* Listing files, changing directories
A => build.gradle +37 -0
@@ 1,37 @@
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ maven {
+ url 'https://oss.jfrog.org/artifactory/oss-snapshot-local/'
+ }
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.1'
+ }
+}
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 'android-30'
+ buildToolsVersion '30.0.2'
+
+ defaultConfig {
+ minSdkVersion 19
+ targetSdkVersion 30
+ }
+
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFile getDefaultProguardFile('proguard-android.txt')
+ }
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ }
+}
A => ceph.patch +242 -0
@@ 1,242 @@
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/cmake/modules/CephChecks.cmake ceph-15.2.5-android/cmake/modules/CephChecks.cmake
+--- ceph-15.2.5/cmake/modules/CephChecks.cmake 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/cmake/modules/CephChecks.cmake 2020-10-09 15:54:41.488684672 +0800
+@@ -74,7 +74,7 @@
+ if(HAVE_POSIX_TIMERS)
+ find_library(RT_LIBRARY NAMES rt)
+ endif()
+-check_symbol_exists(res_nquery "resolv.h" HAVE_RES_NQUERY)
++#check_symbol_exists(res_nquery "resolv.h" HAVE_RES_NQUERY)
+ check_symbol_exists(F_SETPIPE_SZ "linux/fcntl.h" CEPH_HAVE_SETPIPE_SZ)
+ check_symbol_exists(__func__ "" HAVE_FUNC)
+ check_symbol_exists(__PRETTY_FUNCTION__ "" HAVE_PRETTY_FUNC)
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/CMakeLists.txt ceph-15.2.5-android/CMakeLists.txt
+--- ceph-15.2.5/CMakeLists.txt 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/CMakeLists.txt 2020-10-09 17:40:39.627422756 +0800
+@@ -260,7 +260,7 @@
+ find_file(HAVE_LEVELDB_FILTER_POLICY leveldb/filter_policy.h PATHS ${LEVELDB_INCLUDE_DIR})
+ endif(WITH_LEVELDB)
+
+-find_package(snappy REQUIRED)
++#find_package(snappy REQUIRED)
+
+ option(WITH_BROTLI "Brotli compression support" OFF)
+ if(WITH_BROTLI)
+@@ -319,10 +319,10 @@
+ set(LIBTCMALLOC_MISSING_ALIGNED_ALLOC ON)
+ endif()
+
+-find_package(CURL REQUIRED)
+-set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
+-set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARIES})
+-CHECK_SYMBOL_EXISTS(curl_multi_wait curl/curl.h HAVE_CURL_MULTI_WAIT)
++#find_package(CURL REQUIRED)
++#set(CMAKE_REQUIRED_INCLUDES ${CURL_INCLUDE_DIRS})
++#set(CMAKE_REQUIRED_LIBRARIES ${CURL_LIBRARIES})
++#CHECK_SYMBOL_EXISTS(curl_multi_wait curl/curl.h HAVE_CURL_MULTI_WAIT)
+
+ find_package(OpenSSL REQUIRED)
+ set(CRYPTO_LIBS OpenSSL::Crypto)
+@@ -429,8 +429,8 @@
+ elseif(NOT WITH_PYTHON3 STREQUAL "3")
+ set(find_python3_exact "EXACT")
+ endif()
+-find_package(Python3 ${WITH_PYTHON3} ${find_python3_exact} REQUIRED
+- COMPONENTS Interpreter Development)
++#find_package(Python3 ${WITH_PYTHON3} ${find_python3_exact} REQUIRED
++# COMPONENTS Interpreter Development)
+ unset(find_python3_exact)
+
+ option(WITH_MGR "ceph-mgr is enabled" ON)
+@@ -556,7 +556,7 @@
+ # Boost::thread depends on Boost::atomic, so list it explicitly.
+ set(BOOST_COMPONENTS
+ atomic chrono thread system regex random program_options date_time
+- iostreams)
++ iostreams filesystem)
+ set(BOOST_HEADER_COMPONENTS container)
+
+ if(WITH_MGR)
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/client/Client.cc ceph-15.2.5-android/src/client/Client.cc
+--- ceph-15.2.5/src/client/Client.cc 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/client/Client.cc 2020-10-09 15:42:09.299181519 +0800
+@@ -1,3 +1,4 @@
++#define IFTODT(x) ((x) >> 12 & 017)
+ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+ // vim: ts=8 sw=2 smarttab
+ /*
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/CMakeLists.txt ceph-15.2.5-android/src/CMakeLists.txt
+--- ceph-15.2.5/src/CMakeLists.txt 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/CMakeLists.txt 2020-10-09 17:39:35.463005918 +0800
+@@ -374,7 +374,7 @@
+ Boost::program_options
+ Boost::date_time
+ Boost::iostreams
+- StdFilesystem::filesystem
++ Boost::filesystem
+ fmt::fmt
+ ${BLKID_LIBRARIES}
+ ${Backtrace_LIBRARIES}
+@@ -505,7 +505,7 @@
+ set(CEPH_BUILD_VIRTUALENV ${CMAKE_BINARY_DIR})
+ endif()
+
+-add_subdirectory(pybind)
++#add_subdirectory(pybind)
+ add_subdirectory(ceph-volume)
+ add_subdirectory(python-common)
+ add_subdirectory(cephadm)
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/common/addr_parsing.c ceph-15.2.5-android/src/common/addr_parsing.c
+--- ceph-15.2.5/src/common/addr_parsing.c 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/common/addr_parsing.c 2020-10-09 15:45:32.350180015 +0800
+@@ -1,3 +1,4 @@
++#include <linux/in.h>
+ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+ // vim: ts=8 sw=2 smarttab
+ /*
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/common/blkdev.cc ceph-15.2.5-android/src/common/blkdev.cc
+--- ceph-15.2.5/src/common/blkdev.cc 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/common/blkdev.cc 2020-10-09 16:31:04.381488339 +0800
+@@ -61,7 +61,7 @@
+
+ #include "common/blkdev.h"
+
+-#ifdef __linux__
++#if defined(__linux__) && !defined(__ANDROID__)
+ #include <libudev.h>
+ #include <linux/fs.h>
+ #include <linux/kdev_t.h>
+@@ -104,7 +104,7 @@
+ return 0;
+ }
+
+-#ifdef __linux__
++#if defined(__linux__) && !defined(__ANDROID__)
+
+ const char *BlkDev::sysfsdir() const {
+ return "/sys";
+@@ -1168,12 +1168,12 @@
+ return false;
+ }
+
+-int BlkDev::discard(int fd, int64_t offset, int64_t len) const
++int BlkDev::discard(int64_t offset, int64_t len) const
+ {
+ return -EOPNOTSUPP;
+ }
+
+-bool BlkDev::is_rotational(const char *devname) const
++bool BlkDev::is_rotational() const
+ {
+ return false;
+ }
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/common/ConfUtils.cc ceph-15.2.5-android/src/common/ConfUtils.cc
+--- ceph-15.2.5/src/common/ConfUtils.cc 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/common/ConfUtils.cc 2020-10-09 17:38:43.806680865 +0800
+@@ -21,7 +21,7 @@
+ #include <map>
+ #include <sstream>
+
+-#if __has_include(<filesystem>)
++/*#if __has_include(<filesystem>)
+ #include <filesystem>
+ namespace fs = std::filesystem;
+ #elif __has_include(<experimental/filesystem>)
+@@ -29,7 +29,10 @@
+ namespace fs = std::experimental::filesystem;
+ #else
+ #error std::filesystem not available!
+-#endif
++#endif*/
++
++#include <boost/filesystem.hpp>
++namespace fs = boost::filesystem;
+
+ #include <boost/algorithm/string.hpp>
+ #include <boost/algorithm/string/trim_all.hpp>
+@@ -122,7 +125,7 @@
+ return -EINVAL;
+ }
+ } catch (const fs::filesystem_error& e) {
+- std::error_code ec;
++ boost::system::error_code ec;
+ auto is_other = fs::is_other(fname, ec);
+ if (!ec && is_other) {
+ // /dev/null?
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/common/dns_resolve.cc ceph-15.2.5-android/src/common/dns_resolve.cc
+--- ceph-15.2.5/src/common/dns_resolve.cc 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/common/dns_resolve.cc 2020-10-09 16:20:06.701513735 +0800
+@@ -206,8 +206,13 @@
+
+ }
+
++#ifdef HAVE_RES_NQUERY
+ int DNSResolver::resolve_ip_addr(CephContext *cct, res_state *res, const string& hostname,
+ entity_addr_t *addr) {
++#else
++int DNSResolver::resolve_ip_addr(CephContext *cct, void *res, const string& hostname,
++ entity_addr_t *addr) {
++#endif
+
+ u_char nsbuf[NS_PACKETSZ];
+ int len;
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/common/dns_resolve.h ceph-15.2.5-android/src/common/dns_resolve.h
+--- ceph-15.2.5/src/common/dns_resolve.h 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/common/dns_resolve.h 2020-10-09 16:19:12.409285141 +0800
+@@ -142,8 +142,13 @@
+ /* this private function allows to reuse the res_state structure used
+ * by other function of this class
+ */
++#ifdef HAVE_RES_NQUERY
+ int resolve_ip_addr(CephContext *cct, res_state *res,
+ const std::string& hostname, entity_addr_t *addr);
++#else
++ int resolve_ip_addr(CephContext *cct, void *res,
++ const std::string& hostname, entity_addr_t *addr);
++#endif
+
+ std::string srv_protocol_to_str(SRV_Protocol proto) {
+ switch (proto) {
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/java/CMakeLists.txt ceph-15.2.5-android/src/java/CMakeLists.txt
+--- ceph-15.2.5/src/java/CMakeLists.txt 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/java/CMakeLists.txt 2020-10-09 15:15:57.392846740 +0800
+@@ -1,5 +1,5 @@
+ find_package(Java COMPONENTS Development REQUIRED)
+-find_package(JNI REQUIRED)
++#find_package(JNI REQUIRED)
+ include(UseJava)
+
+ set(java_srcs
+@@ -58,4 +58,4 @@
+
+ add_custom_target(java DEPENDS
+ libcephfs.jar
+- libcephfs_jni)
++ cephfs_jni)
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/mds/CInode.h ceph-15.2.5-android/src/mds/CInode.h
+--- ceph-15.2.5/src/mds/CInode.h 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/mds/CInode.h 2020-10-09 15:47:19.231593102 +0800
+@@ -1,3 +1,4 @@
++#define IFTODT(x) ((x) >> 12 & 017)
+ // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*-
+ // vim: ts=8 sw=2 smarttab
+ /*
+diff '--color=auto' -Naur '--exclude=build' '--exclude=build-android-aarch64' '--exclude=boost' '--exclude=qa' '--exclude=90-ceph-osd.conf' ceph-15.2.5/src/msg/CMakeLists.txt ceph-15.2.5-android/src/msg/CMakeLists.txt
+--- ceph-15.2.5/src/msg/CMakeLists.txt 2020-09-16 02:57:02.000000000 +0800
++++ ceph-15.2.5-android/src/msg/CMakeLists.txt 2020-10-09 18:04:20.807630744 +0800
+@@ -20,13 +20,13 @@
+ async/frames_v2.cc
+ async/net_handler.cc)
+
+-if(LINUX)
++if(LINUX OR ANDROID)
+ list(APPEND msg_srcs
+ async/EventEpoll.cc)
+ elseif(FREEBSD OR APPLE)
+ list(APPEND msg_srcs
+ async/EventKqueue.cc)
+-endif(LINUX)
++endif(LINUX OR ANDROID)
+
+ if(HAVE_RDMA)
+ list(APPEND msg_srcs
A => gradle/wrapper/gradle-wrapper.jar +0 -0
A => gradle/wrapper/gradle-wrapper.properties +6 -0
@@ 1,6 @@
+#Wed Apr 10 15:27:10 PDT 2013
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.4.1-all.zip
A => gradlew +164 -0
@@ 1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+ echo "$*"
+}
+
+die ( ) {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+ [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+ JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
A => gradlew.bat +90 -0
@@ 1,90 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windowz variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+if "%@eval[2+2]" == "4" goto 4NT_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+goto execute
+
+:4NT_args
+@rem Get arguments from the 4NT Shell from JP Software
+set CMD_LINE_ARGS=%$
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
A => src/main/AndroidManifest.xml +30 -0
@@ 1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="org.safcephfs"
+ android:versionCode="1"
+ android:versionName="1.0">
+
+ <uses-permission android:name="android.permission.INTERNET" />
+
+ <application android:label="@string/app_name"
+ android:icon="@mipmap/sym_def_app_icon"
+ android:allowBackup="false">
+ <activity android:name="MainActivity"
+ android:label="@string/app_name"
+ android:theme="@android:style/Theme.DeviceDefault">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ <provider android:name=".CephFSDocumentsProvider"
+ android:authorities="org.safcephfs"
+ android:permission="android.permission.MANAGE_DOCUMENTS"
+ android:grantUriPermissions="true"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+ </intent-filter>
+ </provider>
+ </application>
+</manifest>
A => src/main/java/com/ceph/crush/Bucket.java +42 -0
@@ 1,42 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.crush;
+
+public class Bucket {
+ private String type;
+ private String name;
+
+ public Bucket(String type, String name) {
+ this.type = type;
+ this.name = name;
+ }
+
+ public String getType() {
+ return type;
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String toString() {
+ return "bucket[" + type + "," + name + "]";
+ }
+}
A => src/main/java/com/ceph/fs/CephAlreadyMountedException.java +44 -0
@@ 1,44 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+
+/**
+ * Ceph is already mounted.
+ */
+public class CephAlreadyMountedException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct CephAlreadyMountedException.
+ */
+ public CephAlreadyMountedException() {
+ super();
+ }
+
+ /**
+ * Construct CephAlreadyMountedException with message.
+ */
+ public CephAlreadyMountedException(String s) {
+ super(s);
+ }
+}
A => src/main/java/com/ceph/fs/CephFileAlreadyExistsException.java +44 -0
@@ 1,44 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+
+/**
+ * Ceph file/directory already exists.
+ */
+public class CephFileAlreadyExistsException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct CephFileAlreadyExistsException.
+ */
+ public CephFileAlreadyExistsException() {
+ super();
+ }
+
+ /**
+ * Construct CephFileAlreadyExistsException with message.
+ */
+ public CephFileAlreadyExistsException(String s) {
+ super(s);
+ }
+}
A => src/main/java/com/ceph/fs/CephFileExtent.java +66 -0
@@ 1,66 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.util.Arrays;
+
+/**
+ * Holds information about a file extent in CephFS.
+ */
+public class CephFileExtent {
+ private long offset;
+ private long length;
+ private int[] osds;
+
+ CephFileExtent(long offset, long length, int[] osds) {
+ this.offset = offset;
+ this.length = length;
+ this.osds = osds;
+ }
+
+ /**
+ * Get starting offset of extent.
+ */
+ public long getOffset() {
+ return offset;
+ }
+
+ /**
+ * Get length of extent.
+ */
+ public long getLength() {
+ return length;
+ }
+
+ /**
+ * Get list of OSDs with this extent.
+ */
+ public int[] getOSDs() {
+ return osds;
+ }
+
+ /**
+ * Pretty print.
+ */
+ public String toString() {
+ return "extent[" + offset + "," + length + ","
+ + Arrays.toString(osds) + "]";
+ }
+}
A => src/main/java/com/ceph/fs/CephMount.java +1103 -0
@@ 1,1103 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+import java.io.FileNotFoundException;
+import java.net.InetAddress;
+import java.util.concurrent.locks.Lock;
+import java.util.concurrent.locks.ReentrantReadWriteLock;
+import java.lang.String;
+
+import com.ceph.crush.Bucket;
+
+public class CephMount {
+
+ /*
+ * Set via JNI callback in native_ceph_create
+ *
+ * Do not touch!
+ */
+ private long instance_ptr;
+
+ /*
+ * Flags for open().
+ *
+ * Must be synchronized with JNI if changed.
+ */
+ public static final int O_RDONLY = 1;
+ public static final int O_RDWR = 2;
+ public static final int O_APPEND = 4;
+ public static final int O_CREAT = 8;
+ public static final int O_TRUNC = 16;
+ public static final int O_EXCL = 32;
+ public static final int O_WRONLY = 64;
+ public static final int O_DIRECTORY = 128;
+
+ /*
+ * Whence flags for seek().
+ *
+ * Must be synchronized with JNI if changed.
+ */
+ public static final int SEEK_SET = 1;
+ public static final int SEEK_CUR = 2;
+ public static final int SEEK_END = 3;
+
+ /*
+ * Attribute flags for setattr().
+ *
+ * Must be synchronized with JNI if changed.
+ */
+ public static final int SETATTR_MODE = 1;
+ public static final int SETATTR_UID = 2;
+ public static final int SETATTR_GID = 4;
+ public static final int SETATTR_MTIME = 8;
+ public static final int SETATTR_ATIME = 16;
+
+ /*
+ * Flags for setxattr();
+ *
+ * Must be synchronized with JNI if changed.
+ */
+ public static final int XATTR_CREATE = 1;
+ public static final int XATTR_REPLACE = 2;
+ public static final int XATTR_NONE = 3;
+
+ /*
+ * Flags for flock();
+ *
+ * Must be synchronized with JNI if changed.
+ */
+ public static final int LOCK_SH = 1;
+ public static final int LOCK_EX = 2;
+ public static final int LOCK_NB = 4;
+ public static final int LOCK_UN = 8;
+
+ /*
+ * This is run by the class loader and will report early any problems
+ * finding or linking in the shared JNI library.
+ */
+ static {
+ loadLibrary();
+ }
+
+ static synchronized void loadLibrary() {
+ CephNativeLoader.getInstance().loadLibrary();
+ }
+
+ /*
+ * Package-private: called from CephNativeLoader
+ */
+ static native void native_initialize();
+
+ /*
+ * RW lock used for fine grained synchronization to native
+ */
+ private final ReentrantReadWriteLock rwlock = new ReentrantReadWriteLock();
+ private final Lock rlock = rwlock.readLock();
+ private final Lock wlock = rwlock.writeLock();
+
+ /*
+ * Controls clean-up synchronization between the constructor and finalize().
+ * If native_ceph_create fails, then we want a call to finalize() to not
+ * attempt to clean-up native context, because there is none.
+ */
+ private boolean initialized = false;
+
+ /*
+ * Try to clean-up. First, unmount() will catch users who forget to do the
+ * unmount manually. Second, release() will destroy the entire context. It
+ * is safe to call release after a failure in unmount.
+ */
+ protected void finalize() throws Throwable {
+ if (initialized) {
+ try {
+ unmount();
+ } catch (Exception e) {}
+ try {
+ native_ceph_release(instance_ptr);
+ } catch (Exception e) {}
+ }
+ super.finalize();
+ }
+
+ /**
+ * Create a new CephMount with specific client id.
+ *
+ * @param id client id.
+ */
+ public CephMount(String id) {
+ native_ceph_create(this, id);
+ initialized = true;
+ }
+
+ private static native int native_ceph_create(CephMount mount, String id);
+
+ /**
+ * Create a new CephMount with default client id.
+ */
+ public CephMount() {
+ this(null);
+ }
+
+ /**
+ * Activate the mount with a given root path.
+ *
+ * @param root The path to use as the root (pass null for "/").
+ */
+ public void mount(String root) {
+ wlock.lock();
+ try {
+ native_ceph_mount(instance_ptr, root);
+ } finally {
+ wlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_mount(long mountp, String root);
+
+ /**
+ * Deactivate the mount.
+ *
+ * The mount can be reactivated using mount(). Configuration parameters
+ * previously set are not reset.
+ */
+ public void unmount() {
+ wlock.lock();
+ try {
+ native_ceph_unmount(instance_ptr);
+ } finally {
+ wlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_unmount(long mountp);
+
+ /*
+ * Private access to low-level ceph_release.
+ */
+ private static native int native_ceph_release(long mountp);
+
+ /**
+ * Load configuration from a file.
+ *
+ * @param path The path to the configuration file.
+ */
+ public void conf_read_file(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_conf_read_file(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_conf_read_file(long mountp, String path);
+
+ /**
+ * Set the value of a configuration option.
+ *
+ * @param option The configuration option to modify.
+ * @param value The new value of the option.
+ */
+ public void conf_set(String option, String value) {
+ rlock.lock();
+ try {
+ native_ceph_conf_set(instance_ptr, option, value);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_conf_set(long mountp, String option, String value);
+
+ /**
+ * Get the value of a configuration option.
+ *
+ * @param option The name of the configuration option.
+ * @return The value of the option or null if option not found
+ */
+ public String conf_get(String option) {
+ rlock.lock();
+ try {
+ return native_ceph_conf_get(instance_ptr, option);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String native_ceph_conf_get(long mountp, String option);
+
+ /**
+ * Get file system status.
+ *
+ * @param path Path to file in file system.
+ * @param statvfs CephStatVFS structure to hold status.
+ */
+ public void statfs(String path, CephStatVFS statvfs) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_statfs(instance_ptr, path, statvfs);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_statfs(long mountp, String path, CephStatVFS statvfs);
+
+ /**
+ * Get the current working directory.
+ *
+ * @return The current working directory in Ceph.
+ */
+ public String getcwd() {
+ rlock.lock();
+ try {
+ return native_ceph_getcwd(instance_ptr);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String native_ceph_getcwd(long mountp);
+
+ /**
+ * Set the current working directory.
+ *
+ * @param path The directory set as the cwd.
+ */
+ public void chdir(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_chdir(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_chdir(long mountp, String cwd);
+
+ /**
+ * List the contents of a directory.
+ *
+ * @param dir The directory.
+ * @return List of files and directories excluding "." and "..".
+ */
+ public String[] listdir(String dir) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_listdir(instance_ptr, dir);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String[] native_ceph_listdir(long mountp, String path);
+
+ /**
+ * Create a hard link to an existing file.
+ *
+ * @param oldpath The target path of the link.
+ * @param newpath The name of the link.
+ */
+ public void link(String oldpath, String newpath) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_link(instance_ptr, oldpath, newpath);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_link(long mountp, String existing, String newname);
+
+ /**
+ * Unlink/delete a name from the file system.
+ *
+ * @param path The name to unlink/delete.
+ */
+ public void unlink(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_unlink(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_unlink(long mountp, String path);
+
+ /**
+ * Rename a file or directory.
+ *
+ * @param from The current path.
+ * @param to The new path.
+ */
+ public void rename(String from, String to) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_rename(instance_ptr, from, to);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_rename(long mountp, String from, String to);
+
+ /**
+ * Create a directory.
+ *
+ * @param path The directory to create.
+ * @param mode The mode of the new directory.
+ */
+ public void mkdir(String path, int mode) {
+ rlock.lock();
+ try {
+ native_ceph_mkdir(instance_ptr, path, mode);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_mkdir(long mountp, String path, int mode);
+
+ /**
+ * Create a directory and all parents.
+ *
+ * @param path The directory to create.
+ * @param mode The mode of the new directory.
+ */
+ public void mkdirs(String path, int mode) throws IOException {
+ rlock.lock();
+ try {
+ native_ceph_mkdirs(instance_ptr, path, mode);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_mkdirs(long mountp, String path, int mode);
+
+ /**
+ * Delete a directory.
+ *
+ * @param path The directory to delete.
+ */
+ public void rmdir(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_rmdir(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_rmdir(long mountp, String path);
+
+ /**
+ * Read the value of a symbolic link.
+ */
+ public String readlink(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_readlink(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String native_ceph_readlink(long mountp, String path);
+
+ /**
+ * Create a symbolic link.
+ *
+ * @param oldpath Target of the symbolic link.
+ * @param newpath Name of the link.
+ */
+ public void symlink(String oldpath, String newpath) {
+ rlock.lock();
+ try {
+ native_ceph_symlink(instance_ptr, oldpath, newpath);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_symlink(long mountp, String existing, String newname);
+
+ /**
+ * Get file status.
+ *
+ * @param path Path of file to stat.
+ * @param stat CephStat structure to hold file status.
+ */
+ public void stat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException {
+ rlock.lock();
+ try {
+ native_ceph_stat(instance_ptr, path, stat);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_stat(long mountp, String path, CephStat stat);
+
+ /**
+ * Get file status, without following symlinks.
+ *
+ * @param path Path of file to stat.
+ * @param stat CephStat structure to hold file status.
+ */
+ public void lstat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException {
+ rlock.lock();
+ try {
+ native_ceph_lstat(instance_ptr, path, stat);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_lstat(long mountp, String path, CephStat stat);
+
+ /**
+ * Set file attributes.
+ *
+ * @param path Path to file.
+ * @param stat CephStat structure holding attributes.
+ * @param mask Mask specifying which attributes to set.
+ */
+ public void setattr(String path, CephStat stat, int mask) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_setattr(instance_ptr, path, stat, mask);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_setattr(long mountp, String relpath, CephStat stat, int mask);
+
+ /**
+ * Change file mode.
+ *
+ * @param path Path to file.
+ * @param mode New mode bits.
+ */
+ public void chmod(String path, int mode) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_chmod(instance_ptr, path, mode);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_chmod(long mountp, String path, int mode);
+
+ /**
+ * Change file mode of an open file.
+ *
+ * @param fd The open file descriptor to change the mode bits on.
+ * @param mode New mode bits.
+ */
+ public void fchmod(int fd, int mode) {
+ rlock.lock();
+ try {
+ native_ceph_fchmod(instance_ptr, fd, mode);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_fchmod(long mountp, int fd, int mode);
+
+ /**
+ * Truncate a file to a specified length.
+ *
+ * @param path Path of the file.
+ * @param size New file length.
+ */
+ public void truncate(String path, long size) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_truncate(instance_ptr, path, size);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_truncate(long mountp, String path, long size);
+
+ /**
+ * Open a file.
+ *
+ * @param path Path of file to open or create.
+ * @param flags Open flags.
+ * @param mode Permission mode.
+ * @return File descriptor.
+ */
+ public int open(String path, int flags, int mode) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_open(instance_ptr, path, flags, mode);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_open(long mountp, String path, int flags, int mode);
+
+ /**
+ * Open a file with a specific file layout.
+ *
+ * @param path Path of file to open or create.
+ * @param flags Open flags.
+ * @param mode Permission mode.
+ * @param stripe_unit File layout stripe unit size.
+ * @param stripe_count File layout stripe count.
+ * @param object_size Size of each object.
+ * @param data_pool The target data pool.
+ * @return File descriptor.
+ */
+ public int open(String path, int flags, int mode, int stripe_unit, int stripe_count,
+ int object_size, String data_pool) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_open_layout(instance_ptr, path, flags, mode, stripe_unit,
+ stripe_count, object_size, data_pool);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_open_layout(long mountp, String path,
+ int flags, int mode, int stripe_unit, int stripe_count, int object_size, String data_pool);
+
+ /**
+ * Close an open file.
+ *
+ * @param fd The file descriptor.
+ */
+ public void close(int fd) {
+ rlock.lock();
+ try {
+ native_ceph_close(instance_ptr, fd);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_close(long mountp, int fd);
+
+ /**
+ * Seek to a position in a file.
+ *
+ * @param fd File descriptor.
+ * @param offset New offset.
+ * @param whence Whence value.
+ * @return The new offset.
+ */
+ public long lseek(int fd, long offset, int whence) {
+ rlock.lock();
+ try {
+ return native_ceph_lseek(instance_ptr, fd, offset, whence);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native long native_ceph_lseek(long mountp, int fd, long offset, int whence);
+
+ /**
+ * Read from a file.
+ *
+ * @param fd The file descriptor.
+ * @param buf Buffer to for data read.
+ * @param size Amount of data to read into the buffer.
+ * @param offset Offset to read from (-1 for current position).
+ * @return The number of bytes read.
+ */
+ public long read(int fd, byte[] buf, long size, long offset) {
+ rlock.lock();
+ try {
+ return native_ceph_read(instance_ptr, fd, buf, size, offset);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native long native_ceph_read(long mountp, int fd, byte[] buf, long size, long offset);
+
+ /**
+ * Write to a file at a specific offset.
+ *
+ * @param fd The file descriptor.
+ * @param buf Buffer to write.
+ * @param size Amount of data to write.
+ * @param offset Offset to write from (-1 for current position).
+ * @return The number of bytes written.
+ */
+ public long write(int fd, byte[] buf, long size, long offset) {
+ rlock.lock();
+ try {
+ return native_ceph_write(instance_ptr, fd, buf, size, offset);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native long native_ceph_write(long mountp, int fd, byte[] buf, long size, long offset);
+
+ /**
+ * Truncate a file.
+ *
+ * @param fd File descriptor of the file to truncate.
+ * @param size New file size.
+ */
+ public void ftruncate(int fd, long size) {
+ rlock.lock();
+ try {
+ native_ceph_ftruncate(instance_ptr, fd, size);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_ftruncate(long mountp, int fd, long size);
+
+ /**
+ * Synchronize a file with the file system.
+ *
+ * @param fd File descriptor to synchronize.
+ * @param dataonly Synchronize only data.
+ */
+ public void fsync(int fd, boolean dataonly) {
+ rlock.lock();
+ try {
+ native_ceph_fsync(instance_ptr, fd, dataonly);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_fsync(long mountp, int fd, boolean dataonly);
+
+ /**
+ * Apply or remove an advisory lock.
+ *
+ * @param fd File descriptor to lock or unlock.
+ * @param operation the advisory lock operation to be performed on the file
+ * descriptor among LOCK_SH (shared lock), LOCK_EX (exclusive lock),
+ * or LOCK_UN (remove lock). The LOCK_NB value can be ORed to perform a
+ * non-blocking operation.
+ * @param owner the user-supplied owner identifier (an arbitrary integer)
+ */
+ public void flock(int fd, int operation, long owner) throws IOException {
+ rlock.lock();
+ try {
+ native_ceph_flock(instance_ptr, fd, operation, owner);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_flock(long mountp, int fd, int operation, long owner);
+
+ /**
+ * Get file status.
+ *
+ * @param fd The file descriptor.
+ * @param stat The object in which to store the status.
+ */
+ public void fstat(int fd, CephStat stat) {
+ rlock.lock();
+ try {
+ native_ceph_fstat(instance_ptr, fd, stat);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_fstat(long mountp, int fd, CephStat stat);
+
+ /**
+ * Synchronize the client with the file system.
+ */
+ public void sync_fs() {
+ rlock.lock();
+ try {
+ native_ceph_sync_fs(instance_ptr);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_sync_fs(long mountp);
+
+ /**
+ * Get an extended attribute value.
+ *
+ * If the buffer is large enough to hold the entire attribute value, or
+ * buf is null, the size of the value is returned.
+ *
+ * @param path File path.
+ * @param name Name of the attribute.
+ * @param buf Buffer to store attribute value.
+ * @return The length of the attribute value. See description for more
+ * details.
+ */
+ public long getxattr(String path, String name, byte[] buf) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_getxattr(instance_ptr, path, name, buf);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native long native_ceph_getxattr(long mountp, String path, String name, byte[] buf);
+
+ /**
+ * Get an extended attribute value of a symbolic link.
+ *
+ * If the buffer is large enough to hold the entire attribute value, or
+ * buf is null, the size of the value is returned.
+ *
+ * @param path File path.
+ * @param name Name of attribute.
+ * @param buf Buffer to store attribute value.
+ * @return The length of the attribute value. See description for more
+ * details.
+ */
+ public long lgetxattr(String path, String name, byte[] buf) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_lgetxattr(instance_ptr, path, name, buf);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native long native_ceph_lgetxattr(long mountp, String path, String name, byte[] buf);
+
+ /**
+ * List extended attributes.
+ *
+ * @param path File path.
+ * @return List of attribute names.
+ */
+ public String[] listxattr(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_listxattr(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String[] native_ceph_listxattr(long mountp, String path);
+
+ /**
+ * List extended attributes of a symbolic link.
+ *
+ * @param path File path.
+ * @return List of attribute names.
+ */
+ public String[] llistxattr(String path) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ return native_ceph_llistxattr(instance_ptr, path);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String[] native_ceph_llistxattr(long mountp, String path);
+
+ /**
+ * Remove an extended attribute.
+ *
+ * @param path File path.
+ * @param name Name of attribute.
+ */
+ public void removexattr(String path, String name) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_removexattr(instance_ptr, path, name);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_removexattr(long mountp, String path, String name);
+
+ /**
+ * Remove an extended attribute from a symbolic link.
+ *
+ * @param path File path.
+ * @param name Name of attribute.
+ */
+ public void lremovexattr(String path, String name) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_lremovexattr(instance_ptr, path, name);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_lremovexattr(long mountp, String path, String name);
+
+ /**
+ * Set the value of an extended attribute.
+ *
+ * @param path The file path.
+ * @param name The attribute name.
+ * @param buf The attribute value.
+ * @param size The size of the attribute value.
+ * @param flags Flag controlling behavior (XATTR_CREATE/REPLACE/NONE).
+ */
+ public void setxattr(String path, String name, byte[] buf, long size, int flags) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_setxattr(instance_ptr, path, name, buf, size, flags);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_setxattr(long mountp, String path, String name, byte[] buf, long size, int flags);
+
+ /**
+ * Set the value of an extended attribute on a symbolic link.
+ *
+ * @param path The file path.
+ * @param name The attribute name.
+ * @param buf The attribute value.
+ * @param size The size of the attribute value.
+ * @param flags Flag controlling behavior (XATTR_CREATE/REPLACE/NONE).
+ */
+ public void lsetxattr(String path, String name, byte[] buf, long size, int flags) throws FileNotFoundException {
+ rlock.lock();
+ try {
+ native_ceph_lsetxattr(instance_ptr, path, name, buf, size, flags);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_lsetxattr(long mountp, String path, String name, byte[] buf, long size, int flags);
+
+ /**
+ * Get the stripe unit of a file.
+ *
+ * @param fd The file descriptor.
+ * @return The stripe unit.
+ */
+ public int get_file_stripe_unit(int fd) {
+ rlock.lock();
+ try {
+ return native_ceph_get_file_stripe_unit(instance_ptr, fd);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_get_file_stripe_unit(long mountp, int fd);
+
+ /**
+ * Get the name of the pool a file is stored in.
+ *
+ * @param fd An open file descriptor.
+ * @return The pool name.
+ */
+ public String get_file_pool_name(int fd) {
+ rlock.lock();
+ try {
+ return native_ceph_get_file_pool_name(instance_ptr, fd);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String native_ceph_get_file_pool_name(long mountp, int fd);
+
+ /**
+ * Get the default data pool of cephfs.
+ *
+ * @return The pool name.
+ */
+ public String get_default_data_pool_name() {
+ rlock.lock();
+ try {
+ return native_ceph_get_default_data_pool_name(instance_ptr);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String native_ceph_get_default_data_pool_name(long mountp);
+
+ /**
+ * Get the replication of a file.
+ *
+ * @param fd The file descriptor.
+ * @return The file replication.
+ */
+ public int get_file_replication(int fd) {
+ rlock.lock();
+ try {
+ return native_ceph_get_file_replication(instance_ptr, fd);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_get_file_replication(long mountp, int fd);
+
+ /**
+ * Favor reading from local replicas when possible.
+ *
+ * @param state Enable or disable localized reads.
+ */
+ public void localize_reads(boolean state) {
+ rlock.lock();
+ try {
+ native_ceph_localize_reads(instance_ptr, state);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_localize_reads(long mountp, boolean on);
+
+ /**
+ * Get file layout stripe unit granularity.
+ *
+ * @return Stripe unit granularity.
+ */
+ public int get_stripe_unit_granularity() {
+ rlock.lock();
+ try {
+ return native_ceph_get_stripe_unit_granularity(instance_ptr);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_get_stripe_unit_granularity(long mountp);
+
+ /**
+ * Get the pool id for the named pool.
+ *
+ * @param name The pool name.
+ * @return The pool id.
+ */
+ public int get_pool_id(String name) throws CephPoolException {
+ rlock.lock();
+ try {
+ return native_ceph_get_pool_id(instance_ptr, name);
+ } catch (FileNotFoundException e) {
+ throw new CephPoolException("pool name " + name + " not found");
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_get_pool_id(long mountp, String name) throws FileNotFoundException;
+
+ /**
+ * Get the pool replication factor.
+ *
+ * @param pool_id The pool id.
+ * @return Number of replicas stored in the pool.
+ */
+ public int get_pool_replication(int pool_id) throws CephPoolException {
+ rlock.lock();
+ try {
+ return native_ceph_get_pool_replication(instance_ptr, pool_id);
+ } catch (FileNotFoundException e) {
+ throw new CephPoolException("pool id " + pool_id + " not found");
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native int native_ceph_get_pool_replication(long mountp, int pool_id) throws FileNotFoundException;
+
+ /**
+ * Get file extent containing a given offset.
+ *
+ * @param fd The file descriptor.
+ * @param offset Offset in file.
+ * @return A CephFileExtent object.
+ */
+ public CephFileExtent get_file_extent(int fd, long offset) {
+ rlock.lock();
+ try {
+ return native_ceph_get_file_extent_osds(instance_ptr, fd, offset);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native CephFileExtent native_ceph_get_file_extent_osds(long mountp, int fd, long offset);
+
+ /**
+ * Get the fully qualified CRUSH location of an OSD.
+ *
+ * Returns (type, name) string pairs for each device in the CRUSH bucket
+ * hierarchy starting from the given OSD to the root.
+ *
+ * @param osd The OSD device id.
+ * @return List of pairs.
+ */
+ public Bucket[] get_osd_crush_location(int osd) {
+ rlock.lock();
+ try {
+ String[] parts = native_ceph_get_osd_crush_location(instance_ptr, osd);
+ Bucket[] path = new Bucket[parts.length / 2];
+ for (int i = 0; i < path.length; i++)
+ path[i] = new Bucket(parts[i*2], parts[i*2+1]);
+ return path;
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native String[] native_ceph_get_osd_crush_location(long mountp, int osd);
+
+ /**
+ * Get the network address of an OSD.
+ *
+ * @param osd The OSD device id.
+ * @return The network address.
+ */
+ public InetAddress get_osd_address(int osd) {
+ rlock.lock();
+ try {
+ return native_ceph_get_osd_addr(instance_ptr, osd);
+ } finally {
+ rlock.unlock();
+ }
+ }
+
+ private static native InetAddress native_ceph_get_osd_addr(long mountp, int osd);
+}
A => src/main/java/com/ceph/fs/CephNativeLoader.java +93 -0
@@ 1,93 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+class CephNativeLoader {
+ private static final CephNativeLoader instance = new CephNativeLoader();
+ private static boolean initialized = false;
+
+ private static final String JNI_PATH_ENV_VAR = "CEPH_JNI_PATH";
+ private static final String LIBRARY_NAME = "cephfs_jni";
+ private static final String LIBRARY_FILE = "libcephfs_jni.so";
+
+ private CephNativeLoader() {}
+
+ public static CephNativeLoader getInstance() {
+ return instance;
+ }
+
+ public synchronized void loadLibrary() {
+ if (initialized)
+ return;
+
+ boolean success = false;
+
+ /*
+ * Allow a Ceph specific environment variable to force
+ * the loading path.
+ */
+ String path = System.getenv(JNI_PATH_ENV_VAR);
+ try {
+ if (path != null) {
+ System.out.println("Loading libcephfs-jni: " + path);
+ System.load(path);
+ success = true;
+ } else {
+ try {
+ /*
+ * Try default Java loading path(s)
+ */
+ System.out.println("Loading libcephfs-jni from default path: " +
+ System.getProperty("java.library.path"));
+ System.loadLibrary(LIBRARY_NAME);
+ success = true;
+ } catch (final UnsatisfiedLinkError ule1) {
+ try {
+ /*
+ * Try RHEL/CentOS default path
+ */
+ path = "/usr/lib64/" + LIBRARY_FILE;
+ System.out.println("Loading libcephfs-jni: " + path);
+ System.load(path);
+ success = true;
+ } catch (final UnsatisfiedLinkError ule2) {
+ /*
+ * Try Ubuntu default path
+ */
+ path = "/usr/lib/jni/" + LIBRARY_FILE;
+ System.out.println("Loading libcephfs-jni: " + path);
+ System.load(path);
+ success = true;
+ }
+ }
+ }
+ } finally {
+ System.out.println("Loading libcephfs-jni: " +
+ (success ? "Success!" : "Failure!"));
+ }
+
+ /*
+ * Finish initialization
+ */
+ CephMount.native_initialize();
+ initialized = true;
+ }
+
+}
A => src/main/java/com/ceph/fs/CephNotDirectoryException.java +44 -0
@@ 1,44 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+
+/**
+ * Component of path is not a directory.
+ */
+public class CephNotDirectoryException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct CephNotDirectoryException.
+ */
+ public CephNotDirectoryException() {
+ super();
+ }
+
+ /**
+ * Construct CephNotDirectoryException with message.
+ */
+ public CephNotDirectoryException(String s) {
+ super(s);
+ }
+}
A => src/main/java/com/ceph/fs/CephNotMountedException.java +44 -0
@@ 1,44 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+
+/**
+ * Ceph is not mounted.
+ */
+public class CephNotMountedException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct CephNotMountedException.
+ */
+ public CephNotMountedException() {
+ super();
+ }
+
+ /**
+ * Construct CephNotMountedException with message.
+ */
+ public CephNotMountedException(String s) {
+ super(s);
+ }
+}
A => src/main/java/com/ceph/fs/CephPoolException.java +44 -0
@@ 1,44 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+import java.io.IOException;
+
+/**
+ * Exception related to Ceph pool.
+ */
+public class CephPoolException extends IOException {
+
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * Construct CephPoolException.
+ */
+ public CephPoolException() {
+ super();
+ }
+
+ /**
+ * Construct CephPoolException with message.
+ */
+ public CephPoolException(String s) {
+ super(s);
+ }
+}
A => src/main/java/com/ceph/fs/CephStat.java +53 -0
@@ 1,53 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+/**
+ * Holds struct stat fields.
+ */
+public class CephStat {
+
+ /* Set from native */
+ private boolean is_file; /* S_ISREG */
+ private boolean is_directory; /* S_ISDIR */
+ private boolean is_symlink; /* S_ISLNK */
+
+ public int mode;
+ public int uid;
+ public int gid;
+ public long size;
+ public long blksize;
+ public long blocks;
+ public long a_time;
+ public long m_time;
+
+ public boolean isFile() {
+ return is_file;
+ }
+
+ public boolean isDir() {
+ return is_directory;
+ }
+
+ public boolean isSymlink() {
+ return is_symlink;
+ }
+
+}
A => src/main/java/com/ceph/fs/CephStatVFS.java +33 -0
@@ 1,33 @@
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+package com.ceph.fs;
+
+/**
+ * Holds struct statvfs fields.
+ */
+public class CephStatVFS {
+ public long bsize;
+ public long frsize;
+ public long blocks;
+ public long bavail;
+ public long files;
+ public long fsid;
+ public long namemax;
+}
A => src/main/java/org/safcephfs/CephFSDocumentsProvider.java +154 -0
@@ 1,154 @@
+package org.safcephfs;
+
+import android.content.SharedPreferences;
+import android.database.Cursor;
+import android.database.MatrixCursor;
+import android.os.CancellationSignal;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.os.StrictMode;
+import android.preference.PreferenceManager;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsProvider;
+import android.webkit.MimeTypeMap;
+import android.widget.Toast;
+import android.util.Log;
+
+import java.io.IOException;
+import java.util.Vector;
+
+import com.ceph.fs.CephMount;
+import com.ceph.fs.CephStat;
+
+public class CephFSDocumentsProvider extends DocumentsProvider {
+ private String id, mon, path, key;
+ private ToastThread lthread;
+
+ private static final String[] DEFAULT_ROOT_PROJECTION = new String[]{
+ Root.COLUMN_ROOT_ID,
+ Root.COLUMN_FLAGS,
+ Root.COLUMN_ICON,
+ Root.COLUMN_TITLE,
+ Root.COLUMN_DOCUMENT_ID,
+ };
+
+ private static final String[] DEFAULT_DOC_PROJECTION = new String[]{
+ Document.COLUMN_DOCUMENT_ID,
+ Document.COLUMN_DISPLAY_NAME,
+ Document.COLUMN_MIME_TYPE,
+ Document.COLUMN_LAST_MODIFIED,
+ Document.COLUMN_SIZE
+ };
+
+ private static String getMime(String filename) {
+ int idx = filename.lastIndexOf(".");
+ if (idx > 0) {
+ String mime = MimeTypeMap.getSingleton()
+ .getMimeTypeFromExtension(
+ filename.substring(idx + 1).toLowerCase()
+ );
+ if (mime != null) return mime;
+ }
+ return "application/octet-stream";
+ }
+
+ @Override
+ public boolean onCreate() {
+ lthread = new ToastThread(getContext());
+ lthread.start();
+ return true;
+ }
+
+ public ParcelFileDescriptor openDocument(String documentId,
+ String mode,CancellationSignal cancellationSignal) {
+ throw new UnsupportedOperationException("TODO");
+ }
+
+ public Cursor queryChildDocuments(String parentDocumentId,
+ String[] projection,String sortOrder) {
+ MatrixCursor result=new MatrixCursor(projection != null ? projection : DEFAULT_DOC_PROJECTION);
+ Log.v("CephFS","qcf " + parentDocumentId);
+ String filename = parentDocumentId.substring(parentDocumentId.indexOf("/") + 1);
+ CephMount cm = new CephMount(id);
+ cm.conf_set("mon_host", mon);
+ cm.conf_set("key", key);
+ cm.mount(path);
+ try {
+ String[] res = cm.listdir(filename);
+ for (String entry : res) {
+ CephStat cs = new CephStat();
+ Log.v("CephFS","qcf " + parentDocumentId + " " + entry);
+ cm.lstat(filename + "/" + entry, cs);
+ MatrixCursor.RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, parentDocumentId + '/' + entry);
+ row.add(Document.COLUMN_DISPLAY_NAME, entry);
+ if (cs.isDir()) {
+ row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ } else if (cs.isFile()) {
+ row.add(Document.COLUMN_MIME_TYPE, getMime(entry));
+ }
+ row.add(Document.COLUMN_SIZE, cs.size);
+ row.add(Document.COLUMN_LAST_MODIFIED, cs.m_time);
+ }
+ } catch (Exception e) {
+ Log.e("CephFS","qcf " + parentDocumentId + " " + e.toString());
+ Message msg = lthread.handler.obtainMessage();
+ msg.obj = e.toString();
+ lthread.handler.sendMessage(msg);
+ }
+ cm.unmount();
+ return result;
+ }
+
+ public Cursor queryDocument(String documentId, String[] projection) {
+ MatrixCursor result = new MatrixCursor(projection != null ? projection : DEFAULT_DOC_PROJECTION);
+ String filename = documentId.substring(documentId.indexOf("/") + 1);
+ CephMount cm = new CephMount(id);
+ cm.conf_set("mon_host", mon);
+ cm.conf_set("key", key);
+ cm.mount(path);
+ try {
+ CephStat cs = new CephStat();
+ Log.v("CephFS","qf " + documentId);
+ cm.lstat(filename, cs);
+ MatrixCursor.RowBuilder row = result.newRow();
+ row.add(Document.COLUMN_DOCUMENT_ID, documentId);
+ row.add(Document.COLUMN_DISPLAY_NAME, filename);
+ if (cs.isDir()) {
+ row.add(Document.COLUMN_MIME_TYPE, Document.MIME_TYPE_DIR);
+ } else if (cs.isFile()) {
+ row.add(Document.COLUMN_MIME_TYPE, getMime(filename));
+ }
+ row.add(Document.COLUMN_SIZE, cs.size);
+ row.add(Document.COLUMN_LAST_MODIFIED, cs.m_time);
+ } catch(Exception e){
+ Log.e("CephFS","qf " + documentId + " " + e.toString());
+ Message msg = lthread.handler.obtainMessage();
+ msg.obj = e.toString();
+ lthread.handler.sendMessage(msg);
+ }
+ cm.unmount();
+ return result;
+ }
+
+ public Cursor queryRoots(String[] projection) {
+ MatrixCursor result=new MatrixCursor(projection != null ? projection : DEFAULT_ROOT_PROJECTION);
+ SharedPreferences settings=PreferenceManager
+ .getDefaultSharedPreferences(getContext());
+ mon = settings.getString("mon", "");
+ key = settings.getString("key", "");
+ id = settings.getString("id", "");
+ path = settings.getString("path", "");
+ MatrixCursor.RowBuilder row=result.newRow();
+ row.add(Root.COLUMN_ROOT_ID, id + "@" + mon + ":" + path);
+ row.add(Root.COLUMN_DOCUMENT_ID, "root/");
+ row.add(Root.COLUMN_FLAGS, 0);
+ row.add(Root.COLUMN_TITLE,"CephFS " + mon + ":" + path);
+ row.add(Root.COLUMN_ICON, R.mipmap.sym_def_app_icon);
+ return result;
+ }
+}
+
A => src/main/java/org/safcephfs/MainActivity.java +76 -0
@@ 1,76 @@
+package org.safcephfs;
+
+import android.content.SharedPreferences;
+import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.net.Uri;
+import android.preference.EditTextPreference;
+import android.preference.PreferenceActivity;
+import android.provider.DocumentsContract;
+import android.os.Bundle;
+import android.util.Log;
+
+import java.util.Arrays;
+
+public class MainActivity extends PreferenceActivity
+ implements OnSharedPreferenceChangeListener {
+ private EditTextPreference monText, pathText, idText, keyText;
+
+ private void notifyRootChanges(){
+ Uri uri = DocumentsContract.buildRootsUri("org.safcephfs");
+ getContentResolver().notifyChange(uri, null);
+ }
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ addPreferencesFromResource(R.xml.main_pre);
+
+ monText = (EditTextPreference) findPreference("mon");
+ pathText = (EditTextPreference) findPreference("path");
+ idText = (EditTextPreference) findPreference("id");
+ keyText = (EditTextPreference) findPreference("key");
+
+ SharedPreferences settings=getPreferenceScreen().getSharedPreferences();
+ settings.registerOnSharedPreferenceChangeListener(this);
+ if (!settings.getString("mon", "").equals(""))
+ monText.setSummary(settings.getString("mon", ""));
+ if (!settings.getString("path", "").equals(""))
+ pathText.setSummary(settings.getString("path", ""));
+ if (!settings.getString("id", "").equals(""))
+ idText.setSummary(settings.getString("id", ""));
+ if (!settings.getString("key", "").equals(""))
+ keyText.setSummary(getString(R.string.key_filled));
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences settings,
+ String key) {
+ notifyRootChanges();
+ switch (key) {
+ case "mon":
+ if (settings.getString("mon", "").equals(""))
+ monText.setSummary(getString(R.string.mon_summary));
+ else
+ monText.setSummary(settings.getString("mon", ""));
+ break;
+ case "path":
+ if (settings.getString("path", "").equals(""))
+ pathText.setSummary(getString(R.string.path_summary));
+ else
+ pathText.setSummary(settings.getString("path", ""));
+ break;
+ case "id":
+ if (settings.getString("id", "").equals(""))
+ idText.setSummary(getString(R.string.id_summary));
+ else
+ idText.setSummary(settings.getString("id", ""));
+ break;
+ case "key":
+ if (settings.getString("key", "").equals(""))
+ keyText.setSummary(getString(R.string.key_summary));
+ else
+ keyText.setSummary(getString(R.string.key_filled));
+ break;
+ }
+ }
+}
A => src/main/java/org/safcephfs/ToastThread.java +27 -0
@@ 1,27 @@
+package org.safcephfs;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.widget.Toast;
+
+public class ToastThread extends Thread {
+ public Handler handler;
+ private Context context;
+
+ public ToastThread(Context context){
+ this.context=context;
+ }
+
+ public void run() {
+ Looper.prepare();
+ handler=new Handler() {
+ public void handleMessage(Message msg) {
+ Toast.makeText(context,(String)msg.obj,Toast.LENGTH_SHORT).show();
+ }
+ };
+ Looper.loop();
+ }
+}
+
A => src/main/jniLibs/arm64-v8a/libboost_filesystem.so +0 -0
A => src/main/jniLibs/arm64-v8a/libboost_iostreams.so +0 -0
A => src/main/jniLibs/arm64-v8a/libboost_thread.so +0 -0
A => src/main/jniLibs/arm64-v8a/libc++_shared.so +0 -0
A => src/main/jniLibs/arm64-v8a/libcephfs.so +0 -0
A => src/main/jniLibs/arm64-v8a/libcephfs_jni.so +0 -0
A => src/main/jniLibs/arm64-v8a/libcrc32.so +0 -0
A => src/main/jniLibs/arm64-v8a/libcrypto_1_1.so +0 -0
A => src/main/jniLibs/arm64-v8a/libfmt.so +0 -0
A => src/main/res/mipmap-hdpi/sym_def_app_icon.png +0 -0
A => src/main/res/mipmap-ldpi/sym_def_app_icon.png +0 -0
A => src/main/res/mipmap-mdpi/sym_def_app_icon.png +0 -0
A => src/main/res/mipmap-xhdpi/sym_def_app_icon.png +0 -0
A => src/main/res/mipmap-xxhdpi/sym_def_app_icon.png +0 -0
A => src/main/res/mipmap-xxxhdpi/sym_def_app_icon.png +0 -0
A => src/main/res/values/strings.xml +15 -0
@@ 1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="app_name">SAF CephFS</string>
+ <string name="conn_det">Connection Details</string>
+ <string name="mon">Monitors</string>
+ <string name="mon_summary">Monitors to connect.</string>
+ <string name="path">Path to mount</string>
+ <string name="path_summary">Path on CephFS to mount.</string>
+ <string name="auth">Authentication Details</string>
+ <string name="id">CephX user</string>
+ <string name="id_summary">CephX user to authenticate.</string>
+ <string name="key">Secret key</string>
+ <string name="key_summary">Secret key of CephX user.</string>
+ <string name="key_filled">(filled)</string>
+</resources>
A => src/main/res/xml/main_pre.xml +20 -0
@@ 1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+ <PreferenceCategory android:title="@string/conn_det">
+ <EditTextPreference android:key="mon"
+ android:summary="@string/mon_summary"
+ android:title="@string/mon" />
+ <EditTextPreference android:key="path"
+ android:summary="@string/path_summary"
+ android:title="@string/path" />
+ </PreferenceCategory>
+ <PreferenceCategory android:title="@string/auth">
+ <EditTextPreference android:key="id"
+ android:summary="@string/id_summary"
+ android:title="@string/id" />
+ <EditTextPreference android:title="@string/key"
+ android:summary="@string/key_summary"
+ android:inputType="textPassword"
+ android:key="key" />
+ </PreferenceCategory>
+</PreferenceScreen>