summaryrefslogtreecommitdiffstats
path: root/src/java
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:45:59 +0000
commit19fcec84d8d7d21e796c7624e521b60d28ee21ed (patch)
tree42d26aa27d1e3f7c0b8bd3fd14e7d7082f5008dc /src/java
parentInitial commit. (diff)
downloadceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.tar.xz
ceph-19fcec84d8d7d21e796c7624e521b60d28ee21ed.zip
Adding upstream version 16.2.11+ds.upstream/16.2.11+dsupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/java')
-rw-r--r--src/java/.gitignore6
-rw-r--r--src/java/CMakeLists.txt61
-rw-r--r--src/java/README54
-rw-r--r--src/java/build.xml75
-rw-r--r--src/java/java/com/ceph/crush/Bucket.java42
-rw-r--r--src/java/java/com/ceph/fs/CephAlreadyMountedException.java44
-rw-r--r--src/java/java/com/ceph/fs/CephFileAlreadyExistsException.java44
-rw-r--r--src/java/java/com/ceph/fs/CephFileExtent.java66
-rw-r--r--src/java/java/com/ceph/fs/CephMount.java1103
-rw-r--r--src/java/java/com/ceph/fs/CephNativeLoader.java93
-rw-r--r--src/java/java/com/ceph/fs/CephNotDirectoryException.java44
-rw-r--r--src/java/java/com/ceph/fs/CephNotMountedException.java44
-rw-r--r--src/java/java/com/ceph/fs/CephPoolException.java44
-rw-r--r--src/java/java/com/ceph/fs/CephStat.java53
-rw-r--r--src/java/java/com/ceph/fs/CephStatVFS.java33
-rw-r--r--src/java/native/CMakeLists.txt14
-rw-r--r--src/java/native/JniConstants.cpp42
-rw-r--r--src/java/native/JniConstants.h52
-rw-r--r--src/java/native/ScopedLocalRef.h63
-rw-r--r--src/java/native/libcephfs_jni.cc3031
-rw-r--r--src/java/test/com/ceph/fs/CephAllTests.java44
-rw-r--r--src/java/test/com/ceph/fs/CephDoubleMountTest.java45
-rw-r--r--src/java/test/com/ceph/fs/CephMountCreateTest.java91
-rw-r--r--src/java/test/com/ceph/fs/CephMountTest.java1040
-rw-r--r--src/java/test/com/ceph/fs/CephUnmountedTest.java164
25 files changed, 6392 insertions, 0 deletions
diff --git a/src/java/.gitignore b/src/java/.gitignore
new file mode 100644
index 000000000..6aa4d6209
--- /dev/null
+++ b/src/java/.gitignore
@@ -0,0 +1,6 @@
+*.class
+libcephfs.jar
+libcephfs-test.jar
+native/com_ceph_fs_CephMount.h
+TEST-*.txt
+doc
diff --git a/src/java/CMakeLists.txt b/src/java/CMakeLists.txt
new file mode 100644
index 000000000..62b5259c9
--- /dev/null
+++ b/src/java/CMakeLists.txt
@@ -0,0 +1,61 @@
+find_package(Java COMPONENTS Development REQUIRED)
+find_package(JNI REQUIRED)
+include(UseJava)
+
+set(java_srcs
+ java/com/ceph/crush/Bucket.java
+ java/com/ceph/fs/CephAlreadyMountedException.java
+ java/com/ceph/fs/CephFileAlreadyExistsException.java
+ java/com/ceph/fs/CephFileExtent.java
+ java/com/ceph/fs/CephMount.java
+ java/com/ceph/fs/CephNativeLoader.java
+ java/com/ceph/fs/CephNotDirectoryException.java
+ java/com/ceph/fs/CephNotMountedException.java
+ java/com/ceph/fs/CephPoolException.java
+ java/com/ceph/fs/CephStat.java
+ java/com/ceph/fs/CephStatVFS.java)
+
+# note: for the -source 1.7 builds, we add
+# -Xlint:-options
+# to get rid of the warning
+# warning: [options] bootstrap class path not set in conjunction with -source 1.7
+# as per
+# https://blogs.oracle.com/darcy/entry/bootclasspath_older_source
+set(CMAKE_JAVA_COMPILE_FLAGS "-source" "1.8" "-target" "1.8" "-Xlint:-options")
+set(jni_header_dir "${CMAKE_CURRENT_BINARY_DIR}/native")
+if(CMAKE_VERSION VERSION_LESS 3.11)
+ set(CMAKE_JAVA_COMPILE_FLAGS ${CMAKE_JAVA_COMPILE_FLAGS} "-h" ${jni_header_dir})
+ add_jar(libcephfs ${java_srcs})
+ add_custom_target(
+ jni-header
+ DEPENDS libcephfs)
+ add_dependencies(jni-header libcephfs)
+else()
+ add_jar(libcephfs ${java_srcs}
+ GENERATE_NATIVE_HEADERS jni-header
+ DESTINATION ${jni_header_dir})
+endif()
+get_property(libcephfs_jar TARGET libcephfs PROPERTY JAR_FILE)
+install_jar(libcephfs share/java)
+
+find_jar(JUNIT_JAR
+ NAMES junit4 junit
+ PATHS "/usr/share/java")
+if(JUNIT_JAR)
+ set(CMAKE_JAVA_INCLUDE_PATH ${JUNIT_JAR} ${libcephfs_jar})
+ set(java_test_srcs
+ test/com/ceph/fs/CephAllTests.java
+ test/com/ceph/fs/CephDoubleMountTest.java
+ test/com/ceph/fs/CephMountCreateTest.java
+ test/com/ceph/fs/CephMountTest.java
+ test/com/ceph/fs/CephUnmountedTest.java)
+ add_jar(libcephfs-test ${java_test_srcs})
+ add_dependencies(libcephfs-test libcephfs)
+ install_jar(libcephfs-test share/java)
+endif(JUNIT_JAR)
+
+add_subdirectory(native)
+
+add_custom_target(java DEPENDS
+ libcephfs.jar
+ libcephfs_jni)
diff --git a/src/java/README b/src/java/README
new file mode 100644
index 000000000..5077bb301
--- /dev/null
+++ b/src/java/README
@@ -0,0 +1,54 @@
+libcephfs Java wrappers
+=======================
+
+- native/: C++
+- java/: Java
+- test/: JUnit tests
+- lib/: JUnit library
+- build.xml: Test runner
+
+Building
+--------
+
+Autotools handles the build using the configure flag --enable-cephfs-java
+
+Testing
+-------
+
+These tests assume a live cluster, and depend on JUnit4 and Ant.
+
+To run the tests make sure that the JUnit4 JAR is installed.
+Install it via a package manager or like this:
+
+ $ mkdir lib
+ $ cd lib
+ $ wget https://github.com/downloads/KentBeck/junit/junit-4.8.2.jar
+
+And then add the jar to the CLASSPATH.
+*NOTE* for now, configure is only looking for this jar in the
+/usr/share/java directory as junit4.jar. So create a softlink
+to that location from wherever the junit jar is installed.
+
+Ant is used to run the unit test (apt-get install ant). For example:
+
+ $ cd src/
+ $ ./vstart -d -n --localhost
+ $ cd java
+ $ CEPHFS_CONF=../ceph.conf CLASSPATH=/usr/share/java/junit4.jar ant test
+
+1. The tests depend on the compiled wrappers. If the wrappers are installed as
+part of a package (e.g. Debian package) then this should 'just work'. Ant will
+also look in the current directory for 'libcephfs.jar' and 'libcephfs-test.jar';
+and in ../build/lib for the
+JNI library. If all else fails, set the environment variables CEPHFS_JAR, and
+CEPHFS_JNI_LIB accordingly.
+
+2. Set CEPHFS_CONF environment variable to point to a ceph.conf. This can be
+omitted if the desired configuration file can be found in a default location.
+
+Documentation
+-------------
+
+Ant is used to build the Javadocs:
+
+ $ ant docs
diff --git a/src/java/build.xml b/src/java/build.xml
new file mode 100644
index 000000000..49509adbf
--- /dev/null
+++ b/src/java/build.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0"?>
+<project name="cephfs-java" default="main" basedir=".">
+
+ <description>CephFS Java Bindings</description>
+
+ <property name="src.dir" location="java" />
+ <property name="doc.dir" location="doc" />
+ <property name="test.dir" location="test" />
+
+ <property environment="env"/>
+
+ <target name="clean">
+ <delete dir="${doc.dir}" />
+ <delete>
+ <fileset dir="${test.dir}" includes="**/*.class" />
+ </delete>
+ <delete file="./libcephfs-test.jar" />
+ </target>
+
+ <target name="makedir">
+ <mkdir dir="${doc.dir}" />
+ </target>
+
+ <target name="docs" depends="makedir">
+ <javadoc packagenames="src" sourcepath="${src.dir}" destdir="${doc.dir}">
+ <fileset dir="${src.dir}">
+ <include name="**/*.java" />
+ </fileset>
+ </javadoc>
+ </target>
+
+ <target name="compile-tests-jar">
+ <javac srcdir="${test.dir}" destdir="${test.dir}"
+ includeantruntime="false" source="1.5" target="1.5">
+ <classpath>
+ <pathelement location="${env.CEPHFS_JAR}"/>
+ <pathelement location="libcephfs.jar"/>
+ <pathelement location="${env.CLASSPATH}" />
+ </classpath>
+ </javac>
+ <jar destfile="./libcephfs-test.jar">
+ <fileset dir="${test.dir}" includes="**/*.class"/>
+ </jar>
+ </target>
+
+ <target name="test" depends="compile-tests-jar">
+ <junit printsummary="yes" haltonfailure="yes" showoutput="yes" fork="true">
+ <sysproperty key="java.library.path" path="${env.CEPHFS_JNI_LIB}:../../build/lib/"/>
+ <sysproperty key="CEPH_CONF_FILE" path="${env.CEPHFS_CONF}"/>
+ <jvmarg value="-Xcheck:jni"/>
+ <classpath>
+ <pathelement location="${env.CEPHFS_JAR}"/>
+ <pathelement location="libcephfs.jar"/>
+ <pathelement location="libcephfs-test.jar"/>
+ </classpath>
+ <formatter type="plain"/>
+ <test name="com.ceph.fs.CephAllTests" haltonerror="true" />
+ </junit>
+ </target>
+
+ <target name="test-compat" depends="compile-tests-jar">
+ <junit printsummary="yes" haltonfailure="yes" showoutput="yes" fork="true">
+ <sysproperty key="java.library.path" path="${env.CEPHFS_JNI_LIB}:../../build/lib/"/>
+ <sysproperty key="CEPH_CONF_FILE" path="${env.CEPHFS_CONF}"/>
+ <classpath>
+ <pathelement location="${env.CEPHFS_JAR}"/>
+ <pathelement location="libcephfs.jar"/>
+ <pathelement location="libcephfs-test.jar"/>
+ </classpath>
+ <formatter type="plain"/>
+ <test name="com.ceph.fs.CephAllTests" haltonerror="true" />
+ </junit>
+ </target>
+
+</project>
diff --git a/src/java/java/com/ceph/crush/Bucket.java b/src/java/java/com/ceph/crush/Bucket.java
new file mode 100644
index 000000000..989f61982
--- /dev/null
+++ b/src/java/java/com/ceph/crush/Bucket.java
@@ -0,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 + "]";
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephAlreadyMountedException.java b/src/java/java/com/ceph/fs/CephAlreadyMountedException.java
new file mode 100644
index 000000000..23b93e9a1
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephAlreadyMountedException.java
@@ -0,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);
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephFileAlreadyExistsException.java b/src/java/java/com/ceph/fs/CephFileAlreadyExistsException.java
new file mode 100644
index 000000000..12cdcb2bf
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephFileAlreadyExistsException.java
@@ -0,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);
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephFileExtent.java b/src/java/java/com/ceph/fs/CephFileExtent.java
new file mode 100644
index 000000000..909ff1389
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephFileExtent.java
@@ -0,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) + "]";
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephMount.java b/src/java/java/com/ceph/fs/CephMount.java
new file mode 100644
index 000000000..786a6ece2
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephMount.java
@@ -0,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);
+}
diff --git a/src/java/java/com/ceph/fs/CephNativeLoader.java b/src/java/java/com/ceph/fs/CephNativeLoader.java
new file mode 100644
index 000000000..358ca243e
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephNativeLoader.java
@@ -0,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;
+ }
+
+}
diff --git a/src/java/java/com/ceph/fs/CephNotDirectoryException.java b/src/java/java/com/ceph/fs/CephNotDirectoryException.java
new file mode 100644
index 000000000..3fb77c77f
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephNotDirectoryException.java
@@ -0,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);
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephNotMountedException.java b/src/java/java/com/ceph/fs/CephNotMountedException.java
new file mode 100644
index 000000000..5a479b5e4
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephNotMountedException.java
@@ -0,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);
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephPoolException.java b/src/java/java/com/ceph/fs/CephPoolException.java
new file mode 100644
index 000000000..c5092e6c4
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephPoolException.java
@@ -0,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);
+ }
+}
diff --git a/src/java/java/com/ceph/fs/CephStat.java b/src/java/java/com/ceph/fs/CephStat.java
new file mode 100644
index 000000000..12aa8c98e
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephStat.java
@@ -0,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;
+ }
+
+}
diff --git a/src/java/java/com/ceph/fs/CephStatVFS.java b/src/java/java/com/ceph/fs/CephStatVFS.java
new file mode 100644
index 000000000..4a37a28db
--- /dev/null
+++ b/src/java/java/com/ceph/fs/CephStatVFS.java
@@ -0,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;
+}
diff --git a/src/java/native/CMakeLists.txt b/src/java/native/CMakeLists.txt
new file mode 100644
index 000000000..2c6067b60
--- /dev/null
+++ b/src/java/native/CMakeLists.txt
@@ -0,0 +1,14 @@
+add_library(cephfs_jni SHARED
+ libcephfs_jni.cc
+ ScopedLocalRef.h
+ JniConstants.cpp
+ JniConstants.h)
+set_target_properties(cephfs_jni PROPERTIES
+ VERSION 1.0.0
+ SOVERSION 1)
+add_dependencies(cephfs_jni jni-header)
+include_directories(${JNI_INCLUDE_DIRS} ${CMAKE_CURRENT_BINARY_DIR})
+target_link_libraries(cephfs_jni PRIVATE cephfs ceph-common
+ ${EXTRALIBS} ${JNI_LIBRARIES})
+install(TARGETS cephfs_jni
+ DESTINATION ${CMAKE_INSTALL_LIBDIR})
diff --git a/src/java/native/JniConstants.cpp b/src/java/native/JniConstants.cpp
new file mode 100644
index 000000000..cd54c99b9
--- /dev/null
+++ b/src/java/native/JniConstants.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "JniConstants.h"
+#include "ScopedLocalRef.h"
+
+#include <stdlib.h>
+
+jclass JniConstants::inet6AddressClass;
+jclass JniConstants::inetAddressClass;
+jclass JniConstants::inetSocketAddressClass;
+jclass JniConstants::stringClass;
+
+static jclass findClass(JNIEnv* env, const char* name) {
+ ScopedLocalRef<jclass> localClass(env, env->FindClass(name));
+ jclass result = reinterpret_cast<jclass>(env->NewGlobalRef(localClass.get()));
+ if (result == NULL) {
+ fprintf(stderr, "failed to find class '%s'", name);
+ abort();
+ }
+ return result;
+}
+
+void JniConstants::init(JNIEnv* env) {
+ inet6AddressClass = findClass(env, "java/net/Inet6Address");
+ inetAddressClass = findClass(env, "java/net/InetAddress");
+ inetSocketAddressClass = findClass(env, "java/net/InetSocketAddress");
+ stringClass = findClass(env, "java/lang/String");
+}
diff --git a/src/java/native/JniConstants.h b/src/java/native/JniConstants.h
new file mode 100644
index 000000000..acee86709
--- /dev/null
+++ b/src/java/native/JniConstants.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef JNI_CONSTANTS_H_included
+#define JNI_CONSTANTS_H_included
+
+#include <jni.h>
+
+/**
+ * A cache to avoid calling FindClass at runtime.
+ *
+ * Class lookup is relatively expensive (2.5us on passion-eng at the time of writing), so we do
+ * all such lookups eagerly at VM startup. This means that code that never uses, say,
+ * java.util.zip.Deflater still has to pay for the lookup, but it means that on a device the cost
+ * is definitely paid during boot and amortized. A central cache also removes the temptation to
+ * dynamically call FindClass rather than add a small cache to each file that needs one. Another
+ * cost is that each class cached here requires a global reference, though in practice we save
+ * enough by not having a global reference for each file that uses a class such as java.lang.String
+ * which is used in several files.
+ *
+ * FindClass is still called in a couple of situations: when throwing exceptions, and in some of
+ * the serialization code. The former is clearly not a performance case, and we're currently
+ * assuming that neither is the latter.
+ *
+ * TODO: similar arguments hold for field and method IDs; we should cache them centrally too.
+ */
+struct JniConstants {
+ static void init(JNIEnv* env);
+
+ static jclass inet6AddressClass;
+ static jclass inetAddressClass;
+ static jclass inetSocketAddressClass;
+ static jclass stringClass;
+};
+
+#define NATIVE_METHOD(className, functionName, signature) \
+ { #functionName, signature, reinterpret_cast<void*>(className ## _ ## functionName) }
+
+#endif // JNI_CONSTANTS_H_included
diff --git a/src/java/native/ScopedLocalRef.h b/src/java/native/ScopedLocalRef.h
new file mode 100644
index 000000000..71d577679
--- /dev/null
+++ b/src/java/native/ScopedLocalRef.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef SCOPED_LOCAL_REF_H_included
+#define SCOPED_LOCAL_REF_H_included
+
+#include "jni.h"
+
+#include <stddef.h>
+
+// A smart pointer that deletes a JNI local reference when it goes out of scope.
+template<typename T>
+class ScopedLocalRef {
+public:
+ ScopedLocalRef(JNIEnv* env, T localRef) : mEnv(env), mLocalRef(localRef) {
+ }
+
+ ~ScopedLocalRef() {
+ reset();
+ }
+
+ void reset(T ptr = NULL) {
+ if (ptr != mLocalRef) {
+ if (mLocalRef != NULL) {
+ mEnv->DeleteLocalRef(mLocalRef);
+ }
+ mLocalRef = ptr;
+ }
+ }
+
+ T release() __attribute__((warn_unused_result)) {
+ T localRef = mLocalRef;
+ mLocalRef = NULL;
+ return localRef;
+ }
+
+ T get() const {
+ return mLocalRef;
+ }
+
+private:
+ JNIEnv* mEnv;
+ T mLocalRef;
+
+ // Disallow copy and assignment.
+ ScopedLocalRef(const ScopedLocalRef&);
+ void operator=(const ScopedLocalRef&);
+};
+
+#endif // SCOPED_LOCAL_REF_H_included
diff --git a/src/java/native/libcephfs_jni.cc b/src/java/native/libcephfs_jni.cc
new file mode 100644
index 000000000..74ef8dcdd
--- /dev/null
+++ b/src/java/native/libcephfs_jni.cc
@@ -0,0 +1,3031 @@
+/*
+ * 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.
+ */
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <jni.h>
+
+#include "ScopedLocalRef.h"
+#include "JniConstants.h"
+
+#include "include/cephfs/libcephfs.h"
+#include "common/dout.h"
+
+#define dout_subsys ceph_subsys_javaclient
+
+#include "com_ceph_fs_CephMount.h"
+
+#define CEPH_STAT_CP "com/ceph/fs/CephStat"
+#define CEPH_STAT_VFS_CP "com/ceph/fs/CephStatVFS"
+#define CEPH_FILE_EXTENT_CP "com/ceph/fs/CephFileExtent"
+#define CEPH_MOUNT_CP "com/ceph/fs/CephMount"
+#define CEPH_NOTMOUNTED_CP "com/ceph/fs/CephNotMountedException"
+#define CEPH_FILEEXISTS_CP "com/ceph/fs/CephFileAlreadyExistsException"
+#define CEPH_ALREADYMOUNTED_CP "com/ceph/fs/CephAlreadyMountedException"
+#define CEPH_NOTDIR_CP "com/ceph/fs/CephNotDirectoryException"
+
+/*
+ * Flags to open(). must be synchronized with CephMount.java
+ *
+ * There are two versions of flags: the version in Java and the version in the
+ * target library (e.g. libc or libcephfs). We control the Java values and map
+ * to the target value with fixup_* functions below. This is much faster than
+ * keeping the values in Java and making a cross-JNI up-call to retrieve them,
+ * and makes it easy to keep any platform specific value changes in this file.
+ */
+#define JAVA_O_RDONLY 1
+#define JAVA_O_RDWR 2
+#define JAVA_O_APPEND 4
+#define JAVA_O_CREAT 8
+#define JAVA_O_TRUNC 16
+#define JAVA_O_EXCL 32
+#define JAVA_O_WRONLY 64
+#define JAVA_O_DIRECTORY 128
+
+/*
+ * Whence flags for seek(). sync with CephMount.java if changed.
+ *
+ * Mapping of SEEK_* done in seek function.
+ */
+#define JAVA_SEEK_SET 1
+#define JAVA_SEEK_CUR 2
+#define JAVA_SEEK_END 3
+
+/*
+ * File attribute flags. sync with CephMount.java if changed.
+ */
+#define JAVA_SETATTR_MODE 1
+#define JAVA_SETATTR_UID 2
+#define JAVA_SETATTR_GID 4
+#define JAVA_SETATTR_MTIME 8
+#define JAVA_SETATTR_ATIME 16
+
+/*
+ * Setxattr flags. sync with CephMount.java if changed.
+ */
+#define JAVA_XATTR_CREATE 1
+#define JAVA_XATTR_REPLACE 2
+#define JAVA_XATTR_NONE 3
+
+/*
+ * flock flags. sync with CephMount.java if changed.
+ */
+#define JAVA_LOCK_SH 1
+#define JAVA_LOCK_EX 2
+#define JAVA_LOCK_NB 4
+#define JAVA_LOCK_UN 8
+
+/* Map JAVA_O_* open flags to values in libc */
+static inline int fixup_open_flags(jint jflags)
+{
+ int ret = 0;
+
+#define FIXUP_OPEN_FLAG(name) \
+ if (jflags & JAVA_##name) \
+ ret |= name;
+
+ FIXUP_OPEN_FLAG(O_RDONLY)
+ FIXUP_OPEN_FLAG(O_RDWR)
+ FIXUP_OPEN_FLAG(O_APPEND)
+ FIXUP_OPEN_FLAG(O_CREAT)
+ FIXUP_OPEN_FLAG(O_TRUNC)
+ FIXUP_OPEN_FLAG(O_EXCL)
+ FIXUP_OPEN_FLAG(O_WRONLY)
+ FIXUP_OPEN_FLAG(O_DIRECTORY)
+
+#undef FIXUP_OPEN_FLAG
+
+ return ret;
+}
+
+/* Map JAVA_SETATTR_* to values in ceph lib */
+static inline int fixup_attr_mask(jint jmask)
+{
+ int mask = 0;
+
+#define FIXUP_ATTR_MASK(name) \
+ if (jmask & JAVA_##name) \
+ mask |= CEPH_##name;
+
+ FIXUP_ATTR_MASK(SETATTR_MODE)
+ FIXUP_ATTR_MASK(SETATTR_UID)
+ FIXUP_ATTR_MASK(SETATTR_GID)
+ FIXUP_ATTR_MASK(SETATTR_MTIME)
+ FIXUP_ATTR_MASK(SETATTR_ATIME)
+
+#undef FIXUP_ATTR_MASK
+
+ return mask;
+}
+
+/* Cached field IDs for com.ceph.fs.CephStat */
+static jfieldID cephstat_mode_fid;
+static jfieldID cephstat_uid_fid;
+static jfieldID cephstat_gid_fid;
+static jfieldID cephstat_size_fid;
+static jfieldID cephstat_blksize_fid;
+static jfieldID cephstat_blocks_fid;
+static jfieldID cephstat_a_time_fid;
+static jfieldID cephstat_m_time_fid;
+static jfieldID cephstat_is_file_fid;
+static jfieldID cephstat_is_directory_fid;
+static jfieldID cephstat_is_symlink_fid;
+
+/* Cached field IDs for com.ceph.fs.CephStatVFS */
+static jfieldID cephstatvfs_bsize_fid;
+static jfieldID cephstatvfs_frsize_fid;
+static jfieldID cephstatvfs_blocks_fid;
+static jfieldID cephstatvfs_bavail_fid;
+static jfieldID cephstatvfs_files_fid;
+static jfieldID cephstatvfs_fsid_fid;
+static jfieldID cephstatvfs_namemax_fid;
+
+/* Cached field IDs for com.ceph.fs.CephMount */
+static jfieldID cephmount_instance_ptr_fid;
+
+/* Cached field IDs for com.ceph.fs.CephFileExtent */
+static jclass cephfileextent_cls;
+static jmethodID cephfileextent_ctor_fid;
+
+/*
+ * Exception throwing helper. Adapted from Apache Hadoop header
+ * org_apache_hadoop.h by adding the do {} while (0) construct.
+ */
+#define THROW(env, exception_name, message) \
+ do { \
+ jclass ecls = env->FindClass(exception_name); \
+ if (ecls) { \
+ int ret = env->ThrowNew(ecls, message); \
+ if (ret < 0) { \
+ printf("(CephFS) Fatal Error\n"); \
+ } \
+ env->DeleteLocalRef(ecls); \
+ } \
+ } while (0)
+
+
+static void cephThrowNullArg(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/lang/NullPointerException", msg);
+}
+
+static void cephThrowOutOfMemory(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/lang/OutOfMemoryError", msg);
+}
+
+static void cephThrowInternal(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/lang/InternalError", msg);
+}
+
+static void cephThrowIndexBounds(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/lang/IndexOutOfBoundsException", msg);
+}
+
+static void cephThrowIllegalArg(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/lang/IllegalArgumentException", msg);
+}
+
+static void cephThrowFNF(JNIEnv *env, const char *msg)
+{
+ THROW(env, "java/io/FileNotFoundException", msg);
+}
+
+static void cephThrowFileExists(JNIEnv *env, const char *msg)
+{
+ THROW(env, CEPH_FILEEXISTS_CP, msg);
+}
+
+static void cephThrowNotDir(JNIEnv *env, const char *msg)
+{
+ THROW(env, CEPH_NOTDIR_CP, msg);
+}
+
+static void handle_error(JNIEnv *env, int rc)
+{
+ switch (rc) {
+ case -ENOENT:
+ cephThrowFNF(env, "");
+ return;
+ case -EEXIST:
+ cephThrowFileExists(env, "");
+ return;
+ case -ENOTDIR:
+ cephThrowNotDir(env, "");
+ return;
+ default:
+ break;
+ }
+
+ THROW(env, "java/io/IOException", strerror(-rc));
+}
+
+#define CHECK_ARG_NULL(v, m, r) do { \
+ if (!(v)) { \
+ cephThrowNullArg(env, (m)); \
+ return (r); \
+ } } while (0)
+
+#define CHECK_ARG_BOUNDS(c, m, r) do { \
+ if ((c)) { \
+ cephThrowIndexBounds(env, (m)); \
+ return (r); \
+ } } while (0)
+
+#define CHECK_MOUNTED(_c, _r) do { \
+ if (!ceph_is_mounted((_c))) { \
+ THROW(env, CEPH_NOTMOUNTED_CP, "not mounted"); \
+ return (_r); \
+ } } while (0)
+
+/*
+ * Cast a jlong to ceph_mount_info. Each JNI function is expected to pass in
+ * the class instance variable instance_ptr. Passing a parameter is faster
+ * than reaching back into Java via an upcall to retrieve this pointer.
+ */
+static inline struct ceph_mount_info *get_ceph_mount(jlong j_mntp)
+{
+ return (struct ceph_mount_info *)j_mntp;
+}
+
+/*
+ * Setup cached field IDs
+ */
+static void setup_field_ids(JNIEnv *env, jclass clz)
+{
+ jclass cephstat_cls;
+ jclass cephstatvfs_cls;
+ jclass tmp_cephfileextent_cls;
+
+/*
+ * Get a fieldID from a class with a specific type
+ *
+ * clz: jclass
+ * field: field in clz
+ * type: integer, long, etc..
+ *
+ * This macro assumes some naming convention that is used
+ * only in this file:
+ *
+ * GETFID(cephstat, mode, I) gets translated into
+ * cephstat_mode_fid = env->GetFieldID(cephstat_cls, "mode", "I");
+ */
+#define GETFID(clz, field, type) do { \
+ clz ## _ ## field ## _fid = env->GetFieldID(clz ## _cls, #field, #type); \
+ if ( ! clz ## _ ## field ## _fid ) \
+ return; \
+ } while (0)
+
+ /* Cache CephStat fields */
+
+ cephstat_cls = env->FindClass(CEPH_STAT_CP);
+ if (!cephstat_cls)
+ return;
+
+ GETFID(cephstat, mode, I);
+ GETFID(cephstat, uid, I);
+ GETFID(cephstat, gid, I);
+ GETFID(cephstat, size, J);
+ GETFID(cephstat, blksize, J);
+ GETFID(cephstat, blocks, J);
+ GETFID(cephstat, a_time, J);
+ GETFID(cephstat, m_time, J);
+ GETFID(cephstat, is_file, Z);
+ GETFID(cephstat, is_directory, Z);
+ GETFID(cephstat, is_symlink, Z);
+
+ /* Cache CephStatVFS fields */
+
+ cephstatvfs_cls = env->FindClass(CEPH_STAT_VFS_CP);
+ if (!cephstatvfs_cls)
+ return;
+
+ GETFID(cephstatvfs, bsize, J);
+ GETFID(cephstatvfs, frsize, J);
+ GETFID(cephstatvfs, blocks, J);
+ GETFID(cephstatvfs, bavail, J);
+ GETFID(cephstatvfs, files, J);
+ GETFID(cephstatvfs, fsid, J);
+ GETFID(cephstatvfs, namemax, J);
+
+ /* Cache CephFileExtent fields */
+
+ tmp_cephfileextent_cls = env->FindClass(CEPH_FILE_EXTENT_CP);
+ if (!tmp_cephfileextent_cls)
+ return;
+
+ cephfileextent_cls = (jclass)env->NewGlobalRef(tmp_cephfileextent_cls);
+ env->DeleteLocalRef(tmp_cephfileextent_cls);
+
+ cephfileextent_ctor_fid = env->GetMethodID(cephfileextent_cls, "<init>", "(JJ[I)V");
+ if (!cephfileextent_ctor_fid)
+ return;
+
+ JniConstants::init(env);
+
+#undef GETFID
+
+ cephmount_instance_ptr_fid = env->GetFieldID(clz, "instance_ptr", "J");
+}
+
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_initialize
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_com_ceph_fs_CephMount_native_1initialize
+ (JNIEnv *env, jclass clz)
+{
+ setup_field_ids(env, clz);
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_create
+ * Signature: (Lcom/ceph/fs/CephMount;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1create
+ (JNIEnv *env, jclass clz, jobject j_cephmount, jstring j_id)
+{
+ struct ceph_mount_info *cmount;
+ const char *c_id = NULL;
+ int ret;
+
+ CHECK_ARG_NULL(j_cephmount, "@mount is null", -1);
+
+ if (j_id) {
+ c_id = env->GetStringUTFChars(j_id, NULL);
+ if (!c_id) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+ }
+
+ ret = ceph_create(&cmount, c_id);
+
+ if (c_id)
+ env->ReleaseStringUTFChars(j_id, c_id);
+
+ if (ret) {
+ THROW(env, "java/lang/RuntimeException", "failed to create Ceph mount object");
+ return ret;
+ }
+
+ env->SetLongField(j_cephmount, cephmount_instance_ptr_fid, (long)cmount);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_mount
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mount
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_root)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_root = NULL;
+ int ret;
+
+ /*
+ * Toss a message up if we are already mounted.
+ */
+ if (ceph_is_mounted(cmount)) {
+ THROW(env, CEPH_ALREADYMOUNTED_CP, "");
+ return -1;
+ }
+
+ if (j_root) {
+ c_root = env->GetStringUTFChars(j_root, NULL);
+ if (!c_root) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+ }
+
+ ldout(cct, 10) << "jni: ceph_mount: " << (c_root ? c_root : "<NULL>") << dendl;
+
+ ret = ceph_mount(cmount, c_root);
+
+ ldout(cct, 10) << "jni: ceph_mount: exit ret " << ret << dendl;
+
+ if (c_root)
+ env->ReleaseStringUTFChars(j_root, c_root);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_unmount
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unmount
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ ldout(cct, 10) << "jni: ceph_unmount enter" << dendl;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ret = ceph_unmount(cmount);
+
+ ldout(cct, 10) << "jni: ceph_unmount exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_release
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1release
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ ldout(cct, 10) << "jni: ceph_release called" << dendl;
+
+ ret = ceph_release(cmount);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_conf_set
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1set
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt, jstring j_val)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_opt, *c_val;
+ int ret;
+
+ CHECK_ARG_NULL(j_opt, "@option is null", -1);
+ CHECK_ARG_NULL(j_val, "@value is null", -1);
+
+ c_opt = env->GetStringUTFChars(j_opt, NULL);
+ if (!c_opt) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ c_val = env->GetStringUTFChars(j_val, NULL);
+ if (!c_val) {
+ env->ReleaseStringUTFChars(j_opt, c_opt);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: conf_set: opt " << c_opt << " val " << c_val << dendl;
+
+ ret = ceph_conf_set(cmount, c_opt, c_val);
+
+ ldout(cct, 10) << "jni: conf_set: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_opt, c_opt);
+ env->ReleaseStringUTFChars(j_val, c_val);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_conf_get
+ * Signature: (JLjava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1get
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_opt;
+ jstring value = NULL;
+ int ret, buflen;
+ char *buf;
+
+ CHECK_ARG_NULL(j_opt, "@option is null", NULL);
+
+ c_opt = env->GetStringUTFChars(j_opt, NULL);
+ if (!c_opt) {
+ cephThrowInternal(env, "failed to pin memory");
+ return NULL;
+ }
+
+ buflen = 128;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+
+ while (1) {
+ memset(buf, 0, sizeof(char)*buflen);
+ ldout(cct, 10) << "jni: conf_get: opt " << c_opt << " len " << buflen << dendl;
+ ret = ceph_conf_get(cmount, c_opt, buf, buflen);
+ if (ret == -ENAMETOOLONG) {
+ buflen *= 2;
+ delete [] buf;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+ } else
+ break;
+ }
+
+ ldout(cct, 10) << "jni: conf_get: ret " << ret << dendl;
+
+ if (ret == 0)
+ value = env->NewStringUTF(buf);
+ else if (ret != -ENOENT)
+ handle_error(env, ret);
+
+ delete [] buf;
+
+out:
+ env->ReleaseStringUTFChars(j_opt, c_opt);
+ return value;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_conf_read_file
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1read_1file
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: conf_read_file: path " << c_path << dendl;
+
+ ret = ceph_conf_read_file(cmount, c_path);
+
+ ldout(cct, 10) << "jni: conf_read_file: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_statfs
+ * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStatVFS;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1statfs
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstatvfs)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ struct statvfs st;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_cephstatvfs, "@stat is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: statfs: path " << c_path << dendl;
+
+ ret = ceph_statfs(cmount, c_path, &st);
+
+ ldout(cct, 10) << "jni: statfs: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret) {
+ handle_error(env, ret);
+ return ret;
+ }
+
+ env->SetLongField(j_cephstatvfs, cephstatvfs_bsize_fid, st.f_bsize);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_frsize_fid, st.f_frsize);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_blocks_fid, st.f_blocks);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_bavail_fid, st.f_bavail);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_files_fid, st.f_files);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_fsid_fid, st.f_fsid);
+ env->SetLongField(j_cephstatvfs, cephstatvfs_namemax_fid, st.f_namemax);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_getcwd
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getcwd
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_cwd;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: getcwd: enter" << dendl;
+
+ c_cwd = ceph_getcwd(cmount);
+ if (!c_cwd) {
+ cephThrowOutOfMemory(env, "ceph_getcwd");
+ return NULL;
+ }
+
+ ldout(cct, 10) << "jni: getcwd: exit ret " << c_cwd << dendl;
+
+ return env->NewStringUTF(c_cwd);
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_chdir
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chdir
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: chdir: path " << c_path << dendl;
+
+ ret = ceph_chdir(cmount, c_path);
+
+ ldout(cct, 10) << "jni: chdir: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_listdir
+ * Signature: (JLjava/lang/String;)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listdir
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ struct ceph_dir_result *dirp;
+ list<string>::iterator it;
+ list<string> contents;
+ const char *c_path;
+ jobjectArray dirlist;
+ string *ent;
+ int ret, buflen, bufpos, i;
+ jstring name;
+ char *buf;
+
+ CHECK_ARG_NULL(j_path, "@path is null", NULL);
+ CHECK_MOUNTED(cmount, NULL);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return NULL;
+ }
+
+ ldout(cct, 10) << "jni: listdir: opendir: path " << c_path << dendl;
+
+ /* ret < 0 also includes -ENOTDIR which should return NULL */
+ ret = ceph_opendir(cmount, c_path, &dirp);
+ if (ret) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ handle_error(env, ret);
+ return NULL;
+ }
+
+ ldout(cct, 10) << "jni: listdir: opendir: exit ret " << ret << dendl;
+
+ /* buffer for ceph_getdnames() results */
+ buflen = 256;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+
+ while (1) {
+ ldout(cct, 10) << "jni: listdir: getdnames: enter" << dendl;
+ ret = ceph_getdnames(cmount, dirp, buf, buflen);
+ if (ret == -ERANGE) {
+ delete [] buf;
+ buflen *= 2;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+ continue;
+ }
+
+ ldout(cct, 10) << "jni: listdir: getdnames: exit ret " << ret << dendl;
+
+ if (ret <= 0)
+ break;
+
+ /* got at least one name */
+ bufpos = 0;
+ while (bufpos < ret) {
+ ent = new (std::nothrow) string(buf + bufpos);
+ if (!ent) {
+ delete [] buf;
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+
+ /* filter out dot files: xref: java.io.File::list() */
+ if (ent->compare(".") && ent->compare("..")) {
+ contents.push_back(*ent);
+ ldout(cct, 20) << "jni: listdir: take path " << *ent << dendl;
+ }
+
+ bufpos += ent->size() + 1;
+ delete ent;
+ }
+ }
+
+ delete [] buf;
+
+ if (ret < 0) {
+ handle_error(env, ret);
+ goto out;
+ }
+
+ /* directory list */
+ dirlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
+ if (!dirlist)
+ goto out;
+
+ /*
+ * Fill directory listing array.
+ *
+ * FIXME: how should a partially filled array be cleaned-up properly?
+ */
+ for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
+ name = env->NewStringUTF(it->c_str());
+ if (!name)
+ goto out;
+ env->SetObjectArrayElement(dirlist, i++, name);
+ if (env->ExceptionOccurred())
+ goto out;
+ env->DeleteLocalRef(name);
+ }
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ ceph_closedir(cmount, dirp);
+
+ return dirlist;
+
+out:
+ env->ReleaseStringUTFChars(j_path, c_path);
+ ceph_closedir(cmount, dirp);
+ return NULL;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_link
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1link
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_oldpath, *c_newpath;
+ int ret;
+
+ CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1);
+ CHECK_ARG_NULL(j_newpath, "@newpath is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_oldpath = env->GetStringUTFChars(j_oldpath, NULL);
+ if (!c_oldpath) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ c_newpath = env->GetStringUTFChars(j_newpath, NULL);
+ if (!c_newpath) {
+ env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: link: oldpath " << c_oldpath <<
+ " newpath " << c_newpath << dendl;
+
+ ret = ceph_link(cmount, c_oldpath, c_newpath);
+
+ ldout(cct, 10) << "jni: link: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
+ env->ReleaseStringUTFChars(j_newpath, c_newpath);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_unlink
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unlink
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: unlink: path " << c_path << dendl;
+
+ ret = ceph_unlink(cmount, c_path);
+
+ ldout(cct, 10) << "jni: unlink: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_rename
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rename
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_from, jstring j_to)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_from, *c_to;
+ int ret;
+
+ CHECK_ARG_NULL(j_from, "@from is null", -1);
+ CHECK_ARG_NULL(j_to, "@to is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_from = env->GetStringUTFChars(j_from, NULL);
+ if (!c_from) {
+ cephThrowInternal(env, "Failed to pin memory!");
+ return -1;
+ }
+
+ c_to = env->GetStringUTFChars(j_to, NULL);
+ if (!c_to) {
+ env->ReleaseStringUTFChars(j_from, c_from);
+ cephThrowInternal(env, "Failed to pin memory.");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: rename: from " << c_from << " to " << c_to << dendl;
+
+ ret = ceph_rename(cmount, c_from, c_to);
+
+ ldout(cct, 10) << "jni: rename: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_from, c_from);
+ env->ReleaseStringUTFChars(j_to, c_to);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_mkdir
+ * Signature: (JLjava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdir
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: mkdir: path " << c_path << " mode " << (int)j_mode << dendl;
+
+ ret = ceph_mkdir(cmount, c_path, (int)j_mode);
+
+ ldout(cct, 10) << "jni: mkdir: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_mkdirs
+ * Signature: (JLjava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdirs
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: mkdirs: path " << c_path << " mode " << (int)j_mode << dendl;
+
+ ret = ceph_mkdirs(cmount, c_path, (int)j_mode);
+
+ ldout(cct, 10) << "jni: mkdirs: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_rmdir
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rmdir
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: rmdir: path " << c_path << dendl;
+
+ ret = ceph_rmdir(cmount, c_path);
+
+ ldout(cct, 10) << "jni: rmdir: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_readlink
+ * Signature: (JLjava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1readlink
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ char *linkname;
+ struct ceph_statx stx;
+ jstring j_linkname;
+
+ CHECK_ARG_NULL(j_path, "@path is null", NULL);
+ CHECK_MOUNTED(cmount, NULL);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "failed to pin memory");
+ return NULL;
+ }
+
+ for (;;) {
+ ldout(cct, 10) << "jni: readlink: lstatx " << c_path << dendl;
+ int ret = ceph_statx(cmount, c_path, &stx, CEPH_STATX_SIZE,
+ AT_SYMLINK_NOFOLLOW);
+ ldout(cct, 10) << "jni: readlink: lstat exit ret " << ret << dendl;
+ if (ret) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ handle_error(env, ret);
+ return NULL;
+ }
+
+ linkname = new (std::nothrow) char[stx.stx_size + 1];
+ if (!linkname) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowOutOfMemory(env, "head allocation failed");
+ return NULL;
+ }
+
+ ldout(cct, 10) << "jni: readlink: size " << stx.stx_size << " path " << c_path << dendl;
+
+ ret = ceph_readlink(cmount, c_path, linkname, stx.stx_size + 1);
+
+ ldout(cct, 10) << "jni: readlink: exit ret " << ret << dendl;
+
+ if (ret < 0) {
+ delete [] linkname;
+ env->ReleaseStringUTFChars(j_path, c_path);
+ handle_error(env, ret);
+ return NULL;
+ }
+
+ /* re-stat and try again */
+ if (ret > (int)stx.stx_size) {
+ delete [] linkname;
+ continue;
+ }
+
+ linkname[ret] = '\0';
+ break;
+ }
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ j_linkname = env->NewStringUTF(linkname);
+ delete [] linkname;
+
+ return j_linkname;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_symlink
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1symlink
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_oldpath, *c_newpath;
+ int ret;
+
+ CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1);
+ CHECK_ARG_NULL(j_newpath, "@newpath is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_oldpath = env->GetStringUTFChars(j_oldpath, NULL);
+ if (!c_oldpath) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ c_newpath = env->GetStringUTFChars(j_newpath, NULL);
+ if (!c_newpath) {
+ env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: symlink: oldpath " << c_oldpath <<
+ " newpath " << c_newpath << dendl;
+
+ ret = ceph_symlink(cmount, c_oldpath, c_newpath);
+
+ ldout(cct, 10) << "jni: symlink: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
+ env->ReleaseStringUTFChars(j_newpath, c_newpath);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+#define CEPH_J_CEPHSTAT_MASK (CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_SIZE|CEPH_STATX_BLOCKS|CEPH_STATX_MTIME|CEPH_STATX_ATIME)
+
+static void fill_cephstat(JNIEnv *env, jobject j_cephstat, struct ceph_statx *stx)
+{
+ env->SetIntField(j_cephstat, cephstat_mode_fid, stx->stx_mode);
+ env->SetIntField(j_cephstat, cephstat_uid_fid, stx->stx_uid);
+ env->SetIntField(j_cephstat, cephstat_gid_fid, stx->stx_gid);
+ env->SetLongField(j_cephstat, cephstat_size_fid, stx->stx_size);
+ env->SetLongField(j_cephstat, cephstat_blksize_fid, stx->stx_blksize);
+ env->SetLongField(j_cephstat, cephstat_blocks_fid, stx->stx_blocks);
+
+ long long time = stx->stx_mtime.tv_sec;
+ time *= 1000;
+ time += stx->stx_mtime.tv_nsec / 1000000;
+ env->SetLongField(j_cephstat, cephstat_m_time_fid, time);
+
+ time = stx->stx_atime.tv_sec;
+ time *= 1000;
+ time += stx->stx_atime.tv_nsec / 1000000;
+ env->SetLongField(j_cephstat, cephstat_a_time_fid, time);
+
+ env->SetBooleanField(j_cephstat, cephstat_is_file_fid,
+ S_ISREG(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
+
+ env->SetBooleanField(j_cephstat, cephstat_is_directory_fid,
+ S_ISDIR(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
+
+ env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid,
+ S_ISLNK(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_lstat
+ * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lstat
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ struct ceph_statx stx;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: lstat: path " << c_path << dendl;
+
+ ret = ceph_statx(cmount, c_path, &stx, CEPH_J_CEPHSTAT_MASK, AT_SYMLINK_NOFOLLOW);
+
+ ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret) {
+ handle_error(env, ret);
+ return ret;
+ }
+
+ fill_cephstat(env, j_cephstat, &stx);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_stat
+ * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1stat
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ struct ceph_statx stx;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: stat: path " << c_path << dendl;
+
+ ret = ceph_statx(cmount, c_path, &stx, CEPH_J_CEPHSTAT_MASK, 0);
+
+ ldout(cct, 10) << "jni: stat exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret) {
+ handle_error(env, ret);
+ return ret;
+ }
+
+ fill_cephstat(env, j_cephstat, &stx);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_setattr
+ * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat, jint j_mask)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ struct ceph_statx stx;
+ int ret, mask = fixup_attr_mask(j_mask);
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ memset(&stx, 0, sizeof(stx));
+
+ stx.stx_mode = env->GetIntField(j_cephstat, cephstat_mode_fid);
+ stx.stx_uid = env->GetIntField(j_cephstat, cephstat_uid_fid);
+ stx.stx_gid = env->GetIntField(j_cephstat, cephstat_gid_fid);
+ long mtime_msec = env->GetLongField(j_cephstat, cephstat_m_time_fid);
+ long atime_msec = env->GetLongField(j_cephstat, cephstat_a_time_fid);
+ stx.stx_mtime.tv_sec = mtime_msec / 1000;
+ stx.stx_mtime.tv_nsec = (mtime_msec % 1000) * 1000000;
+ stx.stx_atime.tv_sec = atime_msec / 1000;
+ stx.stx_atime.tv_nsec = (atime_msec % 1000) * 1000000;
+
+ ldout(cct, 10) << "jni: setattr: path " << c_path << " mask " << mask << dendl;
+
+ ret = ceph_setattrx(cmount, c_path, &stx, mask, 0);
+
+ ldout(cct, 10) << "jni: setattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_chmod
+ * Signature: (JLjava/lang/String;I)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chmod
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: chmod: path " << c_path << " mode " << (int)j_mode << dendl;
+
+ ret = ceph_chmod(cmount, c_path, (int)j_mode);
+
+ ldout(cct, 10) << "jni: chmod: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_fchmod
+ * Signature: (JII)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fchmod
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jint j_mode)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: fchmod: fd " << (int)j_fd << " mode " << (int)j_mode << dendl;
+
+ ret = ceph_fchmod(cmount, (int)j_fd, (int)j_mode);
+
+ ldout(cct, 10) << "jni: fchmod: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_truncate
+ * Signature: (JLjava/lang/String;J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1truncate
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jlong j_size)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: truncate: path " << c_path << " size " << (loff_t)j_size << dendl;
+
+ ret = ceph_truncate(cmount, c_path, (loff_t)j_size);
+
+ ldout(cct, 10) << "jni: truncate: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_open
+ * Signature: (JLjava/lang/String;II)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ int ret, flags = fixup_open_flags(j_flags);
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: open: path " << c_path << " flags " << flags
+ << " mode " << (int)j_mode << dendl;
+
+ ret = ceph_open(cmount, c_path, flags, (int)j_mode);
+
+ ldout(cct, 10) << "jni: open: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_open_layout
+ * Signature: (JLjava/lang/String;IIIIILjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open_1layout
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode,
+ jint stripe_unit, jint stripe_count, jint object_size, jstring j_data_pool)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path, *c_data_pool = NULL;
+ int ret, flags = fixup_open_flags(j_flags);
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ if (j_data_pool) {
+ c_data_pool = env->GetStringUTFChars(j_data_pool, NULL);
+ if (!c_data_pool) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+ }
+
+ ldout(cct, 10) << "jni: open_layout: path " << c_path << " flags " << flags
+ << " mode " << (int)j_mode << " stripe_unit " << stripe_unit
+ << " stripe_count " << stripe_count << " object_size " << object_size
+ << " data_pool " << (c_data_pool ? c_data_pool : "<NULL>") << dendl;
+
+ ret = ceph_open_layout(cmount, c_path, flags, (int)j_mode,
+ (int)stripe_unit, (int)stripe_count, (int)object_size, c_data_pool);
+
+ ldout(cct, 10) << "jni: open_layout: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ if (j_data_pool)
+ env->ReleaseStringUTFChars(j_data_pool, c_data_pool);
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_close
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1close
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: close: fd " << (int)j_fd << dendl;
+
+ ret = ceph_close(cmount, (int)j_fd);
+
+ ldout(cct, 10) << "jni: close: ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_lseek
+ * Signature: (JIJI)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lseek
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_offset, jint j_whence)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int whence;
+ jlong ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ switch (j_whence) {
+ case JAVA_SEEK_SET:
+ whence = SEEK_SET;
+ break;
+ case JAVA_SEEK_CUR:
+ whence = SEEK_CUR;
+ break;
+ case JAVA_SEEK_END:
+ whence = SEEK_END;
+ break;
+ default:
+ cephThrowIllegalArg(env, "Unknown whence value");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: lseek: fd " << (int)j_fd << " offset "
+ << (long)j_offset << " whence " << whence << dendl;
+
+ ret = ceph_lseek(cmount, (int)j_fd, (long)j_offset, whence);
+
+ ldout(cct, 10) << "jni: lseek: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_read
+ * Signature: (JI[BJJ)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1read
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jsize buf_size;
+ jbyte *c_buf;
+ long ret;
+
+ CHECK_ARG_NULL(j_buf, "@buf is null", -1);
+ CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ buf_size = env->GetArrayLength(j_buf);
+ CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: read: fd " << (int)j_fd << " len " << (long)j_size <<
+ " offset " << (long)j_offset << dendl;
+
+ ret = ceph_read(cmount, (int)j_fd, (char*)c_buf, (long)j_size, (long)j_offset);
+
+ ldout(cct, 10) << "jni: read: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, (int)ret);
+ else
+ env->ReleaseByteArrayElements(j_buf, c_buf, 0);
+
+ return (jlong)ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_write
+ * Signature: (JI[BJJ)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1write
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jsize buf_size;
+ jbyte *c_buf;
+ long ret;
+
+ CHECK_ARG_NULL(j_buf, "@buf is null", -1);
+ CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ buf_size = env->GetArrayLength(j_buf);
+ CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: write: fd " << (int)j_fd << " len " << (long)j_size <<
+ " offset " << (long)j_offset << dendl;
+
+ ret = ceph_write(cmount, (int)j_fd, (char*)c_buf, (long)j_size, (long)j_offset);
+
+ ldout(cct, 10) << "jni: write: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, (int)ret);
+ else
+ env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
+
+ return ret;
+}
+
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_ftruncate
+ * Signature: (JIJ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1ftruncate
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_size)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: ftruncate: fd " << (int)j_fd <<
+ " size " << (loff_t)j_size << dendl;
+
+ ret = ceph_ftruncate(cmount, (int)j_fd, (loff_t)j_size);
+
+ ldout(cct, 10) << "jni: ftruncate: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_fsync
+ * Signature: (JIZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fsync
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jboolean j_dataonly)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ ldout(cct, 10) << "jni: fsync: fd " << (int)j_fd <<
+ " dataonly " << (j_dataonly ? 1 : 0) << dendl;
+
+ ret = ceph_fsync(cmount, (int)j_fd, j_dataonly ? 1 : 0);
+
+ ldout(cct, 10) << "jni: fsync: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_flock
+ * Signature: (JIZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1flock
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jint j_operation, jlong j_owner)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ ldout(cct, 10) << "jni: flock: fd " << (int)j_fd <<
+ " operation " << j_operation << " owner " << j_owner << dendl;
+
+ int operation = 0;
+
+#define MAP_FLOCK_FLAG(JNI_MASK, NATIVE_MASK) do { \
+ if ((j_operation & JNI_MASK) != 0) { \
+ operation |= NATIVE_MASK; \
+ j_operation &= ~JNI_MASK; \
+ } \
+ } while(0)
+ MAP_FLOCK_FLAG(JAVA_LOCK_SH, LOCK_SH);
+ MAP_FLOCK_FLAG(JAVA_LOCK_EX, LOCK_EX);
+ MAP_FLOCK_FLAG(JAVA_LOCK_NB, LOCK_NB);
+ MAP_FLOCK_FLAG(JAVA_LOCK_UN, LOCK_UN);
+ if (j_operation != 0) {
+ cephThrowIllegalArg(env, "flock flags");
+ return -EINVAL;
+ }
+#undef MAP_FLOCK_FLAG
+
+ ret = ceph_flock(cmount, (int)j_fd, operation, (uint64_t) j_owner);
+
+ ldout(cct, 10) << "jni: flock: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_fstat
+ * Signature: (JILcom/ceph/fs/CephStat;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fstat
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jobject j_cephstat)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ struct ceph_statx stx;
+ int ret;
+
+ CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: fstat: fd " << (int)j_fd << dendl;
+
+ ret = ceph_fstatx(cmount, (int)j_fd, &stx, CEPH_J_CEPHSTAT_MASK, 0);
+
+ ldout(cct, 10) << "jni: fstat exit ret " << ret << dendl;
+
+ if (ret) {
+ handle_error(env, ret);
+ return ret;
+ }
+
+ fill_cephstat(env, j_cephstat, &stx);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_sync_fs
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1sync_1fs
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ ldout(cct, 10) << "jni: sync_fs: enter" << dendl;
+
+ ret = ceph_sync_fs(cmount);
+
+ ldout(cct, 10) << "jni: sync_fs: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_getxattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;[B)J
+ */
+JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ jsize buf_size;
+ jbyte *c_buf = NULL; /* please gcc with goto */
+ long ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ /* just lookup the size if buf is null */
+ if (!j_buf) {
+ buf_size = 0;
+ goto do_getxattr;
+ }
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ buf_size = env->GetArrayLength(j_buf);
+
+do_getxattr:
+
+ ldout(cct, 10) << "jni: getxattr: path " << c_path << " name " << c_name <<
+ " len " << buf_size << dendl;
+
+ ret = ceph_getxattr(cmount, c_path, c_name, c_buf, buf_size);
+ if (ret == -ERANGE)
+ ret = ceph_getxattr(cmount, c_path, c_name, c_buf, 0);
+
+ ldout(cct, 10) << "jni: getxattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ if (j_buf)
+ env->ReleaseByteArrayElements(j_buf, c_buf, 0);
+
+ if (ret < 0)
+ handle_error(env, (int)ret);
+
+ return (jlong)ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_lgetxattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;[B)I
+ */
+JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lgetxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ jsize buf_size;
+ jbyte *c_buf = NULL; /* please gcc with goto */
+ long ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ /* just lookup the size if buf is null */
+ if (!j_buf) {
+ buf_size = 0;
+ goto do_lgetxattr;
+ }
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ buf_size = env->GetArrayLength(j_buf);
+
+do_lgetxattr:
+
+ ldout(cct, 10) << "jni: lgetxattr: path " << c_path << " name " << c_name <<
+ " len " << buf_size << dendl;
+
+ ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, buf_size);
+ if (ret == -ERANGE)
+ ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, 0);
+
+ ldout(cct, 10) << "jni: lgetxattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ if (j_buf)
+ env->ReleaseByteArrayElements(j_buf, c_buf, 0);
+
+ if (ret < 0)
+ handle_error(env, (int)ret);
+
+ return (jlong)ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_listxattr
+ * Signature: (JLjava/lang/String;)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jobjectArray xattrlist;
+ const char *c_path;
+ string *ent;
+ jstring name;
+ list<string>::iterator it;
+ list<string> contents;
+ int ret, buflen, bufpos, i;
+ char *buf;
+
+ CHECK_ARG_NULL(j_path, "@path is null", NULL);
+ CHECK_MOUNTED(cmount, NULL);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return NULL;
+ }
+
+ buflen = 1024;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+
+ while (1) {
+ ldout(cct, 10) << "jni: listxattr: path " << c_path << " len " << buflen << dendl;
+ ret = ceph_listxattr(cmount, c_path, buf, buflen);
+ if (ret == -ERANGE) {
+ delete [] buf;
+ buflen *= 2;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+ continue;
+ }
+ break;
+ }
+
+ ldout(cct, 10) << "jni: listxattr: ret " << ret << dendl;
+
+ if (ret < 0) {
+ delete [] buf;
+ handle_error(env, ret);
+ goto out;
+ }
+
+ bufpos = 0;
+ while (bufpos < ret) {
+ ent = new (std::nothrow) string(buf + bufpos);
+ if (!ent) {
+ delete [] buf;
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+ contents.push_back(*ent);
+ bufpos += ent->size() + 1;
+ delete ent;
+ }
+
+ delete [] buf;
+
+ xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
+ if (!xattrlist)
+ goto out;
+
+ for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
+ name = env->NewStringUTF(it->c_str());
+ if (!name)
+ goto out;
+ env->SetObjectArrayElement(xattrlist, i++, name);
+ if (env->ExceptionOccurred())
+ goto out;
+ env->DeleteLocalRef(name);
+ }
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ return xattrlist;
+
+out:
+ env->ReleaseStringUTFChars(j_path, c_path);
+ return NULL;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_llistxattr
+ * Signature: (JLjava/lang/String;)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1llistxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jobjectArray xattrlist;
+ const char *c_path;
+ string *ent;
+ jstring name;
+ list<string>::iterator it;
+ list<string> contents;
+ int ret, buflen, bufpos, i;
+ char *buf;
+
+ CHECK_ARG_NULL(j_path, "@path is null", NULL);
+ CHECK_MOUNTED(cmount, NULL);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return NULL;
+ }
+
+ buflen = 1024;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+
+ while (1) {
+ ldout(cct, 10) << "jni: llistxattr: path " << c_path << " len " << buflen << dendl;
+ ret = ceph_llistxattr(cmount, c_path, buf, buflen);
+ if (ret == -ERANGE) {
+ delete [] buf;
+ buflen *= 2;
+ buf = new (std::nothrow) char[buflen];
+ if (!buf) {
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+ continue;
+ }
+ break;
+ }
+
+ ldout(cct, 10) << "jni: llistxattr: ret " << ret << dendl;
+
+ if (ret < 0) {
+ delete [] buf;
+ handle_error(env, ret);
+ goto out;
+ }
+
+ bufpos = 0;
+ while (bufpos < ret) {
+ ent = new (std::nothrow) string(buf + bufpos);
+ if (!ent) {
+ delete [] buf;
+ cephThrowOutOfMemory(env, "heap allocation failed");
+ goto out;
+ }
+ contents.push_back(*ent);
+ bufpos += ent->size() + 1;
+ delete ent;
+ }
+
+ delete [] buf;
+
+ xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
+ if (!xattrlist)
+ goto out;
+
+ for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
+ name = env->NewStringUTF(it->c_str());
+ if (!name)
+ goto out;
+ env->SetObjectArrayElement(xattrlist, i++, name);
+ if (env->ExceptionOccurred())
+ goto out;
+ env->DeleteLocalRef(name);
+ }
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ return xattrlist;
+
+out:
+ env->ReleaseStringUTFChars(j_path, c_path);
+ return NULL;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_removexattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1removexattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: removexattr: path " << c_path << " name " << c_name << dendl;
+
+ ret = ceph_removexattr(cmount, c_path, c_name);
+
+ ldout(cct, 10) << "jni: removexattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_lremovexattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lremovexattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ int ret;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: lremovexattr: path " << c_path << " name " << c_name << dendl;
+
+ ret = ceph_lremovexattr(cmount, c_path, c_name);
+
+ ldout(cct, 10) << "jni: lremovexattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_setxattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name,
+ jbyteArray j_buf, jlong j_size, jint j_flags)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ jsize buf_size;
+ jbyte *c_buf;
+ int ret, flags;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_ARG_NULL(j_buf, "@buf is null", -1);
+ CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ buf_size = env->GetArrayLength(j_buf);
+ CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ switch (j_flags) {
+ case JAVA_XATTR_CREATE:
+ flags = CEPH_XATTR_CREATE;
+ break;
+ case JAVA_XATTR_REPLACE:
+ flags = CEPH_XATTR_REPLACE;
+ break;
+ case JAVA_XATTR_NONE:
+ flags = 0;
+ break;
+ default:
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
+ cephThrowIllegalArg(env, "setxattr flag");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: setxattr: path " << c_path << " name " << c_name
+ << " len " << j_size << " flags " << flags << dendl;
+
+ ret = ceph_setxattr(cmount, c_path, c_name, c_buf, j_size, flags);
+
+ ldout(cct, 10) << "jni: setxattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_lsetxattr
+ * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lsetxattr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name,
+ jbyteArray j_buf, jlong j_size, jint j_flags)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_path;
+ const char *c_name;
+ jsize buf_size;
+ jbyte *c_buf;
+ int ret, flags;
+
+ CHECK_ARG_NULL(j_path, "@path is null", -1);
+ CHECK_ARG_NULL(j_name, "@name is null", -1);
+ CHECK_ARG_NULL(j_buf, "@buf is null", -1);
+ CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
+ CHECK_MOUNTED(cmount, -1);
+
+ buf_size = env->GetArrayLength(j_buf);
+ CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
+
+ c_path = env->GetStringUTFChars(j_path, NULL);
+ if (!c_path) {
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_name = env->GetStringUTFChars(j_name, NULL);
+ if (!c_name) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ cephThrowInternal(env, "Failed to pin memory");
+ return -1;
+ }
+
+ c_buf = env->GetByteArrayElements(j_buf, NULL);
+ if (!c_buf) {
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ switch (j_flags) {
+ case JAVA_XATTR_CREATE:
+ flags = CEPH_XATTR_CREATE;
+ break;
+ case JAVA_XATTR_REPLACE:
+ flags = CEPH_XATTR_REPLACE;
+ break;
+ case JAVA_XATTR_NONE:
+ flags = 0;
+ break;
+ default:
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
+ cephThrowIllegalArg(env, "lsetxattr flag");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: lsetxattr: path " << c_path << " name " << c_name
+ << " len " << j_size << " flags " << flags << dendl;
+
+ ret = ceph_lsetxattr(cmount, c_path, c_name, c_buf, j_size, flags);
+
+ ldout(cct, 10) << "jni: lsetxattr: exit ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(j_path, c_path);
+ env->ReleaseStringUTFChars(j_name, c_name);
+ env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_file_stripe_unit
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1stripe_1unit
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: get_file_stripe_unit: fd " << (int)j_fd << dendl;
+
+ ret = ceph_get_file_stripe_unit(cmount, (int)j_fd);
+
+ ldout(cct, 10) << "jni: get_file_stripe_unit: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_file_replication
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1replication
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: get_file_replication: fd " << (int)j_fd << dendl;
+
+ ret = ceph_get_file_replication(cmount, (int)j_fd);
+
+ ldout(cct, 10) << "jni: get_file_replication: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_file_pool_name
+ * Signature: (JI)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1pool_1name
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jstring pool = NULL;
+ int ret, buflen = 0;
+ char *buf = NULL;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: get_file_pool_name: fd " << (int)j_fd << dendl;
+
+ for (;;) {
+ /* get pool name length (len==0) */
+ ret = ceph_get_file_pool_name(cmount, (int)j_fd, NULL, 0);
+ if (ret < 0)
+ break;
+
+ /* allocate buffer */
+ if (buf)
+ delete [] buf;
+ buflen = ret;
+ buf = new (std::nothrow) char[buflen+1]; /* +1 for '\0' */
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+ memset(buf, 0, (buflen+1)*sizeof(*buf));
+
+ /* handle zero-length pool name!? */
+ if (buflen == 0)
+ break;
+
+ /* fill buffer */
+ ret = ceph_get_file_pool_name(cmount, (int)j_fd, buf, buflen);
+ if (ret == -ERANGE) /* size changed! */
+ continue;
+ else
+ break;
+ }
+
+ ldout(cct, 10) << "jni: get_file_pool_name: ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+ else
+ pool = env->NewStringUTF(buf);
+
+out:
+ if (buf)
+ delete [] buf;
+
+ return pool;
+}
+
+/**
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_default_data_pool_name
+ * Signature: (J)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1default_1data_1pool_1name
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jstring pool = NULL;
+ int ret, buflen = 0;
+ char *buf = NULL;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: get_default_data_pool_name" << dendl;
+
+ ret = ceph_get_default_data_pool_name(cmount, NULL, 0);
+ if (ret < 0)
+ goto out;
+ buflen = ret;
+ buf = new (std::nothrow) char[buflen+1]; /* +1 for '\0' */
+ if (!buf) {
+ cephThrowOutOfMemory(env, "head allocation failed");
+ goto out;
+ }
+ memset(buf, 0, (buflen+1)*sizeof(*buf));
+ ret = ceph_get_default_data_pool_name(cmount, buf, buflen);
+
+ ldout(cct, 10) << "jni: get_default_data_pool_name: ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+ else
+ pool = env->NewStringUTF(buf);
+
+out:
+ if (buf)
+ delete [] buf;
+
+ return pool;
+}
+
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_localize_reads
+ * Signature: (JZ)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1localize_1reads
+ (JNIEnv *env, jclass clz, jlong j_mntp, jboolean j_on)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret, val = j_on ? 1 : 0;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: localize_reads: val " << val << dendl;
+
+ ret = ceph_localize_reads(cmount, val);
+
+ ldout(cct, 10) << "jni: localize_reads: exit ret " << ret << dendl;
+
+ if (ret)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_stripe_unit_granularity
+ * Signature: (J)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1stripe_1unit_1granularity
+ (JNIEnv *env, jclass clz, jlong j_mntp)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: get_stripe_unit_granularity" << dendl;
+
+ ret = ceph_get_stripe_unit_granularity(cmount);
+
+ ldout(cct, 10) << "jni: get_stripe_unit_granularity: exit ret " << ret << dendl;
+
+ if (ret < 0)
+ handle_error(env, ret);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_pool_id
+ * Signature: (JLjava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1id
+ (JNIEnv *env, jclass clz, jlong j_mntp, jstring jname)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ const char *c_name;
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+ CHECK_ARG_NULL(jname, "@name is null", -1);
+
+ c_name = env->GetStringUTFChars(jname, NULL);
+ if (!c_name) {
+ cephThrowInternal(env, "failed to pin memory");
+ return -1;
+ }
+
+ ldout(cct, 10) << "jni: get_pool_id: name " << c_name << dendl;
+
+ ret = ceph_get_pool_id(cmount, c_name);
+ if (ret < 0)
+ handle_error(env, ret);
+
+ ldout(cct, 10) << "jni: get_pool_id: ret " << ret << dendl;
+
+ env->ReleaseStringUTFChars(jname, c_name);
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_pool_replication
+ * Signature: (JI)I
+ */
+JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1replication
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint jpoolid)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ int ret;
+
+ CHECK_MOUNTED(cmount, -1);
+
+ ldout(cct, 10) << "jni: get_pool_replication: poolid " << jpoolid << dendl;
+
+ ret = ceph_get_pool_replication(cmount, jpoolid);
+ if (ret < 0)
+ handle_error(env, ret);
+
+ ldout(cct, 10) << "jni: get_pool_replication: ret " << ret << dendl;
+
+ return ret;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_file_extent_osds
+ * Signature: (JIJ)Lcom/ceph/fs/CephFileExtent;
+ */
+JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1extent_1osds
+ (JNIEnv *env, jclass clz, jlong mntp, jint fd, jlong off)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jobject extent = NULL;
+ int ret, nosds, *osds = NULL;
+ jintArray osd_array;
+ loff_t len;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: get_file_extent_osds: fd " << fd << " off " << off << dendl;
+
+ for (;;) {
+ /* get pg size */
+ ret = ceph_get_file_extent_osds(cmount, fd, off, NULL, NULL, 0);
+ if (ret < 0)
+ break;
+
+ /* alloc osd id array */
+ if (osds)
+ delete [] osds;
+ nosds = ret;
+ osds = new int[nosds];
+
+ /* get osd ids */
+ ret = ceph_get_file_extent_osds(cmount, fd, off, &len, osds, nosds);
+ if (ret == -ERANGE)
+ continue;
+ else
+ break;
+ }
+
+ ldout(cct, 10) << "jni: get_file_extent_osds: ret " << ret << dendl;
+
+ if (ret < 0) {
+ handle_error(env, ret);
+ goto out;
+ }
+
+ nosds = ret;
+
+ osd_array = env->NewIntArray(nosds);
+ if (!osd_array)
+ goto out;
+
+ env->SetIntArrayRegion(osd_array, 0, nosds, osds);
+ if (env->ExceptionOccurred())
+ goto out;
+
+ extent = env->NewObject(cephfileextent_cls, cephfileextent_ctor_fid, off, len, osd_array);
+ if (!extent)
+ goto out;
+
+out:
+ if (osds)
+ delete [] osds;
+
+ return extent;
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_osd_crush_location
+ * Signature: (JI)[Ljava/lang/String;
+ */
+JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1crush_1location
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint osdid)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ jobjectArray path = NULL;
+ vector<string> str_path;
+ int ret, bufpos, buflen = 0;
+ char *buf = NULL;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: osd loc: osd " << osdid << dendl;
+
+ for (;;) {
+ /* get length of the location path */
+ ret = ceph_get_osd_crush_location(cmount, osdid, NULL, 0);
+ if (ret < 0)
+ break;
+
+ /* alloc path buffer */
+ if (buf)
+ delete [] buf;
+ buflen = ret;
+ buf = new char[buflen+1];
+ memset(buf, 0, buflen*sizeof(*buf));
+
+ /* empty path */
+ if (buflen == 0)
+ break;
+
+ /* get the path */
+ ret = ceph_get_osd_crush_location(cmount, osdid, buf, buflen);
+ if (ret == -ERANGE)
+ continue;
+ else
+ break;
+ }
+
+ ldout(cct, 10) << "jni: osd loc: osd " << osdid << " ret " << ret << dendl;
+
+ if (ret < 0) {
+ handle_error(env, ret);
+ goto out;
+ }
+
+ bufpos = 0;
+ while (bufpos < ret) {
+ string type(buf + bufpos);
+ bufpos += type.size() + 1;
+ string name(buf + bufpos);
+ bufpos += name.size() + 1;
+ str_path.push_back(type);
+ str_path.push_back(name);
+ }
+
+ path = env->NewObjectArray(str_path.size(), env->FindClass("java/lang/String"), NULL);
+ if (!path)
+ goto out;
+
+ for (unsigned i = 0; i < str_path.size(); i++) {
+ jstring ent = env->NewStringUTF(str_path[i].c_str());
+ if (!ent)
+ goto out;
+ env->SetObjectArrayElement(path, i, ent);
+ if (env->ExceptionOccurred())
+ goto out;
+ env->DeleteLocalRef(ent);
+ }
+
+out:
+ if (buf)
+ delete [] buf;
+
+ return path;
+}
+
+/*
+ * sockaddrToInetAddress uses with the following license, and is adapted for
+ * use in this project by using Ceph JNI exception utilities.
+ *
+ * ----
+ *
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+jobject sockaddrToInetAddress(JNIEnv* env, const sockaddr_storage& ss, jint* port) {
+ // Convert IPv4-mapped IPv6 addresses to IPv4 addresses.
+ // The RI states "Java will never return an IPv4-mapped address".
+ const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
+ if (ss.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
+ // Copy the IPv6 address into the temporary sockaddr_storage.
+ sockaddr_storage tmp;
+ memset(&tmp, 0, sizeof(tmp));
+ memcpy(&tmp, &ss, sizeof(sockaddr_in6));
+ // Unmap it into an IPv4 address.
+ sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(tmp);
+ sin.sin_family = AF_INET;
+ sin.sin_port = sin6.sin6_port;
+ memcpy(&sin.sin_addr.s_addr, &sin6.sin6_addr.s6_addr[12], 4);
+ // Do the regular conversion using the unmapped address.
+ return sockaddrToInetAddress(env, tmp, port);
+ }
+
+ const void* rawAddress;
+ size_t addressLength;
+ int sin_port = 0;
+ int scope_id = 0;
+ if (ss.ss_family == AF_INET) {
+ const sockaddr_in& sin = reinterpret_cast<const sockaddr_in&>(ss);
+ rawAddress = &sin.sin_addr.s_addr;
+ addressLength = 4;
+ sin_port = ntohs(sin.sin_port);
+ } else if (ss.ss_family == AF_INET6) {
+ const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
+ rawAddress = &sin6.sin6_addr.s6_addr;
+ addressLength = 16;
+ sin_port = ntohs(sin6.sin6_port);
+ scope_id = sin6.sin6_scope_id;
+ } else if (ss.ss_family == AF_UNIX) {
+ const sockaddr_un& sun = reinterpret_cast<const sockaddr_un&>(ss);
+ rawAddress = &sun.sun_path;
+ addressLength = strlen(sun.sun_path);
+ } else {
+ // We can't throw SocketException. We aren't meant to see bad addresses, so seeing one
+ // really does imply an internal error.
+ //jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
+ // "sockaddrToInetAddress unsupported ss_family: %i", ss.ss_family);
+ cephThrowIllegalArg(env, "sockaddrToInetAddress unsupposed ss_family");
+ return NULL;
+ }
+ if (port != NULL) {
+ *port = sin_port;
+ }
+
+ ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(addressLength));
+ if (byteArray.get() == NULL) {
+ return NULL;
+ }
+ env->SetByteArrayRegion(byteArray.get(), 0, addressLength,
+ reinterpret_cast<jbyte*>(const_cast<void*>(rawAddress)));
+
+ if (ss.ss_family == AF_UNIX) {
+ // Note that we get here for AF_UNIX sockets on accept(2). The unix(7) man page claims
+ // that the peer's sun_path will contain the path, but in practice it doesn't, and the
+ // peer length is returned as 2 (meaning only the sun_family field was set).
+ //
+ // Ceph Note: this isn't supported. inetUnixAddress appears to just be
+ // something in Dalvik/Android stuff.
+ cephThrowInternal(env, "OSD address should never be a UNIX socket");
+ return NULL;
+ //static jmethodID ctor = env->GetMethodID(JniConstants::inetUnixAddressClass, "<init>", "([B)V");
+ //return env->NewObject(JniConstants::inetUnixAddressClass, ctor, byteArray.get());
+ }
+
+ if (addressLength == 4) {
+ static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inetAddressClass,
+ "getByAddress", "(Ljava/lang/String;[B)Ljava/net/InetAddress;");
+ if (getByAddressMethod == NULL) {
+ return NULL;
+ }
+ return env->CallStaticObjectMethod(JniConstants::inetAddressClass, getByAddressMethod,
+ NULL, byteArray.get());
+ } else if (addressLength == 16) {
+ static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inet6AddressClass,
+ "getByAddress", "(Ljava/lang/String;[BI)Ljava/net/Inet6Address;");
+ if (getByAddressMethod == NULL) {
+ return NULL;
+ }
+ return env->CallStaticObjectMethod(JniConstants::inet6AddressClass, getByAddressMethod,
+ NULL, byteArray.get(), scope_id);
+ } else {
+ abort();
+ return NULL;
+ }
+}
+
+/*
+ * Class: com_ceph_fs_CephMount
+ * Method: native_ceph_get_osd_addr
+ * Signature: (JI)Ljava/net/InetAddress;
+ */
+JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1addr
+ (JNIEnv *env, jclass clz, jlong j_mntp, jint osd)
+{
+ struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
+ CephContext *cct = ceph_get_mount_context(cmount);
+ struct sockaddr_storage addr;
+ int ret;
+
+ CHECK_MOUNTED(cmount, NULL);
+
+ ldout(cct, 10) << "jni: get_osd_addr: osd " << osd << dendl;
+
+ ret = ceph_get_osd_addr(cmount, osd, &addr);
+
+ ldout(cct, 10) << "jni: get_osd_addr: ret " << ret << dendl;
+
+ if (ret < 0) {
+ handle_error(env, ret);
+ return NULL;
+ }
+
+ return sockaddrToInetAddress(env, addr, NULL);
+}
diff --git a/src/java/test/com/ceph/fs/CephAllTests.java b/src/java/test/com/ceph/fs/CephAllTests.java
new file mode 100644
index 000000000..039ad6da3
--- /dev/null
+++ b/src/java/test/com/ceph/fs/CephAllTests.java
@@ -0,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.FileNotFoundException;
+import java.io.IOException;
+import java.util.UUID;
+import org.junit.*;
+import org.junit.runners.Suite;
+import org.junit.runner.RunWith;
+import static org.junit.Assert.*;
+
+
+@RunWith( Suite.class )
+@Suite.SuiteClasses( {
+ CephDoubleMountTest.class,
+ CephMountCreateTest.class,
+ CephMountTest.class,
+ CephUnmountedTest.class,
+})
+
+/**
+ * Every Java test class must be added to this list in order to be executed with 'ant test'
+ */
+public class CephAllTests{
+
+}
diff --git a/src/java/test/com/ceph/fs/CephDoubleMountTest.java b/src/java/test/com/ceph/fs/CephDoubleMountTest.java
new file mode 100644
index 000000000..62ca1cb89
--- /dev/null
+++ b/src/java/test/com/ceph/fs/CephDoubleMountTest.java
@@ -0,0 +1,45 @@
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.util.UUID;
+import org.junit.*;
+import static org.junit.Assert.*;
+
+
+public class CephDoubleMountTest {
+
+ @Test(expected=CephAlreadyMountedException.class)
+ public void test_double_mount() throws Exception {
+ CephMount mount = new CephMount("admin");
+ String conf_file = System.getProperty("CEPH_CONF_FILE");
+ if (conf_file != null)
+ mount.conf_read_file(conf_file);
+ mount.mount(null);
+ try {
+ mount.mount(null);
+ } finally {
+ mount.unmount();
+ }
+ }
+
+}
diff --git a/src/java/test/com/ceph/fs/CephMountCreateTest.java b/src/java/test/com/ceph/fs/CephMountCreateTest.java
new file mode 100644
index 000000000..fc2bafd60
--- /dev/null
+++ b/src/java/test/com/ceph/fs/CephMountCreateTest.java
@@ -0,0 +1,91 @@
+/*
+ * 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.FileNotFoundException;
+import org.junit.*;
+import java.util.UUID;
+import static org.junit.Assert.*;
+
+/*
+ * This tests the mount root dir functionality. It creates an empty
+ * directory in the real root, then it re-mounts the file system
+ * with the empty directory specified as the root. Assertions are
+ * that the "/" in the normal mount is non-empty, and that "/" is
+ * empty in the mount with the empty directory as the root.
+ */
+public class CephMountCreateTest {
+
+ private static String conf_file;
+
+ @BeforeClass
+ public static void class_setup() throws Exception {
+ conf_file = System.getProperty("CEPH_CONF_FILE");
+ }
+
+ private CephMount setupMount(String root) throws Exception {
+ CephMount mount = new CephMount("admin");
+ if (conf_file != null)
+ mount.conf_read_file(conf_file);
+ mount.conf_set("client_permissions", "0");
+ mount.mount(root);
+ return mount;
+ }
+
+ @Test
+ public void test_CephMountCreate() throws Exception {
+ CephMount mount;
+ boolean found;
+
+ String dir = "libcephfs_junit_" + UUID.randomUUID();
+
+ /* root dir has more than one dir */
+ mount = setupMount("/");
+
+ try {
+ mount.rmdir("/" + dir);
+ } catch (FileNotFoundException e) {}
+ mount.mkdirs("/" + dir, 777);
+ String[] subdirs = mount.listdir("/");
+ found = false;
+ for (String d : subdirs) {
+ if (d.compareTo(dir) == 0)
+ found = true;
+ }
+ assertTrue(found);
+ mount.unmount();
+
+ /* changing root to empty dir */
+ mount = setupMount("/" + dir);
+
+ subdirs = mount.listdir("/");
+ found = false;
+ for (String d : subdirs) {
+ found = true;
+ }
+ assertFalse(found);
+ mount.unmount();
+
+ /* cleanup */
+ mount = setupMount("/");
+ mount.rmdir("/" + dir);
+ mount.unmount();
+ }
+}
diff --git a/src/java/test/com/ceph/fs/CephMountTest.java b/src/java/test/com/ceph/fs/CephMountTest.java
new file mode 100644
index 000000000..fcc54d8c5
--- /dev/null
+++ b/src/java/test/com/ceph/fs/CephMountTest.java
@@ -0,0 +1,1040 @@
+/*
+ * 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.FileNotFoundException;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.util.UUID;
+import org.junit.*;
+import static org.junit.Assert.*;
+
+import com.ceph.crush.Bucket;
+
+/*
+ * Coverage
+ * - Everything is covered in at least success cases.
+ * - l[set,get,remove]xattr are not working
+ */
+
+public class CephMountTest {
+
+ private static CephMount mount;
+ private static String basedir = null;
+
+ @BeforeClass
+ public static void setup() throws Exception {
+ mount = new CephMount("admin");
+
+ String conf_file = System.getProperty("CEPH_CONF_FILE");
+ if (conf_file != null)
+ mount.conf_read_file(conf_file);
+ mount.conf_set("client_permissions", "0");
+
+ mount.mount(null);
+
+ basedir = "/libcephfs_junit_" + UUID.randomUUID();
+ mount.mkdir(basedir, 0777);
+ }
+
+ @AfterClass
+ public static void destroy() throws Exception {
+ String[] list = mount.listdir(basedir);
+ for (String l : list)
+ System.out.println(l);
+ mount.rmdir(basedir);
+ mount.unmount();
+ }
+
+ /*
+ * Helper function to construct a unique path.
+ */
+ public String makePath() {
+ String path = basedir + "/" + UUID.randomUUID();
+ return path;
+ }
+
+ /*
+ * Helper to learn the data pool name, by reading it
+ * from the '/' dir inode.
+ */
+ public String getRootPoolName() throws Exception
+ {
+ int fd = mount.open("/", CephMount.O_DIRECTORY, 0600);
+ String pool = mount.get_file_pool_name(fd);
+ mount.close(fd);
+ return pool;
+ }
+
+ /*
+ * Helper function to create a file with the given path and size. The file
+ * is filled with size bytes and the file descriptor is returned.
+ */
+ public int createFile(String path, int size) throws Exception {
+ int fd = mount.open(path, CephMount.O_RDWR|CephMount.O_CREAT, 0600);
+ byte[] buf = new byte[4096];
+ int left = size;
+ while (left > 0) {
+ size = Math.min(buf.length, left);
+ long ret = mount.write(fd, buf, size, -1);
+ left -= ret;
+ }
+ return fd;
+ }
+
+ /*
+ * Helper function to create a unique file and fill it with size bytes. The
+ * file descriptor is returned.
+ */
+ public int createFile(int size) throws Exception {
+ return createFile(makePath(), size);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_mount_dne() throws Exception {
+ CephMount mount2 = new CephMount("admin");
+ String conf_file = System.getProperty("CEPH_CONF_FILE");
+ if (conf_file != null)
+ mount2.conf_read_file(conf_file);
+ mount2.mount("/wlfkjwlekfjwlejfwe");
+ mount2.unmount();
+ }
+
+ /*
+ * Test loading of conf file that doesn't exist.
+ *
+ * FIXME:
+ * Ceph returns -ENOSYS rather than -ENOENT. Correct?
+ */
+ //@Test(expected=FileNotFoundException.class)
+ @Test
+ public void test_conf_read_file_dne() throws Exception {
+ //mount.conf_read_file("/this_file_does_not_exist");
+ }
+
+ /*
+ * Test loading of conf file that isn't valid
+ *
+ * FIXME: implement
+ */
+ @Test
+ public void test_conf_read_file_invalid() throws Exception {
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_conf_read_file_null() throws Exception {
+ mount.conf_read_file(null);
+ }
+
+ /*
+ * conf_set/conf_get
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_conf_set_null_opt() throws Exception {
+ mount.conf_set(null, "value");
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_conf_set_null_val() throws Exception {
+ mount.conf_set("option", null);
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_conf_get_null_opt() throws Exception {
+ mount.conf_get(null);
+ }
+
+ @Test
+ public void test_conf() throws Exception {
+ String opt = "log to stderr";
+ String val1, val2, val3;
+
+ /* get the current value */
+ val1 = mount.conf_get(opt);
+
+ /*
+ * flip the value. this may make some debug information be dumped to the
+ * console when the value becomes true. TODO: find a better config option
+ * to toggle.
+ */
+ if (val1.compareTo("true") == 0)
+ val2 = "false";
+ else
+ val2 = "true";
+ mount.conf_set(opt, val2);
+
+ /* verify the change */
+ val3 = mount.conf_get(opt);
+ assertTrue(val3.compareTo(val2) == 0);
+
+ /* reset to original value */
+ mount.conf_set(opt, val1);
+ val3 = mount.conf_get(opt);
+ assertTrue(val3.compareTo(val1) == 0);
+ }
+
+ /*
+ * statfs
+ */
+
+ @Test
+ public void test_statfs() throws Exception {
+ CephStatVFS st1 = new CephStatVFS();
+ mount.statfs("/", st1);
+
+ /*
+ * FIXME: a better test here is to see if changes to the file system are
+ * reflected through statfs (e.g. increasing number of files). However, it
+ * appears that the updates aren't immediately visible.
+ */
+ assertTrue(st1.bsize > 0);
+ assertTrue(st1.frsize > 0);
+ assertTrue(st1.blocks > 0);
+ assertTrue(st1.bavail > 0);
+ assertTrue(st1.namemax > 0);
+ }
+
+ /*
+ * getcwd/chdir
+ */
+
+ @Test
+ public void test_getcwd() throws Exception {
+ mount.chdir(basedir);
+ String cwd = mount.getcwd();
+ assertTrue(cwd.compareTo(basedir) == 0);
+
+ /* Make sure to reset cwd to root */
+ mount.chdir("/");
+ cwd = mount.getcwd();
+ assertTrue(cwd.compareTo("/") == 0);
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_chdir_null() throws Exception {
+ mount.chdir(null);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_chdir_dne() throws Exception {
+ mount.chdir("/this/path/does/not/exist/");
+ }
+
+ /*
+ * FIXME: this test should throw an error (but does not)?
+ */
+ //@Test(expected=IOException.class)
+ @Test
+ public void test_chdir_not_dir() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+ //mount.chdir(path); shouldn't be able to do this?
+ mount.unlink(path);
+
+ /*
+ * Switch back. Other tests seem to be sensitive to the current directory
+ * being something other than "/". This shouldn't happen once this tests
+ * passes and the call to chdir fails anyway.
+ */
+ mount.chdir("/");
+ }
+
+ /*
+ * listdir
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_listdir_null() throws Exception {
+ mount.listdir(null);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_listdir_dne() throws Exception {
+ mount.listdir("/this/path/does/not/exist/");
+ }
+
+ @Test(expected=IOException.class)
+ public void test_listdir_not_dir() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+ try {
+ mount.listdir(path);
+ } finally {
+ mount.unlink(path);
+ }
+ }
+
+ @Test
+ public void test_listdir() throws Exception {
+ String dir = makePath();
+ mount.mkdir(dir, 0777);
+ /* test that new directory is empty */
+ String[] list = mount.listdir(dir);
+ assertTrue(list.length == 0);
+ /* test that new directories are seen */
+ for (int i = 0; i < 3; i++)
+ mount.mkdir(dir + "/" + i, 777);
+ list = mount.listdir(dir);
+ assertTrue(list.length == 3);
+ /* test that more new directories are seen */
+ for (int i = 0; i < 30; i++)
+ mount.mkdir(dir + "/x" + i, 777);
+ list = mount.listdir(dir);
+ assertTrue(list.length == 33);
+
+ /* remove */
+ for (int i = 0; i < 30; i++)
+ mount.rmdir(dir + "/x" + i);
+ for (int i = 0; i < 3; i++)
+ mount.rmdir(dir + "/" + i);
+ mount.rmdir(dir);
+ }
+
+ /*
+ * Missing
+ *
+ * ceph_link
+ * ceph_unlink
+ */
+
+ /*
+ * rename
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_rename_null_from() throws Exception {
+ mount.rename(null, "to");
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_rename_null_to() throws Exception {
+ mount.rename("from", null);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_rename_dne() throws Exception {
+ mount.rename("/this/doesnt/exist", "/this/neither");
+ }
+
+ @Test
+ public void test_rename() throws Exception {
+ /* create a file */
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+
+ /* move it to a new name */
+ String newpath = makePath();
+ mount.rename(path, newpath);
+
+ /* verfiy the sizes are the same */
+ CephStat st = new CephStat();
+ mount.lstat(newpath, st);
+ assertTrue(st.size == 1);
+
+ /* remove the file */
+ mount.unlink(newpath);
+ }
+
+ /*
+ * mkdir/mkdirs/rmdir
+ */
+
+ @Test(expected=IOException.class)
+ public void test_mkdir_exists() throws Exception {
+ String path = makePath();
+ mount.mkdir(path, 0777);
+ try {
+ mount.mkdir(path, 0777);
+ } finally {
+ mount.rmdir(path);
+ }
+ }
+
+ @Test(expected=IOException.class)
+ public void test_mkdirs_exists() throws Exception {
+ String path = makePath();
+ mount.mkdirs(path, 0777);
+ try {
+ mount.mkdirs(path, 0777);
+ } finally {
+ mount.rmdir(path);
+ }
+ }
+
+ @Test
+ public void test_mkdir() throws Exception {
+ String path = makePath();
+ mount.mkdir(path, 0777);
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+ assertTrue(st.isDir());
+ mount.rmdir(path);
+ }
+
+ @Test
+ public void test_mkdirs() throws Exception {
+ String path = makePath();
+ mount.mkdirs(path + "/x/y", 0777);
+
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+ assertTrue(st.isDir());
+
+ mount.lstat(path + "/x", st);
+ assertTrue(st.isDir());
+
+ mount.lstat(path + "/x/y", st);
+ assertTrue(st.isDir());
+
+ mount.rmdir(path + "/x/y");
+ mount.rmdir(path + "/x");
+ mount.rmdir(path);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_rmdir() throws Exception {
+ /* make a new directory */
+ String path = makePath();
+ mount.mkdir(path, 0777);
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+ assertTrue(st.isDir());
+ /* remove it */
+ mount.rmdir(path);
+ /* should not exist now */
+ mount.lstat(path, st);
+ }
+
+ /*
+ * readlink
+ * symlink
+ */
+ @Test
+ public void test_symlink() throws Exception {
+ String oldpath = makePath();
+ String newpath = makePath();
+
+ mount.symlink(oldpath, newpath);
+ CephStat stat = new CephStat();
+ mount.lstat(newpath, stat);
+ assertTrue(stat.isSymlink());
+
+ String symlink = mount.readlink(newpath);
+ assertTrue(symlink.compareTo(oldpath) == 0);
+
+ mount.unlink(newpath);
+ }
+
+ /*
+ * lstat
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_lstat_null_path() throws Exception {
+ mount.lstat(null, new CephStat());
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_lstat_null_stat() throws Exception {
+ mount.lstat("/path", null);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_lstat_null_dne() throws Exception {
+ mount.lstat("/path/does/not/exist", new CephStat());
+ }
+
+ /*
+ * test_stat covers lstat and fstat and stat.
+ *
+ * TODO: create test that for lstat vs stat with symlink follow/nofollow.
+ */
+
+ @Test
+ public void test_stat() throws Exception {
+ /* create a new file */
+ String path = makePath();
+ int size = 12345;
+ int fd = createFile(path, size);
+ mount.close(fd);
+
+ /* test some basic info about the new file */
+ CephStat orig_st = new CephStat();
+ mount.lstat(path, orig_st);
+ assertTrue(orig_st.size == size);
+ assertTrue(orig_st.blksize > 0);
+ assertTrue(orig_st.blocks > 0);
+
+ /* now try stat */
+ CephStat stat_st = new CephStat();
+ mount.stat(path, stat_st);
+
+ /* now try fstat */
+ CephStat other_st = new CephStat();
+ fd = mount.open(path, CephMount.O_RDWR, 0);
+ mount.fstat(fd, other_st);
+ mount.close(fd);
+
+ mount.unlink(path);
+
+ /* compare to fstat results */
+ assertTrue(orig_st.mode == other_st.mode);
+ assertTrue(orig_st.uid == other_st.uid);
+ assertTrue(orig_st.gid == other_st.gid);
+ assertTrue(orig_st.size == other_st.size);
+ assertTrue(orig_st.blksize == other_st.blksize);
+ assertTrue(orig_st.blocks == other_st.blocks);
+
+ /* compare to stat results */
+ assertTrue(orig_st.mode == stat_st.mode);
+ assertTrue(orig_st.uid == stat_st.uid);
+ assertTrue(orig_st.gid == stat_st.gid);
+ assertTrue(orig_st.size == stat_st.size);
+ assertTrue(orig_st.blksize == stat_st.blksize);
+ assertTrue(orig_st.blocks == stat_st.blocks);
+ }
+
+ /*
+ * stat
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_stat_null_path() throws Exception {
+ mount.stat(null, new CephStat());
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_stat_null_stat() throws Exception {
+ mount.stat("/path", null);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_stat_null_dne() throws Exception {
+ mount.stat("/path/does/not/exist", new CephStat());
+ }
+
+ @Test(expected=CephNotDirectoryException.class)
+ public void test_enotdir() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+
+ try {
+ CephStat stat = new CephStat();
+ mount.lstat(path + "/blah", stat);
+ } finally {
+ mount.unlink(path);
+ }
+ }
+
+ /*
+ * setattr
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_setattr_null_path() throws Exception {
+ mount.setattr(null, new CephStat(), 0);
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_setattr_null_stat() throws Exception {
+ mount.setattr("/path", null, 0);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_setattr_dne() throws Exception {
+ mount.setattr("/path/does/not/exist", new CephStat(), 0);
+ }
+
+ @Test
+ public void test_setattr() throws Exception {
+ /* create a file */
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+
+ CephStat st1 = new CephStat();
+ mount.lstat(path, st1);
+
+ st1.uid += 1;
+ st1.gid += 1;
+ mount.setattr(path, st1, mount.SETATTR_UID|mount.SETATTR_GID);
+
+ CephStat st2 = new CephStat();
+ mount.lstat(path, st2);
+
+ assertTrue(st2.uid == st1.uid);
+ assertTrue(st2.gid == st1.gid);
+
+ /* remove the file */
+ mount.unlink(path);
+ }
+
+ /*
+ * chmod
+ */
+
+ @Test(expected=NullPointerException.class)
+ public void test_chmod_null_path() throws Exception {
+ mount.chmod(null, 0);
+ }
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_chmod_dne() throws Exception {
+ mount.chmod("/path/does/not/exist", 0);
+ }
+
+ @Test
+ public void test_chmod() throws Exception {
+ /* create a file */
+ String path = makePath();
+ int fd = createFile(path, 1);
+ mount.close(fd);
+
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+
+ /* flip a bit */
+ int mode = st.mode;
+ if ((mode & 1) != 0)
+ mode -= 1;
+ else
+ mode += 1;
+
+ mount.chmod(path, mode);
+ CephStat st2 = new CephStat();
+ mount.lstat(path, st2);
+ assertTrue(st2.mode == mode);
+
+ mount.unlink(path);
+ }
+
+ /*
+ * fchmod
+ */
+
+ @Test
+ public void test_fchmod() throws Exception {
+ /* create a file */
+ String path = makePath();
+ int fd = createFile(path, 1);
+
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+
+ /* flip a bit */
+ int mode = st.mode;
+ if ((mode & 1) != 0)
+ mode -= 1;
+ else
+ mode += 1;
+
+ mount.fchmod(fd, mode);
+ mount.close(fd);
+
+ CephStat st2 = new CephStat();
+ mount.lstat(path, st2);
+ assertTrue(st2.mode == mode);
+
+ mount.unlink(path);
+ }
+
+ /*
+ * truncate
+ */
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_truncate_dne() throws Exception {
+ mount.truncate("/path/does/not/exist", 0);
+ }
+
+ @Test(expected=NullPointerException.class)
+ public void test_truncate_null_path() throws Exception {
+ mount.truncate(null, 0);
+ }
+
+ @Test
+ public void test_truncate() throws Exception {
+ // make file
+ String path = makePath();
+ int orig_size = 1398331;
+ int fd = createFile(path, orig_size);
+ mount.close(fd);
+
+ // check file size
+ CephStat st = new CephStat();
+ mount.lstat(path, st);
+ assertTrue(st.size == orig_size);
+
+ // truncate and check
+ int crop_size = 333333;
+ mount.truncate(path, crop_size);
+ mount.lstat(path, st);
+ assertTrue(st.size == crop_size);
+
+ // check after re-open
+ fd = mount.open(path, CephMount.O_RDWR, 0);
+ mount.fstat(fd, st);
+ assertTrue(st.size == crop_size);
+ mount.close(fd);
+
+ mount.unlink(path);
+ }
+
+ @Test
+ public void test_open_layout() throws Exception {
+ String path = makePath();
+ int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0,
+ (1<<20), 1, (1<<20), null);
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ /*
+ * open/close
+ */
+
+ @Test(expected=FileNotFoundException.class)
+ public void test_open_dne() throws Exception {
+ mount.open("/path/doesnt/exist", 0, 0);
+ }
+
+ /*
+ * lseek
+ */
+
+ @Test
+ public void test_lseek() throws Exception {
+ /* create a new file */
+ String path = makePath();
+ int size = 12345;
+ int fd = createFile(path, size);
+ mount.close(fd);
+
+ /* open and check size */
+ fd = mount.open(path, CephMount.O_RDWR, 0);
+ long end = mount.lseek(fd, 0, CephMount.SEEK_END);
+ mount.close(fd);
+
+ mount.unlink(path);
+
+ assertTrue(size == (int)end);
+ }
+
+ /*
+ * read/write
+ */
+
+ @Test
+ public void test_read() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1500);
+ byte[] buf = new byte[1500];
+ long ret = mount.read(fd, buf, 1500, 0);
+ assertTrue(ret == 1500);
+ mount.unlink(path);
+ }
+
+ /*
+ * ftruncate
+ */
+
+ @Test
+ public void test_ftruncate() throws Exception {
+ // make file
+ String path = makePath();
+ int orig_size = 1398331;
+ int fd = createFile(path, orig_size);
+
+ // check file size
+ CephStat st = new CephStat();
+ mount.fstat(fd, st);
+ assertTrue(st.size == orig_size);
+
+ // truncate and check
+ int crop_size = 333333;
+ mount.ftruncate(fd, crop_size);
+ mount.fstat(fd, st);
+ if (st.size != crop_size) {
+ System.err.println("ftruncate error: st.size=" + st.size + " crop_size=" + crop_size);
+ assertTrue(false);
+ }
+ assertTrue(st.size == crop_size);
+ mount.close(fd);
+
+ // check after re-open
+ fd = mount.open(path, CephMount.O_RDWR, 0);
+ mount.fstat(fd, st);
+ assertTrue(st.size == crop_size);
+ mount.close(fd);
+
+ mount.unlink(path);
+ }
+
+ /*
+ * fsync
+ */
+
+ @Test
+ public void test_fsync() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 123);
+ mount.fsync(fd, false);
+ mount.fsync(fd, true);
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ /*
+ * flock
+ */
+
+ @Test
+ public void test_flock() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 123);
+ mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 42);
+ mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 43);
+ mount.flock(fd, CephMount.LOCK_UN, 42);
+ mount.flock(fd, CephMount.LOCK_UN, 43);
+ mount.flock(fd, CephMount.LOCK_EX | CephMount.LOCK_NB, 42);
+ try {
+ mount.flock(fd, CephMount.LOCK_SH | CephMount.LOCK_NB, 43);
+ assertTrue(false);
+ } catch(IOException io) {}
+ try {
+ mount.flock(fd, CephMount.LOCK_EX | CephMount.LOCK_NB, 43);
+ assertTrue(false);
+ } catch(IOException io) {}
+ mount.flock(fd, CephMount.LOCK_SH, 42); // downgrade
+ mount.flock(fd, CephMount.LOCK_SH, 43);
+ mount.flock(fd, CephMount.LOCK_UN, 42);
+ mount.flock(fd, CephMount.LOCK_UN, 43);
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ /*
+ * fstat
+ *
+ * success case is handled in test_stat along with lstat.
+ */
+
+ /*
+ * sync_fs
+ */
+
+ @Test
+ public void test_sync_fs() throws Exception {
+ mount.sync_fs();
+ }
+
+ /*
+ * get/set/list/remove xattr
+ */
+
+ @Test
+ public void test_xattr() throws Exception {
+ /* make file */
+ String path = makePath();
+ int fd = createFile(path, 123);
+ mount.close(fd);
+
+ /* make xattrs */
+ String val1 = "This is a new xattr";
+ String val2 = "This is a different xattr";
+ byte[] buf1 = val1.getBytes();
+ byte[] buf2 = val2.getBytes();
+ mount.setxattr(path, "user.attr1", buf1, buf1.length, mount.XATTR_CREATE);
+ mount.setxattr(path, "user.attr2", buf2, buf2.length, mount.XATTR_CREATE);
+
+ /* list xattrs */
+ String[] xattrs = mount.listxattr(path);
+ assertTrue(xattrs.length == 2);
+ int found = 0;
+ for (String xattr : xattrs) {
+ if (xattr.compareTo("user.attr1") == 0) {
+ found++;
+ continue;
+ }
+ if (xattr.compareTo("user.attr2") == 0) {
+ found++;
+ continue;
+ }
+ System.out.println("found unwanted xattr: " + xattr);
+ }
+ assertTrue(found == 2);
+
+ /* get first xattr by looking up length */
+ long attr1_len = mount.getxattr(path, "user.attr1", null);
+ byte[] out = new byte[(int)attr1_len];
+ mount.getxattr(path, "user.attr1", out);
+ String outStr = new String(out);
+ assertTrue(outStr.compareTo(val1) == 0);
+
+ /* get second xattr assuming original length */
+ out = new byte[buf2.length];
+ mount.getxattr(path, "user.attr2", out);
+ outStr = new String(out);
+ assertTrue(outStr.compareTo(val2) == 0);
+
+ /* remove the attributes */
+ /* FIXME: the MDS returns ENODATA for removexattr */
+ /*
+ mount.removexattr(path, "attr1");
+ xattrs = mount.listxattr(path);
+ assertTrue(xattrs.length == 1);
+ mount.removexattr(path, "attr2");
+ xattrs = mount.listxattr(path);
+ assertTrue(xattrs.length == 0);
+ */
+
+ mount.unlink(path);
+ }
+
+ /*
+ * get/set/list/remove symlink xattr
+ *
+ * Currently not working. Code is the same as for regular xattrs, so there
+ * might be a deeper issue.
+ */
+
+ @Test
+ public void test_get_stripe_unit() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1);
+ assertTrue(mount.get_file_stripe_unit(fd) > 0);
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ @Test
+ public void test_get_repl() throws Exception {
+ String path = makePath();
+ int fd = createFile(path, 1);
+ assertTrue(mount.get_file_replication(fd) > 0);
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ /*
+ * stripe unit granularity
+ */
+
+ @Test
+ public void test_get_stripe_unit_gran() throws Exception {
+ assertTrue(mount.get_stripe_unit_granularity() > 0);
+ }
+
+ @Test
+ public void test_get_pool_id() throws Exception {
+ String data_pool_name = getRootPoolName();
+ /* returns valid pool id */
+ assertTrue(mount.get_pool_id(data_pool_name) >= 0);
+
+ /* test non-existent pool name */
+ try {
+ mount.get_pool_id("asdlfkjlsejflkjef");
+ assertTrue(false);
+ } catch (CephPoolException e) {}
+ }
+
+ @Test
+ public void test_get_pool_replication() throws Exception {
+ /* test invalid pool id */
+ try {
+ mount.get_pool_replication(-1);
+ assertTrue(false);
+ } catch (CephPoolException e) {}
+
+ /* test valid pool id */
+ String data_pool_name = getRootPoolName();
+ int poolid = mount.get_pool_id(data_pool_name);
+ assertTrue(poolid >= 0);
+ assertTrue(mount.get_pool_replication(poolid) > 0);
+ }
+
+ @Test
+ public void test_get_file_pool_name() throws Exception {
+ String data_pool_name = getRootPoolName();
+ String path = makePath();
+ int fd = createFile(path, 1);
+ String pool = mount.get_file_pool_name(fd);
+ mount.close(fd);
+ assertTrue(pool != null);
+ /* assumes using default data pool */
+ assertTrue(pool.compareTo(data_pool_name) == 0);
+ mount.unlink(path);
+ }
+
+ @Test(expected=IOException.class)
+ public void test_get_file_pool_name_ebadf() throws Exception {
+ String pool = mount.get_file_pool_name(-40);
+ }
+
+ @Test
+ public void test_get_file_extent() throws Exception {
+ int stripe_unit = 1<<18;
+ String path = makePath();
+ int fd = mount.open(path, CephMount.O_WRONLY|CephMount.O_CREAT, 0,
+ stripe_unit, 2, stripe_unit*2, null);
+
+ CephFileExtent e = mount.get_file_extent(fd, 0);
+ assertTrue(e.getOSDs().length > 0);
+
+ assertTrue(e.getOffset() == 0);
+ assertTrue(e.getLength() == stripe_unit);
+
+ e = mount.get_file_extent(fd, stripe_unit/2);
+ assertTrue(e.getOffset() == stripe_unit/2);
+ assertTrue(e.getLength() == stripe_unit/2);
+
+ e = mount.get_file_extent(fd, 3*stripe_unit/2-1);
+ assertTrue(e.getOffset() == 3*stripe_unit/2-1);
+ assertTrue(e.getLength() == stripe_unit/2+1);
+
+ e = mount.get_file_extent(fd, 3*stripe_unit/2+1);
+ assertTrue(e.getLength() == stripe_unit/2-1);
+
+ mount.close(fd);
+ mount.unlink(path);
+ }
+
+ @Test
+ public void test_get_osd_crush_location() throws Exception {
+ Bucket[] path = mount.get_osd_crush_location(0);
+ assertTrue(path.length > 0);
+ for (Bucket b : path) {
+ assertTrue(b.getType().length() > 0);
+ assertTrue(b.getName().length() > 0);
+ }
+ }
+
+ @Test
+ public void test_get_osd_address() throws Exception {
+ InetAddress addr = mount.get_osd_address(0);
+ assertTrue(addr.getHostAddress().length() > 0);
+ }
+}
diff --git a/src/java/test/com/ceph/fs/CephUnmountedTest.java b/src/java/test/com/ceph/fs/CephUnmountedTest.java
new file mode 100644
index 000000000..eb95e69fb
--- /dev/null
+++ b/src/java/test/com/ceph/fs/CephUnmountedTest.java
@@ -0,0 +1,164 @@
+/*
+ * 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 org.junit.*;
+import static org.junit.Assert.*;
+
+public class CephUnmountedTest {
+
+ private CephMount mount;
+
+ @Before
+ public void setup() throws Exception {
+ mount = new CephMount("admin");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_unmount() throws Exception {
+ mount.unmount();
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_statfs() throws Exception {
+ CephStatVFS stat = new CephStatVFS();
+ mount.statfs("/a/path", stat);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_getcwd() throws Exception {
+ mount.getcwd();
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_chdir() throws Exception {
+ mount.chdir("/a/path");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_listdir() throws Exception {
+ mount.listdir("/a/path");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_unlink() throws Exception {
+ mount.unlink("/a/path");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_rename() throws Exception {
+ mount.rename("/a/path", "/another/path");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_mkdirs() throws Exception {
+ mount.mkdirs("/a/path", 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_rmdir() throws Exception {
+ mount.rmdir("/a/path");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_stat() throws Exception {
+ CephStat stat = new CephStat();
+ mount.stat("/a/path", stat);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_lstat() throws Exception {
+ CephStat stat = new CephStat();
+ mount.lstat("/a/path", stat);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_setattr() throws Exception {
+ CephStat stat = new CephStat();
+ mount.setattr("/a/path", stat, 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_open() throws Exception {
+ mount.open("/a/path", 0, 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_open_layout() throws Exception {
+ mount.open("/a/path", 0, 0, 0, 0, 0, null);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_close() throws Exception {
+ mount.close(0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_lseek() throws Exception {
+ mount.lseek(0, 0, CephMount.SEEK_CUR);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_read() throws Exception {
+ byte[] buf = new byte[1];
+ mount.read(0, buf, 1, 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_write() throws Exception {
+ byte[] buf = new byte[1];
+ mount.write(0, buf, 1, 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_get_stripe_unit() throws Exception {
+ mount.get_file_stripe_unit(0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_get_repl() throws Exception {
+ mount.get_file_replication(0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_get_stripe_unit_gran() throws Exception {
+ mount.get_stripe_unit_granularity();
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_get_pool_id() throws Exception {
+ mount.get_pool_id("data");
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_get_pool_replication() throws Exception {
+ mount.get_pool_replication(1);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_fchmod() throws Exception {
+ mount.fchmod(1, 0);
+ }
+
+ @Test(expected=CephNotMountedException.class)
+ public void test_chmod() throws Exception {
+ mount.chmod("/foo", 0);
+ }
+}