From 350433530fb13f219ed528f0327429d17c38de47 Mon Sep 17 00:00:00 2001 From: Noah Watkins Date: Sat, 1 Sep 2012 10:26:41 -0700 Subject: [PATCH] java: add Java and C++ source files This adds all of the Java and C++ source files that make up the libcephfs Java wrappers package. Signed-off-by: Noah Watkins --- src/common/config_opts.h | 1 + src/java/README | 48 + src/java/build.xml | 67 + src/java/java/com/ceph/fs/CephException.java | 40 + src/java/java/com/ceph/fs/CephMount.java | 645 +++++ .../java/com/ceph/fs/CephNativeLoader.java | 35 + .../com/ceph/fs/CephNotMountedException.java | 42 + src/java/java/com/ceph/fs/CephStat.java | 45 + src/java/java/com/ceph/fs/CephStatVFS.java | 33 + src/java/native/libcephfs_jni.cc | 2383 +++++++++++++++++ src/java/test/CephMountCreateTest.java | 88 + src/java/test/CephMountTest.java | 797 ++++++ src/java/test/CephUnmountedTest.java | 143 + 13 files changed, 4367 insertions(+) create mode 100644 src/java/README create mode 100644 src/java/build.xml create mode 100644 src/java/java/com/ceph/fs/CephException.java create mode 100644 src/java/java/com/ceph/fs/CephMount.java create mode 100644 src/java/java/com/ceph/fs/CephNativeLoader.java create mode 100644 src/java/java/com/ceph/fs/CephNotMountedException.java create mode 100644 src/java/java/com/ceph/fs/CephStat.java create mode 100644 src/java/java/com/ceph/fs/CephStatVFS.java create mode 100644 src/java/native/libcephfs_jni.cc create mode 100644 src/java/test/CephMountCreateTest.java create mode 100644 src/java/test/CephMountTest.java create mode 100644 src/java/test/CephUnmountedTest.java diff --git a/src/common/config_opts.h b/src/common/config_opts.h index 29e3b74766d32..706dfd5383272 100644 --- a/src/common/config_opts.h +++ b/src/common/config_opts.h @@ -82,6 +82,7 @@ SUBSYS(heartbeatmap, 1, 5) SUBSYS(perfcounter, 1, 5) SUBSYS(rgw, 1, 5) // log level for the Rados gateway SUBSYS(hadoop, 1, 5) +SUBSYS(javaclient, 1, 5) SUBSYS(asok, 1, 5) SUBSYS(throttle, 1, 5) diff --git a/src/java/README b/src/java/README new file mode 100644 index 0000000000000..ca39a442c8b3b --- /dev/null +++ b/src/java/README @@ -0,0 +1,48 @@ +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 JUnit and Ant. + +To run the tests make sure that the JUnit JAR is available in the lib/ +directory. For example: + + $ mkdir lib + $ cd lib + $ curl -O https://github.com/downloads/KentBeck/junit/junit-4.8.2.jar + +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 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 in ../.libs 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 0000000000000..f846ca433e437 --- /dev/null +++ b/src/java/build.xml @@ -0,0 +1,67 @@ + + + + CephFS Java Bindings + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/java/java/com/ceph/fs/CephException.java b/src/java/java/com/ceph/fs/CephException.java new file mode 100644 index 0000000000000..2fe213704f2e5 --- /dev/null +++ b/src/java/java/com/ceph/fs/CephException.java @@ -0,0 +1,40 @@ +/* + * 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 that represents generic Ceph exception. + */ +public class CephException extends Exception { + + /** + * Create basic CephException. + */ + public CephException() { + super(); + } + + /** + * Create CephException with message. + */ + public CephException(String s) { + super(s); + } +} 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 0000000000000..0211f673073c5 --- /dev/null +++ b/src/java/java/com/ceph/fs/CephMount.java @@ -0,0 +1,645 @@ +/* + * 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.util.Arrays; +import java.lang.String; + +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; + + /* + * 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; + + + /* + * This is run by the class loader and will report early any problems + * finding or linking in the shared JNI library. + */ + static { + CephNativeLoader.checkLoaded(); + } + + /* + * Package-private: called from CephNativeLoader + */ + static native void native_initialize(); + + /** + * Create a new CephMount with specific client id. + * + * @param id client id. + */ + public CephMount(String id) { + native_ceph_create(this, id); + } + + private static synchronized 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) { + native_ceph_mount(instance_ptr, root); + } + + private static synchronized native int native_ceph_mount(long mountp, String root); + + /** + * Shutdown the mount. + */ + public void shutdown() { + native_ceph_shutdown(instance_ptr); + } + + private static synchronized native void native_ceph_shutdown(long mountp); + + /** + * Load configuration from a file. + * + * @param path The path to the configuration file. + */ + public void conf_read_file(String path) throws FileNotFoundException { + native_ceph_conf_read_file(instance_ptr, path); + } + + private static synchronized 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) { + native_ceph_conf_set(instance_ptr, option, value); + } + + private static synchronized 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) { + return native_ceph_conf_get(instance_ptr, option); + } + + private static synchronized 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 { + native_ceph_statfs(instance_ptr, path, statvfs); + } + + private static synchronized 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() { + return native_ceph_getcwd(instance_ptr); + } + + private static synchronized 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 { + native_ceph_chdir(instance_ptr, path); + } + + private static synchronized 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 { + return native_ceph_listdir(instance_ptr, dir); + } + + private static synchronized 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 { + native_ceph_link(instance_ptr, oldpath, newpath); + } + + private static synchronized 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 { + native_ceph_unlink(instance_ptr, path); + } + + private static synchronized 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 { + native_ceph_rename(instance_ptr, from, to); + } + + private static synchronized 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) { + native_ceph_mkdir(instance_ptr, path, mode); + } + + private static synchronized 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) { + native_ceph_mkdirs(instance_ptr, path, mode); + } + + private static synchronized 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 { + native_ceph_rmdir(instance_ptr, path); + } + + private static synchronized native int native_ceph_rmdir(long mountp, String path); + + /** + * Read the value of a symbolic link. + */ + public String readlink(String path) throws FileNotFoundException { + return native_ceph_readlink(instance_ptr, path); + } + + private static synchronized 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) { + native_ceph_symlink(instance_ptr, oldpath, newpath); + } + + private static synchronized 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 lstat(String path, CephStat stat) throws FileNotFoundException { + native_ceph_lstat(instance_ptr, path, stat); + } + + private static synchronized 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 { + native_ceph_setattr(instance_ptr, path, stat, mask); + } + + private static synchronized 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 { + native_ceph_chmod(instance_ptr, path, mode); + } + + private static synchronized native int native_ceph_chmod(long mountp, String path, 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 { + native_ceph_truncate(instance_ptr, path, size); + } + + private static synchronized 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 { + return native_ceph_open(instance_ptr, path, flags, mode); + } + + private static synchronized native int native_ceph_open(long mountp, String path, int flags, int mode); + + /** + * Close an open file. + * + * @param fd The file descriptor. + */ + public void close(int fd) { + native_ceph_close(instance_ptr, fd); + } + + private static synchronized 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) { + return native_ceph_lseek(instance_ptr, fd, offset, whence); + } + + private static synchronized 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) { + return native_ceph_read(instance_ptr, fd, buf, size, offset); + } + + private static synchronized 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) { + return native_ceph_write(instance_ptr, fd, buf, size, offset); + } + + private static synchronized 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) { + native_ceph_ftruncate(instance_ptr, fd, size); + } + + private static synchronized 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) { + native_ceph_fsync(instance_ptr, fd, dataonly); + } + + private static synchronized native int native_ceph_fsync(long mountp, int fd, boolean dataonly); + + /** + * 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) { + native_ceph_fstat(instance_ptr, fd, stat); + } + + private static synchronized native int native_ceph_fstat(long mountp, int fd, CephStat stat); + + /** + * Synchronize the client with the file system. + */ + public void sync_fs() { + native_ceph_sync_fs(instance_ptr); + } + + private static synchronized 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. + * @param The length of the attribute value. See description for more + * details. + */ + public long getxattr(String path, String name, byte[] buf) throws FileNotFoundException { + return native_ceph_getxattr(instance_ptr, path, name, buf); + } + + private static synchronized 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 nuf 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 { + return native_ceph_lgetxattr(instance_ptr, path, name, buf); + } + + private static synchronized 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 { + return native_ceph_listxattr(instance_ptr, path); + } + + private static synchronized 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 { + return native_ceph_llistxattr(instance_ptr, path); + } + + private static synchronized 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 { + native_ceph_removexattr(instance_ptr, path, name); + } + + private static synchronized 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 { + native_ceph_lremovexattr(instance_ptr, path, name); + } + + private static synchronized 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 { + native_ceph_setxattr(instance_ptr, path, name, buf, size, flags); + } + + private static synchronized 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 { + native_ceph_lsetxattr(instance_ptr, path, name, buf, size, flags); + } + + private static synchronized 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) { + return native_ceph_get_file_stripe_unit(instance_ptr, fd); + } + + private static synchronized native int native_ceph_get_file_stripe_unit(long mountp, int fd); + + /** + * Get the replication of a file. + * + * @param fd The file descriptor. + * @return The file replication. + */ + public int get_file_replication(int fd) { + return native_ceph_get_file_replication(instance_ptr, fd); + } + + private static synchronized native int native_ceph_get_file_replication(long mountp, int fd); + + /** + * Set the default file stripe unit. + * + * @param stripe_unit The stripe unit. + */ + public void set_default_file_stripe_unit(int stripe_unit) { + native_ceph_set_default_file_stripe_unit(instance_ptr, stripe_unit); + } + + private static synchronized native int native_ceph_set_default_file_stripe_unit(long mountp, int stripe_unit); + + /** + * Set the default file stripe count. + * + * @param stripe_count The stripe count. + */ + public void set_default_file_stripe_count(int stripe_count) { + native_ceph_set_default_file_stripe_count(instance_ptr, stripe_count); + } + + private static synchronized native int native_ceph_set_default_file_stripe_count(long mountp, int stripe_count); + + /** + * Set the default object size. + * + * @param object_size The object size. + */ + public void set_default_object_size(int object_size) { + native_ceph_set_default_object_size(instance_ptr, object_size); + } + + private static synchronized native int native_ceph_set_default_object_size(long mountp, int object_size); + + /** + * Favor reading from local replicas when possible. + * + * @param state Enable or disable localized reads. + */ + public void localize_reads(boolean state) { + native_ceph_localize_reads(instance_ptr, state); + } + + private static synchronized native int native_ceph_localize_reads(long mountp, boolean on); +} 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 0000000000000..21a54c339fce9 --- /dev/null +++ b/src/java/java/com/ceph/fs/CephNativeLoader.java @@ -0,0 +1,35 @@ +/* + * 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 boolean loaded = false; + + static { + if (!loaded) { + System.loadLibrary("cephfs_jni"); + CephMount.native_initialize(); + loaded = true; + } + } + + static void checkLoaded() { assert(loaded); } +} 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 0000000000000..3e43a75a7ef74 --- /dev/null +++ b/src/java/java/com/ceph/fs/CephNotMountedException.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.fs; + +import java.io.IOException; + +/** + * Ceph is not mounted. + */ +public class CephNotMountedException extends IOException { + + /** + * Construct CephNotMountedException. + */ + public CephNotMountedException() { + super(); + } + + /** + * Construct CephNotMountedException with message. + */ + public CephNotMountedException(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 0000000000000..a2f5a7460c1cd --- /dev/null +++ b/src/java/java/com/ceph/fs/CephStat.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; + +/** + * Holds struct stat fields. + */ +public class CephStat { + 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; + + /* + * Results from the following tests: + * + * - S_ISREG + * - S_ISDIR + * - S_ISLNK + */ + public boolean is_file; + public boolean is_directory; + public boolean 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 0000000000000..4a37a28dbef06 --- /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/libcephfs_jni.cc b/src/java/native/libcephfs_jni.cc new file mode 100644 index 0000000000000..fe5ce754f321e --- /dev/null +++ b/src/java/native/libcephfs_jni.cc @@ -0,0 +1,2383 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include + +#include +#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_MOUNT_CP "com/ceph/fs/CephMount" +#define CEPH_NOTMOUNTED_CP "com/ceph/fs/CephNotMountedException" + +/* + * 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 + +/* + * 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 + +/* 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) + +#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; + +/* + * 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/OutOfMemoryException", 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 handle_error(JNIEnv *env, int rc) +{ + switch (rc) { + case -ENOENT: + cephThrowFNF(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) + +#define CHECK_MOUNTED_NORV(_c) do { \ + if (!ceph_is_mounted((_c))) { \ + THROW(env, CEPH_NOTMOUNTED_CP, "not mounted"); \ + return; \ + } } 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 retreive 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; + +/* + * 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); + +#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; + + 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 : "") << 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_shutdown + * Signature: (J)V + */ +JNIEXPORT void JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1shutdown + (JNIEnv *env, jclass clz, jlong j_mntp) +{ + struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); + CephContext *cct = ceph_get_mount_context(cmount); + + CHECK_MOUNTED_NORV(cmount); + + ldout(cct, 10) << "jni: ceph_shutdown: enter" << dendl; + + ceph_shutdown(cmount); + + ldout(cct, 10) << "jni: ceph_shutdown: exit" << dendl; +} + +/* + * 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::iterator it; + list 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); + + 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 stat st; + jstring j_linkname; + int ret; + + 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; + ret = ceph_lstat(cmount, c_path, &st); + 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[st.st_size + 1]; + if (!linkname) { + env->ReleaseStringUTFChars(j_path, c_path); + cephThrowOutOfMemory(env, "head allocation failed"); + return NULL; + } + + ldout(cct, 10) << "jni: readlink: size " << st.st_size << " path " << c_path << dendl; + + ret = ceph_readlink(cmount, c_path, linkname, st.st_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 > st.st_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; +} + +/* + * 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; + long long time; + struct stat st; + 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_lstat(cmount, c_path, &st); + + ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl; + + env->ReleaseStringUTFChars(j_path, c_path); + + if (ret) { + handle_error(env, ret); + return ret; + } + + env->SetIntField(j_cephstat, cephstat_mode_fid, st.st_mode); + env->SetIntField(j_cephstat, cephstat_uid_fid, st.st_uid); + env->SetIntField(j_cephstat, cephstat_gid_fid, st.st_gid); + env->SetLongField(j_cephstat, cephstat_size_fid, st.st_size); + env->SetLongField(j_cephstat, cephstat_blksize_fid, st.st_blksize); + env->SetLongField(j_cephstat, cephstat_blocks_fid, st.st_blocks); + + time = st.st_mtim.tv_sec; + time *= 1000; + time += st.st_mtim.tv_nsec / 1000000; + env->SetLongField(j_cephstat, cephstat_m_time_fid, time); + + time = st.st_atim.tv_sec; + time *= 1000; + time += st.st_atim.tv_nsec / 1000000; + env->SetLongField(j_cephstat, cephstat_a_time_fid, time); + + env->SetBooleanField(j_cephstat, cephstat_is_file_fid, + S_ISREG(st.st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_cephstat, cephstat_is_directory_fid, + S_ISDIR(st.st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid, + S_ISLNK(st.st_mode) ? JNI_TRUE : JNI_FALSE); + + 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 stat st; + 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(&st, 0, sizeof(st)); + + st.st_mode = env->GetIntField(j_cephstat, cephstat_mode_fid); + st.st_uid = env->GetIntField(j_cephstat, cephstat_uid_fid); + st.st_gid = env->GetIntField(j_cephstat, cephstat_gid_fid); + st.st_mtime = env->GetIntField(j_cephstat, cephstat_m_time_fid); + st.st_atime = env->GetIntField(j_cephstat, cephstat_a_time_fid); + + ldout(cct, 10) << "jni: setattr: path " << c_path << " mask " << mask << dendl; + + ret = ceph_setattr(cmount, c_path, &st, mask); + + 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_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_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 " << (int)j_size << + " offset " << (int)j_offset << dendl; + + ret = ceph_read(cmount, (int)j_fd, (char*)c_buf, (int)j_size, (int)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 " << (int)j_size << + " offset " << (int)j_offset << dendl; + + ret = ceph_write(cmount, (int)j_fd, (char*)c_buf, (int)j_size, (int)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_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); + long long time; + struct stat st; + 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_fstat(cmount, (int)j_fd, &st); + + ldout(cct, 10) << "jni: fstat exit ret " << ret << dendl; + + if (ret) { + handle_error(env, ret); + return ret; + } + + env->SetIntField(j_cephstat, cephstat_mode_fid, st.st_mode); + env->SetIntField(j_cephstat, cephstat_uid_fid, st.st_uid); + env->SetIntField(j_cephstat, cephstat_gid_fid, st.st_gid); + env->SetLongField(j_cephstat, cephstat_size_fid, st.st_size); + env->SetLongField(j_cephstat, cephstat_blksize_fid, st.st_blksize); + env->SetLongField(j_cephstat, cephstat_blocks_fid, st.st_blocks); + + time = st.st_mtim.tv_sec; + time *= 1000; + time += st.st_mtim.tv_nsec / 1000; + env->SetLongField(j_cephstat, cephstat_m_time_fid, time); + + time = st.st_atim.tv_sec; + time *= 1000; + time += st.st_atim.tv_nsec / 1000; + env->SetLongField(j_cephstat, cephstat_a_time_fid, time); + + 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 long 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::iterator it; + list 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::iterator it; + list 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_set_default_file_stripe_unit + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1set_1default_1file_1stripe_1unit + (JNIEnv *env, jclass clz, jlong j_mntp, jint j_stripe_unit) +{ + 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: set_default_file_stripe_unit: " << (int)j_stripe_unit << dendl; + + ret = ceph_set_default_file_stripe_unit(cmount, (int)j_stripe_unit); + + ldout(cct, 10) << "jni: set_default_file_stripe_unit: exit ret " << ret << dendl; + + if (ret) + handle_error(env, ret); + + return ret; +} + +/* + * Class: com_ceph_fs_CephMount + * Method: native_ceph_set_default_file_stripe_count + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1set_1default_1file_1stripe_1count + (JNIEnv *env, jclass clz, jlong j_mntp, jint j_stripe_count) +{ + 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: set_default_file_stripe_count: " << (int)j_stripe_count << dendl; + + ret = ceph_set_default_file_stripe_count(cmount, (int)j_stripe_count); + + ldout(cct, 10) << "jni: set_default_file_stripe_count: exit ret " << ret << dendl; + + if (ret) + handle_error(env, ret); + + return ret; +} + +/* + * Class: com_ceph_fs_CephMount + * Method: native_ceph_set_default_object_size + * Signature: (JI)I + */ +JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1set_1default_1object_1size + (JNIEnv *env, jclass clz, jlong j_mntp, jint j_object_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: set_default_object_size: " << (int)j_object_size << dendl; + + ret = ceph_set_default_object_size(cmount, (int)j_object_size); + + ldout(cct, 10) << "jni: set_default_object_size: exit ret " << ret << dendl; + + if (ret) + handle_error(env, ret); + + return ret; +} + +/* + * 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; +} diff --git a/src/java/test/CephMountCreateTest.java b/src/java/test/CephMountCreateTest.java new file mode 100644 index 0000000000000..1a9c48828fe27 --- /dev/null +++ b/src/java/test/CephMountCreateTest.java @@ -0,0 +1,88 @@ +/* + * 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. + */ +import java.io.FileNotFoundException; +import org.junit.*; +import static org.junit.Assert.*; + +import com.ceph.fs.*; + +/* + * 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.mount(root); + return mount; + } + + @Test + public void test_CephMountCreate() throws Exception { + CephMount mount; + boolean found; + + /* root dir has more than one dir */ + mount = setupMount(null); + + try { + mount.rmdir("/libcephfs_java_test_dir"); + } catch (FileNotFoundException e) {} + mount.mkdirs("/libcephfs_java_test_dir", 777); + String[] subdirs = mount.listdir("/"); + found = false; + for (String d : subdirs) { + if (d.compareTo("libcephfs_java_test_dir") == 0) + found = true; + } + assertTrue(found); + mount.shutdown(); + + /* changing root to empty dir */ + mount = setupMount("/libcephfs_java_test_dir"); + + subdirs = mount.listdir("/"); + found = false; + for (String d : subdirs) { + if (d.compareTo(".") != 0 && d.compareTo("..") != 0) + found = true; + } + assertFalse(found); + mount.shutdown(); + + /* cleanup */ + mount = setupMount(null); + mount.rmdir("/libcephfs_java_test_dir"); + mount.shutdown(); + } +} diff --git a/src/java/test/CephMountTest.java b/src/java/test/CephMountTest.java new file mode 100644 index 0000000000000..4f5a3e05127c1 --- /dev/null +++ b/src/java/test/CephMountTest.java @@ -0,0 +1,797 @@ +/* + * 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. + */ +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.UUID; +import org.junit.*; +import static org.junit.Assert.*; + +import com.ceph.fs.*; + +/* + * Coverage + * - Everything is covered in at least success cases. + * - link/symlink/readlink/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.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.shutdown(); + } + + /* + * Helper function to construct a unique path. + */ + public String makePath() { + String path = basedir + "/" + UUID.randomUUID(); + return path; + } + + /* + * 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 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.is_directory); + 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.is_directory); + + mount.lstat(path + "/x", st); + assertTrue(st.is_directory); + + mount.lstat(path + "/x/y", st); + assertTrue(st.is_directory); + + 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.is_directory); + /* remove it */ + mount.rmdir(path); + /* should not exist now */ + mount.lstat(path, st); + } + + /* + * Missing + * + * readlink + * symlink + */ + + /* + * 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 + */ + + @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 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); + + 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); + } + + /* + * 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); + } + + /* + * 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); + } + + /* + * 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); + 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); + } + + /* + * 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, "attr1", buf1, buf1.length, mount.XATTR_CREATE); + mount.setxattr(path, "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("attr1") == 0) { + found++; + continue; + } + if (xattr.compareTo("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, "attr1", null); + byte[] out = new byte[(int)attr1_len]; + mount.getxattr(path, "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, "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); + } + + @Test + public void test_set_def_obj_size() throws Exception { + mount.set_default_object_size(1 << 21); + } + + @Test + public void test_set_def_file_stripe_count() throws Exception { + mount.set_default_file_stripe_count(2); + } + + @Test + public void test_set_def_file_stripe_unit() throws Exception { + mount.set_default_file_stripe_unit(1 << 10); + } + +} diff --git a/src/java/test/CephUnmountedTest.java b/src/java/test/CephUnmountedTest.java new file mode 100644 index 0000000000000..7b8b7cd27bd05 --- /dev/null +++ b/src/java/test/CephUnmountedTest.java @@ -0,0 +1,143 @@ +/* + * 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. + */ +import org.junit.*; +import static org.junit.Assert.*; + +import com.ceph.fs.*; + +public class CephUnmountedTest { + + private CephMount mount; + + @Before + public void setup() throws Exception { + mount = new CephMount("admin"); + } + + @Test(expected=CephNotMountedException.class) + public void test_shutdown() throws Exception { + mount.shutdown(); + } + + @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_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_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_set_def_stripe_unit() throws Exception { + mount.set_default_file_stripe_unit(1); + } + + @Test(expected=CephNotMountedException.class) + public void test_set_def_stripe_count() throws Exception { + mount.set_default_file_stripe_count(1); + } + + @Test(expected=CephNotMountedException.class) + public void test_set_def_obj_size() throws Exception { + mount.set_default_object_size(1); + } +} -- 2.39.5