Fix some bugs when testing opensds ansible
[stor4nfv.git] / src / ceph / src / java / native / libcephfs_jni.cc
1 /*
2  * Permission is hereby granted, free of charge, to any person obtaining a
3  * copy of this software and associated documentation files (the "Software"),
4  * to deal in the Software without restriction, including without limitation
5  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
6  * and/or sell copies of the Software, and to permit persons to whom the
7  * Software is furnished to do so, subject to the following conditions:
8  *
9  * The above copyright notice and this permission notice shall be included in
10  * all copies or substantial portions of the Software.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
13  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
14  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
15  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
16  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
17  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18  * DEALINGS IN THE SOFTWARE.
19  */
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <string.h>
23 #include <errno.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <sys/un.h>
27 #include <jni.h>
28
29 #include "ScopedLocalRef.h"
30 #include "JniConstants.h"
31
32 #include "include/cephfs/libcephfs.h"
33 #include "common/dout.h"
34
35 #define dout_subsys ceph_subsys_javaclient
36
37 #include "com_ceph_fs_CephMount.h"
38
39 #define CEPH_STAT_CP "com/ceph/fs/CephStat"
40 #define CEPH_STAT_VFS_CP "com/ceph/fs/CephStatVFS"
41 #define CEPH_FILE_EXTENT_CP "com/ceph/fs/CephFileExtent"
42 #define CEPH_MOUNT_CP "com/ceph/fs/CephMount"
43 #define CEPH_NOTMOUNTED_CP "com/ceph/fs/CephNotMountedException"
44 #define CEPH_FILEEXISTS_CP "com/ceph/fs/CephFileAlreadyExistsException"
45 #define CEPH_ALREADYMOUNTED_CP "com/ceph/fs/CephAlreadyMountedException"
46 #define CEPH_NOTDIR_CP "com/ceph/fs/CephNotDirectoryException"
47
48 /*
49  * Flags to open(). must be synchronized with CephMount.java
50  *
51  * There are two versions of flags: the version in Java and the version in the
52  * target library (e.g. libc or libcephfs). We control the Java values and map
53  * to the target value with fixup_* functions below. This is much faster than
54  * keeping the values in Java and making a cross-JNI up-call to retrieve them,
55  * and makes it easy to keep any platform specific value changes in this file.
56  */
57 #define JAVA_O_RDONLY    1
58 #define JAVA_O_RDWR      2
59 #define JAVA_O_APPEND    4
60 #define JAVA_O_CREAT     8
61 #define JAVA_O_TRUNC     16
62 #define JAVA_O_EXCL      32
63 #define JAVA_O_WRONLY    64
64 #define JAVA_O_DIRECTORY 128
65
66 /*
67  * Whence flags for seek(). sync with CephMount.java if changed.
68  *
69  * Mapping of SEEK_* done in seek function.
70  */
71 #define JAVA_SEEK_SET 1
72 #define JAVA_SEEK_CUR 2
73 #define JAVA_SEEK_END 3
74
75 /*
76  * File attribute flags. sync with CephMount.java if changed.
77  */
78 #define JAVA_SETATTR_MODE  1
79 #define JAVA_SETATTR_UID   2
80 #define JAVA_SETATTR_GID   4
81 #define JAVA_SETATTR_MTIME 8
82 #define JAVA_SETATTR_ATIME 16
83
84 /*
85  * Setxattr flags. sync with CephMount.java if changed.
86  */
87 #define JAVA_XATTR_CREATE   1
88 #define JAVA_XATTR_REPLACE  2
89 #define JAVA_XATTR_NONE     3
90
91 /*
92  * flock flags. sync with CephMount.java if changed.
93  */
94 #define JAVA_LOCK_SH 1
95 #define JAVA_LOCK_EX 2
96 #define JAVA_LOCK_NB 4
97 #define JAVA_LOCK_UN 8
98
99 /* Map JAVA_O_* open flags to values in libc */
100 static inline int fixup_open_flags(jint jflags)
101 {
102         int ret = 0;
103
104 #define FIXUP_OPEN_FLAG(name) \
105         if (jflags & JAVA_##name) \
106                 ret |= name;
107
108         FIXUP_OPEN_FLAG(O_RDONLY)
109         FIXUP_OPEN_FLAG(O_RDWR)
110         FIXUP_OPEN_FLAG(O_APPEND)
111         FIXUP_OPEN_FLAG(O_CREAT)
112         FIXUP_OPEN_FLAG(O_TRUNC)
113         FIXUP_OPEN_FLAG(O_EXCL)
114         FIXUP_OPEN_FLAG(O_WRONLY)
115         FIXUP_OPEN_FLAG(O_DIRECTORY)
116
117 #undef FIXUP_OPEN_FLAG
118
119         return ret;
120 }
121
122 /* Map JAVA_SETATTR_* to values in ceph lib */
123 static inline int fixup_attr_mask(jint jmask)
124 {
125         int mask = 0;
126
127 #define FIXUP_ATTR_MASK(name) \
128         if (jmask & JAVA_##name) \
129                 mask |= CEPH_##name;
130
131         FIXUP_ATTR_MASK(SETATTR_MODE)
132         FIXUP_ATTR_MASK(SETATTR_UID)
133         FIXUP_ATTR_MASK(SETATTR_GID)
134         FIXUP_ATTR_MASK(SETATTR_MTIME)
135         FIXUP_ATTR_MASK(SETATTR_ATIME)
136
137 #undef FIXUP_ATTR_MASK
138
139         return mask;
140 }
141
142 /* Cached field IDs for com.ceph.fs.CephStat */
143 static jfieldID cephstat_mode_fid;
144 static jfieldID cephstat_uid_fid;
145 static jfieldID cephstat_gid_fid;
146 static jfieldID cephstat_size_fid;
147 static jfieldID cephstat_blksize_fid;
148 static jfieldID cephstat_blocks_fid;
149 static jfieldID cephstat_a_time_fid;
150 static jfieldID cephstat_m_time_fid;
151 static jfieldID cephstat_is_file_fid;
152 static jfieldID cephstat_is_directory_fid;
153 static jfieldID cephstat_is_symlink_fid;
154
155 /* Cached field IDs for com.ceph.fs.CephStatVFS */
156 static jfieldID cephstatvfs_bsize_fid;
157 static jfieldID cephstatvfs_frsize_fid;
158 static jfieldID cephstatvfs_blocks_fid;
159 static jfieldID cephstatvfs_bavail_fid;
160 static jfieldID cephstatvfs_files_fid;
161 static jfieldID cephstatvfs_fsid_fid;
162 static jfieldID cephstatvfs_namemax_fid;
163
164 /* Cached field IDs for com.ceph.fs.CephMount */
165 static jfieldID cephmount_instance_ptr_fid;
166
167 /* Cached field IDs for com.ceph.fs.CephFileExtent */
168 static jclass cephfileextent_cls;
169 static jmethodID cephfileextent_ctor_fid;
170
171 /*
172  * Exception throwing helper. Adapted from Apache Hadoop header
173  * org_apache_hadoop.h by adding the do {} while (0) construct.
174  */
175 #define THROW(env, exception_name, message) \
176         do { \
177                 jclass ecls = env->FindClass(exception_name); \
178                 if (ecls) { \
179                         int ret = env->ThrowNew(ecls, message); \
180                         if (ret < 0) { \
181                                 printf("(CephFS) Fatal Error\n"); \
182                         } \
183                         env->DeleteLocalRef(ecls); \
184                 } \
185         } while (0)
186
187
188 static void cephThrowNullArg(JNIEnv *env, const char *msg)
189 {
190         THROW(env, "java/lang/NullPointerException", msg);
191 }
192
193 static void cephThrowOutOfMemory(JNIEnv *env, const char *msg)
194 {
195         THROW(env, "java/lang/OutOfMemoryError", msg);
196 }
197
198 static void cephThrowInternal(JNIEnv *env, const char *msg)
199 {
200         THROW(env, "java/lang/InternalError", msg);
201 }
202
203 static void cephThrowIndexBounds(JNIEnv *env, const char *msg)
204 {
205         THROW(env, "java/lang/IndexOutOfBoundsException", msg);
206 }
207
208 static void cephThrowIllegalArg(JNIEnv *env, const char *msg)
209 {
210         THROW(env, "java/lang/IllegalArgumentException", msg);
211 }
212
213 static void cephThrowFNF(JNIEnv *env, const char *msg)
214 {
215         THROW(env, "java/io/FileNotFoundException", msg);
216 }
217
218 static void cephThrowFileExists(JNIEnv *env, const char *msg)
219 {
220         THROW(env, CEPH_FILEEXISTS_CP, msg);
221 }
222
223 static void cephThrowNotDir(JNIEnv *env, const char *msg)
224 {
225         THROW(env, CEPH_NOTDIR_CP, msg);
226 }
227
228 static void handle_error(JNIEnv *env, int rc)
229 {
230         switch (rc) {
231                 case -ENOENT:
232                         cephThrowFNF(env, "");
233                         return;
234                 case -EEXIST:
235                         cephThrowFileExists(env, "");
236                         return;
237                 case -ENOTDIR:
238                         cephThrowNotDir(env, "");
239                         return;
240                 default:
241                         break;
242         }
243
244         THROW(env, "java/io/IOException", strerror(-rc));
245 }
246
247 #define CHECK_ARG_NULL(v, m, r) do { \
248         if (!(v)) { \
249                 cephThrowNullArg(env, (m)); \
250                 return (r); \
251         } } while (0)
252
253 #define CHECK_ARG_BOUNDS(c, m, r) do { \
254         if ((c)) { \
255                 cephThrowIndexBounds(env, (m)); \
256                 return (r); \
257         } } while (0)
258
259 #define CHECK_MOUNTED(_c, _r) do { \
260         if (!ceph_is_mounted((_c))) { \
261                 THROW(env, CEPH_NOTMOUNTED_CP, "not mounted"); \
262                 return (_r); \
263         } } while (0)
264
265 /*
266  * Cast a jlong to ceph_mount_info. Each JNI function is expected to pass in
267  * the class instance variable instance_ptr. Passing a parameter is faster
268  * than reaching back into Java via an upcall to retreive this pointer.
269  */
270 static inline struct ceph_mount_info *get_ceph_mount(jlong j_mntp)
271 {
272         return (struct ceph_mount_info *)j_mntp;
273 }
274
275 /*
276  * Setup cached field IDs
277  */
278 static void setup_field_ids(JNIEnv *env, jclass clz)
279 {
280         jclass cephstat_cls;
281         jclass cephstatvfs_cls;
282         jclass tmp_cephfileextent_cls;
283
284 /*
285  * Get a fieldID from a class with a specific type
286  *
287  * clz: jclass
288  * field: field in clz
289  * type: integer, long, etc..
290  *
291  * This macro assumes some naming convention that is used
292  * only in this file:
293  *
294  *   GETFID(cephstat, mode, I) gets translated into
295  *     cephstat_mode_fid = env->GetFieldID(cephstat_cls, "mode", "I");
296  */
297 #define GETFID(clz, field, type) do { \
298         clz ## _ ## field ## _fid = env->GetFieldID(clz ## _cls, #field, #type); \
299         if ( ! clz ## _ ## field ## _fid ) \
300                 return; \
301         } while (0)
302
303         /* Cache CephStat fields */
304
305         cephstat_cls = env->FindClass(CEPH_STAT_CP);
306         if (!cephstat_cls)
307                 return;
308
309         GETFID(cephstat, mode, I);
310         GETFID(cephstat, uid, I);
311         GETFID(cephstat, gid, I);
312         GETFID(cephstat, size, J);
313         GETFID(cephstat, blksize, J);
314         GETFID(cephstat, blocks, J);
315         GETFID(cephstat, a_time, J);
316         GETFID(cephstat, m_time, J);
317         GETFID(cephstat, is_file, Z);
318         GETFID(cephstat, is_directory, Z);
319         GETFID(cephstat, is_symlink, Z);
320
321         /* Cache CephStatVFS fields */
322
323         cephstatvfs_cls = env->FindClass(CEPH_STAT_VFS_CP);
324         if (!cephstatvfs_cls)
325                 return;
326
327         GETFID(cephstatvfs, bsize, J);
328         GETFID(cephstatvfs, frsize, J);
329         GETFID(cephstatvfs, blocks, J);
330         GETFID(cephstatvfs, bavail, J);
331         GETFID(cephstatvfs, files, J);
332         GETFID(cephstatvfs, fsid, J);
333         GETFID(cephstatvfs, namemax, J);
334
335         /* Cache CephFileExtent fields */
336
337         tmp_cephfileextent_cls = env->FindClass(CEPH_FILE_EXTENT_CP);
338         if (!tmp_cephfileextent_cls)
339                 return;
340
341         cephfileextent_cls = (jclass)env->NewGlobalRef(tmp_cephfileextent_cls);
342         env->DeleteLocalRef(tmp_cephfileextent_cls);
343
344         cephfileextent_ctor_fid = env->GetMethodID(cephfileextent_cls, "<init>", "(JJ[I)V");
345         if (!cephfileextent_ctor_fid)
346                 return;
347
348   JniConstants::init(env);
349
350 #undef GETFID
351
352         cephmount_instance_ptr_fid = env->GetFieldID(clz, "instance_ptr", "J");
353 }
354
355
356 /*
357  * Class:     com_ceph_fs_CephMount
358  * Method:    native_initialize
359  * Signature: ()V
360  */
361 JNIEXPORT void JNICALL Java_com_ceph_fs_CephMount_native_1initialize
362         (JNIEnv *env, jclass clz)
363 {
364         setup_field_ids(env, clz);
365 }
366
367 /*
368  * Class:     com_ceph_fs_CephMount
369  * Method:    native_ceph_create
370  * Signature: (Lcom/ceph/fs/CephMount;Ljava/lang/String;)I
371  */
372 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1create
373         (JNIEnv *env, jclass clz, jobject j_cephmount, jstring j_id)
374 {
375         struct ceph_mount_info *cmount;
376         const char *c_id = NULL;
377         int ret;
378
379         CHECK_ARG_NULL(j_cephmount, "@mount is null", -1);
380
381         if (j_id) {
382                 c_id = env->GetStringUTFChars(j_id, NULL);
383                 if (!c_id) {
384                         cephThrowInternal(env, "Failed to pin memory");
385                         return -1;
386                 }
387         }
388
389         ret = ceph_create(&cmount, c_id);
390
391         if (c_id)
392                 env->ReleaseStringUTFChars(j_id, c_id);
393
394         if (ret) {
395                 THROW(env, "java/lang/RuntimeException", "failed to create Ceph mount object");
396                 return ret;
397         }
398
399         env->SetLongField(j_cephmount, cephmount_instance_ptr_fid, (long)cmount);
400
401         return ret;
402 }
403
404 /*
405  * Class:     com_ceph_fs_CephMount
406  * Method:    native_ceph_mount
407  * Signature: (JLjava/lang/String;)I
408  */
409 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mount
410         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_root)
411 {
412         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
413         CephContext *cct = ceph_get_mount_context(cmount);
414         const char *c_root = NULL;
415         int ret;
416
417         /*
418          * Toss a message up if we are already mounted.
419          */
420         if (ceph_is_mounted(cmount)) {
421                 THROW(env, CEPH_ALREADYMOUNTED_CP, "");
422                 return -1;
423         }
424
425         if (j_root) {
426                 c_root = env->GetStringUTFChars(j_root, NULL);
427                 if (!c_root) {
428                         cephThrowInternal(env, "Failed to pin memory");
429                         return -1;
430                 }
431         }
432
433         ldout(cct, 10) << "jni: ceph_mount: " << (c_root ? c_root : "<NULL>") << dendl;
434
435         ret = ceph_mount(cmount, c_root);
436
437         ldout(cct, 10) << "jni: ceph_mount: exit ret " << ret << dendl;
438
439         if (c_root)
440                 env->ReleaseStringUTFChars(j_root, c_root);
441
442         if (ret)
443                 handle_error(env, ret);
444
445         return ret;
446 }
447
448 /*
449  * Class:     com_ceph_fs_CephMount
450  * Method:    native_ceph_unmount
451  * Signature: (J)I
452  */
453 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unmount
454   (JNIEnv *env, jclass clz, jlong j_mntp)
455 {
456         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
457         CephContext *cct = ceph_get_mount_context(cmount);
458         int ret;
459
460         ldout(cct, 10) << "jni: ceph_unmount enter" << dendl;
461
462         CHECK_MOUNTED(cmount, -1);
463
464         ret = ceph_unmount(cmount);
465
466         ldout(cct, 10) << "jni: ceph_unmount exit ret " << ret << dendl;
467
468         if (ret)
469                 handle_error(env, ret);
470
471         return ret;
472 }
473
474 /*
475  * Class:     com_ceph_fs_CephMount
476  * Method:    native_ceph_release
477  * Signature: (J)I
478  */
479 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1release
480   (JNIEnv *env, jclass clz, jlong j_mntp)
481 {
482         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
483         CephContext *cct = ceph_get_mount_context(cmount);
484         int ret;
485
486         ldout(cct, 10) << "jni: ceph_release called" << dendl;
487
488         ret = ceph_release(cmount);
489
490         if (ret)
491                 handle_error(env, ret);
492
493         return ret;
494 }
495
496 /*
497  * Class:     com_ceph_fs_CephMount
498  * Method:    native_ceph_conf_set
499  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
500  */
501 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1set
502         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt, jstring j_val)
503 {
504         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
505         CephContext *cct = ceph_get_mount_context(cmount);
506         const char *c_opt, *c_val;
507         int ret;
508
509         CHECK_ARG_NULL(j_opt, "@option is null", -1);
510         CHECK_ARG_NULL(j_val, "@value is null", -1);
511
512         c_opt = env->GetStringUTFChars(j_opt, NULL);
513         if (!c_opt) {
514                 cephThrowInternal(env, "failed to pin memory");
515                 return -1;
516         }
517
518         c_val = env->GetStringUTFChars(j_val, NULL);
519         if (!c_val) {
520                 env->ReleaseStringUTFChars(j_opt, c_opt);
521                 cephThrowInternal(env, "failed to pin memory");
522                 return -1;
523         }
524
525         ldout(cct, 10) << "jni: conf_set: opt " << c_opt << " val " << c_val << dendl;
526
527         ret = ceph_conf_set(cmount, c_opt, c_val);
528
529         ldout(cct, 10) << "jni: conf_set: exit ret " << ret << dendl;
530
531         env->ReleaseStringUTFChars(j_opt, c_opt);
532         env->ReleaseStringUTFChars(j_val, c_val);
533
534         if (ret)
535                 handle_error(env, ret);
536
537         return ret;
538 }
539
540 /*
541  * Class:     com_ceph_fs_CephMount
542  * Method:    native_ceph_conf_get
543  * Signature: (JLjava/lang/String;)Ljava/lang/String;
544  */
545 JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1get
546         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_opt)
547 {
548         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
549         CephContext *cct = ceph_get_mount_context(cmount);
550         const char *c_opt;
551         jstring value = NULL;
552         int ret, buflen;
553         char *buf;
554
555         CHECK_ARG_NULL(j_opt, "@option is null", NULL);
556
557         c_opt = env->GetStringUTFChars(j_opt, NULL);
558         if (!c_opt) {
559                 cephThrowInternal(env, "failed to pin memory");
560                 return NULL;
561         }
562
563         buflen = 128;
564         buf = new (std::nothrow) char[buflen];
565         if (!buf) {
566                 cephThrowOutOfMemory(env, "head allocation failed");
567                 goto out;
568         }
569
570         while (1) {
571                 memset(buf, 0, sizeof(char)*buflen);
572                 ldout(cct, 10) << "jni: conf_get: opt " << c_opt << " len " << buflen << dendl;
573                 ret = ceph_conf_get(cmount, c_opt, buf, buflen);
574                 if (ret == -ENAMETOOLONG) {
575                         buflen *= 2;
576                         delete [] buf;
577                         buf = new (std::nothrow) char[buflen];
578                         if (!buf) {
579                                 cephThrowOutOfMemory(env, "head allocation failed");
580                                 goto out;
581                         }
582                 } else
583                         break;
584         }
585
586         ldout(cct, 10) << "jni: conf_get: ret " << ret << dendl;
587
588         if (ret == 0)
589                 value = env->NewStringUTF(buf);
590         else if (ret != -ENOENT)
591                 handle_error(env, ret);
592
593         delete [] buf;
594
595 out:
596         env->ReleaseStringUTFChars(j_opt, c_opt);
597         return value;
598 }
599
600 /*
601  * Class:     com_ceph_fs_CephMount
602  * Method:    native_ceph_conf_read_file
603  * Signature: (JLjava/lang/String;)I
604  */
605 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1conf_1read_1file
606         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
607 {
608         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
609         CephContext *cct = ceph_get_mount_context(cmount);
610         const char *c_path;
611         int ret;
612
613         CHECK_ARG_NULL(j_path, "@path is null", -1);
614
615         c_path = env->GetStringUTFChars(j_path, NULL);
616         if (!c_path) {
617                 cephThrowInternal(env, "failed to pin memory");
618                 return -1;
619         }
620
621         ldout(cct, 10) << "jni: conf_read_file: path " << c_path << dendl;
622
623         ret = ceph_conf_read_file(cmount, c_path);
624
625         ldout(cct, 10) << "jni: conf_read_file: exit ret " << ret << dendl;
626
627         env->ReleaseStringUTFChars(j_path, c_path);
628
629         if (ret)
630                 handle_error(env, ret);
631
632         return ret;
633 }
634
635 /*
636  * Class:     com_ceph_fs_CephMount
637  * Method:    native_ceph_statfs
638  * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStatVFS;)I
639  */
640 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1statfs
641         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstatvfs)
642 {
643         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
644         CephContext *cct = ceph_get_mount_context(cmount);
645         const char *c_path;
646         struct statvfs st;
647         int ret;
648
649         CHECK_ARG_NULL(j_path, "@path is null", -1);
650         CHECK_ARG_NULL(j_cephstatvfs, "@stat is null", -1);
651         CHECK_MOUNTED(cmount, -1);
652
653         c_path = env->GetStringUTFChars(j_path, NULL);
654         if (!c_path) {
655                 cephThrowInternal(env, "Failed to pin memory");
656                 return -1;
657         }
658
659         ldout(cct, 10) << "jni: statfs: path " << c_path << dendl;
660
661         ret = ceph_statfs(cmount, c_path, &st);
662
663         ldout(cct, 10) << "jni: statfs: exit ret " << ret << dendl;
664
665         env->ReleaseStringUTFChars(j_path, c_path);
666
667         if (ret) {
668                 handle_error(env, ret);
669                 return ret;
670         }
671
672         env->SetLongField(j_cephstatvfs, cephstatvfs_bsize_fid, st.f_bsize);
673         env->SetLongField(j_cephstatvfs, cephstatvfs_frsize_fid, st.f_frsize);
674         env->SetLongField(j_cephstatvfs, cephstatvfs_blocks_fid, st.f_blocks);
675         env->SetLongField(j_cephstatvfs, cephstatvfs_bavail_fid, st.f_bavail);
676         env->SetLongField(j_cephstatvfs, cephstatvfs_files_fid, st.f_files);
677         env->SetLongField(j_cephstatvfs, cephstatvfs_fsid_fid, st.f_fsid);
678         env->SetLongField(j_cephstatvfs, cephstatvfs_namemax_fid, st.f_namemax);
679
680         return ret;
681 }
682
683 /*
684  * Class:     com_ceph_fs_CephMount
685  * Method:    native_ceph_getcwd
686  * Signature: (J)Ljava/lang/String;
687  */
688 JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getcwd
689         (JNIEnv *env, jclass clz, jlong j_mntp)
690 {
691         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
692         CephContext *cct = ceph_get_mount_context(cmount);
693         const char *c_cwd;
694
695         CHECK_MOUNTED(cmount, NULL);
696
697         ldout(cct, 10) << "jni: getcwd: enter" << dendl;
698
699         c_cwd = ceph_getcwd(cmount);
700         if (!c_cwd) {
701                 cephThrowOutOfMemory(env, "ceph_getcwd");
702                 return NULL;
703         }
704
705         ldout(cct, 10) << "jni: getcwd: exit ret " << c_cwd << dendl;
706
707         return env->NewStringUTF(c_cwd);
708 }
709
710 /*
711  * Class:     com_ceph_fs_CephMount
712  * Method:    native_ceph_chdir
713  * Signature: (JLjava/lang/String;)I
714  */
715 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chdir
716         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
717 {
718         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
719         CephContext *cct = ceph_get_mount_context(cmount);
720         const char *c_path;
721         int ret;
722
723         CHECK_ARG_NULL(j_path, "@path is null", -1);
724         CHECK_MOUNTED(cmount, -1);
725
726         c_path = env->GetStringUTFChars(j_path, NULL);
727         if (!c_path) {
728                 cephThrowInternal(env, "failed to pin memory");
729                 return -1;
730         }
731
732         ldout(cct, 10) << "jni: chdir: path " << c_path << dendl;
733
734         ret = ceph_chdir(cmount, c_path);
735
736         ldout(cct, 10) << "jni: chdir: exit ret " << ret << dendl;
737
738         env->ReleaseStringUTFChars(j_path, c_path);
739
740         if (ret)
741                 handle_error(env, ret);
742
743         return ret;
744 }
745
746 /*
747  * Class:     com_ceph_fs_CephMount
748  * Method:    native_ceph_listdir
749  * Signature: (JLjava/lang/String;)[Ljava/lang/String;
750  */
751 JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listdir
752         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
753 {
754         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
755         CephContext *cct = ceph_get_mount_context(cmount);
756         struct ceph_dir_result *dirp;
757         list<string>::iterator it;
758         list<string> contents;
759         const char *c_path;
760         jobjectArray dirlist;
761         string *ent;
762         int ret, buflen, bufpos, i;
763         jstring name;
764         char *buf;
765
766         CHECK_ARG_NULL(j_path, "@path is null", NULL);
767         CHECK_MOUNTED(cmount, NULL);
768
769         c_path = env->GetStringUTFChars(j_path, NULL);
770         if (!c_path) {
771                 cephThrowInternal(env, "failed to pin memory");
772                 return NULL;
773         }
774
775         ldout(cct, 10) << "jni: listdir: opendir: path " << c_path << dendl;
776
777         /* ret < 0 also includes -ENOTDIR which should return NULL */
778         ret = ceph_opendir(cmount, c_path, &dirp);
779         if (ret) {
780                 env->ReleaseStringUTFChars(j_path, c_path);
781                 handle_error(env, ret);
782                 return NULL;
783         }
784
785         ldout(cct, 10) << "jni: listdir: opendir: exit ret " << ret << dendl;
786
787         /* buffer for ceph_getdnames() results */
788         buflen = 256;
789         buf = new (std::nothrow) char[buflen];
790         if (!buf)  {
791                 cephThrowOutOfMemory(env, "heap allocation failed");
792                 goto out;
793         }
794
795         while (1) {
796                 ldout(cct, 10) << "jni: listdir: getdnames: enter" << dendl;
797                 ret = ceph_getdnames(cmount, dirp, buf, buflen);
798                 if (ret == -ERANGE) {
799                         delete [] buf;
800                         buflen *= 2;
801                         buf = new (std::nothrow) char[buflen];
802                         if (!buf)  {
803                                 cephThrowOutOfMemory(env, "heap allocation failed");
804                                 goto out;
805                         }
806                         continue;
807                 }
808
809                 ldout(cct, 10) << "jni: listdir: getdnames: exit ret " << ret << dendl;
810
811                 if (ret <= 0)
812                         break;
813
814                 /* got at least one name */
815                 bufpos = 0;
816                 while (bufpos < ret) {
817                         ent = new (std::nothrow) string(buf + bufpos);
818                         if (!ent) {
819                                 delete [] buf;
820                                 cephThrowOutOfMemory(env, "heap allocation failed");
821                                 goto out;
822                         }
823
824                         /* filter out dot files: xref: java.io.File::list() */
825                         if (ent->compare(".") && ent->compare("..")) {
826                                 contents.push_back(*ent);
827                                 ldout(cct, 20) << "jni: listdir: take path " << *ent << dendl;
828                         }
829
830                         bufpos += ent->size() + 1;
831                         delete ent;
832                 }
833         }
834
835         delete [] buf;
836
837         if (ret < 0) {
838                 handle_error(env, ret);
839                 goto out;
840         }
841
842         /* directory list */
843         dirlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
844         if (!dirlist)
845                 goto out;
846
847         /*
848         * Fill directory listing array.
849         *
850         * FIXME: how should a partially filled array be cleaned-up properly?
851         */
852         for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
853                 name = env->NewStringUTF(it->c_str());
854                 if (!name)
855                         goto out;
856                 env->SetObjectArrayElement(dirlist, i++, name);
857                 if (env->ExceptionOccurred())
858                         goto out;
859                 env->DeleteLocalRef(name);
860         }
861
862         env->ReleaseStringUTFChars(j_path, c_path);
863         ceph_closedir(cmount, dirp);
864
865         return dirlist;
866
867 out:
868         env->ReleaseStringUTFChars(j_path, c_path);
869         ceph_closedir(cmount, dirp);
870         return NULL;
871 }
872
873 /*
874  * Class:     com_ceph_fs_CephMount
875  * Method:    native_ceph_link
876  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
877  */
878 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1link
879         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath)
880 {
881         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
882         CephContext *cct = ceph_get_mount_context(cmount);
883         const char *c_oldpath, *c_newpath;
884         int ret;
885
886         CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1);
887         CHECK_ARG_NULL(j_newpath, "@newpath is null", -1);
888         CHECK_MOUNTED(cmount, -1);
889
890         c_oldpath = env->GetStringUTFChars(j_oldpath, NULL);
891         if (!c_oldpath) {
892                 cephThrowInternal(env, "failed to pin memory");
893                 return -1;
894         }
895
896         c_newpath = env->GetStringUTFChars(j_newpath, NULL);
897         if (!c_newpath) {
898                 env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
899                 cephThrowInternal(env, "failed to pin memory");
900                 return -1;
901         }
902
903         ldout(cct, 10) << "jni: link: oldpath " << c_oldpath <<
904                 " newpath " << c_newpath << dendl;
905
906         ret = ceph_link(cmount, c_oldpath, c_newpath);
907
908         ldout(cct, 10) << "jni: link: exit ret " << ret << dendl;
909
910         env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
911         env->ReleaseStringUTFChars(j_newpath, c_newpath);
912
913         if (ret)
914                 handle_error(env, ret);
915
916         return ret;
917 }
918
919 /*
920  * Class:     com_ceph_fs_CephMount
921  * Method:    native_ceph_unlink
922  * Signature: (JLjava/lang/String;)I
923  */
924 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1unlink
925         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
926 {
927         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
928         CephContext *cct = ceph_get_mount_context(cmount);
929         const char *c_path;
930         int ret;
931
932         CHECK_ARG_NULL(j_path, "@path is null", -1);
933         CHECK_MOUNTED(cmount, -1);
934
935         c_path = env->GetStringUTFChars(j_path, NULL);
936         if (!c_path) {
937                 cephThrowInternal(env, "failed to pin memory");
938                 return -1;
939         }
940
941         ldout(cct, 10) << "jni: unlink: path " << c_path << dendl;
942
943         ret = ceph_unlink(cmount, c_path);
944
945         ldout(cct, 10) << "jni: unlink: exit ret " << ret << dendl;
946
947         env->ReleaseStringUTFChars(j_path, c_path);
948
949         if (ret)
950                 handle_error(env, ret);
951
952         return ret;
953 }
954
955 /*
956  * Class:     com_ceph_fs_CephMount
957  * Method:    native_ceph_rename
958  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
959  */
960 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rename
961         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_from, jstring j_to)
962 {
963         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
964         CephContext *cct = ceph_get_mount_context(cmount);
965         const char *c_from, *c_to;
966         int ret;
967
968         CHECK_ARG_NULL(j_from, "@from is null", -1);
969         CHECK_ARG_NULL(j_to, "@to is null", -1);
970         CHECK_MOUNTED(cmount, -1);
971
972         c_from = env->GetStringUTFChars(j_from, NULL);
973         if (!c_from) {
974                 cephThrowInternal(env, "Failed to pin memory!");
975                 return -1;
976         }
977
978         c_to = env->GetStringUTFChars(j_to, NULL);
979         if (!c_to) {
980                 env->ReleaseStringUTFChars(j_from, c_from);
981                 cephThrowInternal(env, "Failed to pin memory.");
982                 return -1;
983         }
984
985         ldout(cct, 10) << "jni: rename: from " << c_from << " to " << c_to << dendl;
986
987         ret = ceph_rename(cmount, c_from, c_to);
988
989         ldout(cct, 10) << "jni: rename: exit ret " << ret << dendl;
990
991         env->ReleaseStringUTFChars(j_from, c_from);
992         env->ReleaseStringUTFChars(j_to, c_to);
993
994         if (ret)
995                 handle_error(env, ret);
996
997         return ret;
998 }
999
1000 /*
1001  * Class:     com_ceph_fs_CephMount
1002  * Method:    native_ceph_mkdir
1003  * Signature: (JLjava/lang/String;I)I
1004  */
1005 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdir
1006         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
1007 {
1008         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1009         CephContext *cct = ceph_get_mount_context(cmount);
1010         const char *c_path;
1011         int ret;
1012
1013         CHECK_ARG_NULL(j_path, "@path is null", -1);
1014         CHECK_MOUNTED(cmount, -1);
1015
1016         c_path = env->GetStringUTFChars(j_path, NULL);
1017         if (!c_path) {
1018                 cephThrowInternal(env, "failed to pin memory");
1019                 return -1;
1020         }
1021
1022         ldout(cct, 10) << "jni: mkdir: path " << c_path << " mode " << (int)j_mode << dendl;
1023
1024         ret = ceph_mkdir(cmount, c_path, (int)j_mode);
1025
1026         ldout(cct, 10) << "jni: mkdir: exit ret " << ret << dendl;
1027
1028         env->ReleaseStringUTFChars(j_path, c_path);
1029
1030         if (ret)
1031                 handle_error(env, ret);
1032
1033         return ret;
1034 }
1035
1036 /*
1037  * Class:     com_ceph_fs_CephMount
1038  * Method:    native_ceph_mkdirs
1039  * Signature: (JLjava/lang/String;I)I
1040  */
1041 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1mkdirs
1042         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
1043 {
1044         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1045         CephContext *cct = ceph_get_mount_context(cmount);
1046         const char *c_path;
1047         int ret;
1048
1049         CHECK_ARG_NULL(j_path, "@path is null", -1);
1050         CHECK_MOUNTED(cmount, -1);
1051
1052         c_path = env->GetStringUTFChars(j_path, NULL);
1053         if (!c_path) {
1054                 cephThrowInternal(env, "failed to pin memory");
1055                 return -1;
1056         }
1057
1058         ldout(cct, 10) << "jni: mkdirs: path " << c_path << " mode " << (int)j_mode << dendl;
1059
1060         ret = ceph_mkdirs(cmount, c_path, (int)j_mode);
1061
1062         ldout(cct, 10) << "jni: mkdirs: exit ret " << ret << dendl;
1063
1064         env->ReleaseStringUTFChars(j_path, c_path);
1065
1066         if (ret)
1067                 handle_error(env, ret);
1068
1069         return ret;
1070 }
1071
1072 /*
1073  * Class:     com_ceph_fs_CephMount
1074  * Method:    native_ceph_rmdir
1075  * Signature: (JLjava/lang/String;)I
1076  */
1077 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1rmdir
1078         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
1079 {
1080         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1081         CephContext *cct = ceph_get_mount_context(cmount);
1082         const char *c_path;
1083         int ret;
1084
1085         CHECK_ARG_NULL(j_path, "@path is null", -1);
1086         CHECK_MOUNTED(cmount, -1);
1087
1088         c_path = env->GetStringUTFChars(j_path, NULL);
1089         if (!c_path) {
1090                 cephThrowInternal(env, "failed to pin memory");
1091                 return -1;
1092         }
1093
1094         ldout(cct, 10) << "jni: rmdir: path " << c_path << dendl;
1095
1096         ret = ceph_rmdir(cmount, c_path);
1097
1098         ldout(cct, 10) << "jni: rmdir: exit ret " << ret << dendl;
1099
1100         env->ReleaseStringUTFChars(j_path, c_path);
1101
1102         if (ret)
1103                 handle_error(env, ret);
1104
1105         return ret;
1106 }
1107
1108 /*
1109  * Class:     com_ceph_fs_CephMount
1110  * Method:    native_ceph_readlink
1111  * Signature: (JLjava/lang/String;)Ljava/lang/String;
1112  */
1113 JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1readlink
1114   (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
1115 {
1116         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1117         CephContext *cct = ceph_get_mount_context(cmount);
1118         const char *c_path;
1119         char *linkname;
1120         struct ceph_statx stx;
1121         jstring j_linkname;
1122
1123         CHECK_ARG_NULL(j_path, "@path is null", NULL);
1124         CHECK_MOUNTED(cmount, NULL);
1125
1126         c_path = env->GetStringUTFChars(j_path, NULL);
1127         if (!c_path) {
1128                 cephThrowInternal(env, "failed to pin memory");
1129                 return NULL;
1130         }
1131
1132         for (;;) {
1133                 ldout(cct, 10) << "jni: readlink: lstatx " << c_path << dendl;
1134                 int ret = ceph_statx(cmount, c_path, &stx, CEPH_STATX_SIZE,
1135                                      AT_SYMLINK_NOFOLLOW);
1136                 ldout(cct, 10) << "jni: readlink: lstat exit ret " << ret << dendl;
1137                 if (ret) {
1138                         env->ReleaseStringUTFChars(j_path, c_path);
1139                         handle_error(env, ret);
1140                         return NULL;
1141                 }
1142
1143                 linkname = new (std::nothrow) char[stx.stx_size + 1];
1144                 if (!linkname) {
1145                         env->ReleaseStringUTFChars(j_path, c_path);
1146                         cephThrowOutOfMemory(env, "head allocation failed");
1147                         return NULL;
1148                 }
1149
1150                 ldout(cct, 10) << "jni: readlink: size " << stx.stx_size << " path " << c_path << dendl;
1151
1152                 ret = ceph_readlink(cmount, c_path, linkname, stx.stx_size + 1);
1153
1154                 ldout(cct, 10) << "jni: readlink: exit ret " << ret << dendl;
1155
1156                 if (ret < 0) {
1157                         delete [] linkname;
1158                         env->ReleaseStringUTFChars(j_path, c_path);
1159                         handle_error(env, ret);
1160                         return NULL;
1161                 }
1162
1163                 /* re-stat and try again */
1164                 if (ret > (int)stx.stx_size) {
1165                         delete [] linkname;
1166                         continue;
1167                 }
1168
1169                 linkname[ret] = '\0';
1170                 break;
1171         }
1172
1173         env->ReleaseStringUTFChars(j_path, c_path);
1174
1175         j_linkname = env->NewStringUTF(linkname);
1176         delete [] linkname;
1177
1178         return j_linkname;
1179 }
1180
1181 /*
1182  * Class:     com_ceph_fs_CephMount
1183  * Method:    native_ceph_symlink
1184  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
1185  */
1186 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1symlink
1187         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_oldpath, jstring j_newpath)
1188 {
1189         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1190         CephContext *cct = ceph_get_mount_context(cmount);
1191         const char *c_oldpath, *c_newpath;
1192         int ret;
1193
1194         CHECK_ARG_NULL(j_oldpath, "@oldpath is null", -1);
1195         CHECK_ARG_NULL(j_newpath, "@newpath is null", -1);
1196         CHECK_MOUNTED(cmount, -1);
1197
1198         c_oldpath = env->GetStringUTFChars(j_oldpath, NULL);
1199         if (!c_oldpath) {
1200                 cephThrowInternal(env, "failed to pin memory");
1201                 return -1;
1202         }
1203
1204         c_newpath = env->GetStringUTFChars(j_newpath, NULL);
1205         if (!c_newpath) {
1206                 env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
1207                 cephThrowInternal(env, "failed to pin memory");
1208                 return -1;
1209         }
1210
1211         ldout(cct, 10) << "jni: symlink: oldpath " << c_oldpath <<
1212                 " newpath " << c_newpath << dendl;
1213
1214         ret = ceph_symlink(cmount, c_oldpath, c_newpath);
1215
1216         ldout(cct, 10) << "jni: symlink: exit ret " << ret << dendl;
1217
1218         env->ReleaseStringUTFChars(j_oldpath, c_oldpath);
1219         env->ReleaseStringUTFChars(j_newpath, c_newpath);
1220
1221         if (ret)
1222                 handle_error(env, ret);
1223
1224         return ret;
1225 }
1226
1227 #define CEPH_J_CEPHSTAT_MASK (CEPH_STATX_UID|CEPH_STATX_GID|CEPH_STATX_SIZE|CEPH_STATX_BLOCKS|CEPH_STATX_MTIME|CEPH_STATX_ATIME)
1228
1229 static void fill_cephstat(JNIEnv *env, jobject j_cephstat, struct ceph_statx *stx)
1230 {
1231         env->SetIntField(j_cephstat, cephstat_mode_fid, stx->stx_mode);
1232         env->SetIntField(j_cephstat, cephstat_uid_fid, stx->stx_uid);
1233         env->SetIntField(j_cephstat, cephstat_gid_fid, stx->stx_gid);
1234         env->SetLongField(j_cephstat, cephstat_size_fid, stx->stx_size);
1235         env->SetLongField(j_cephstat, cephstat_blksize_fid, stx->stx_blksize);
1236         env->SetLongField(j_cephstat, cephstat_blocks_fid, stx->stx_blocks);
1237
1238         long long time = stx->stx_mtime.tv_sec;
1239         time *= 1000;
1240         time += stx->stx_mtime.tv_nsec / 1000000;
1241         env->SetLongField(j_cephstat, cephstat_m_time_fid, time);
1242
1243         time = stx->stx_atime.tv_sec;
1244         time *= 1000;
1245         time += stx->stx_atime.tv_nsec / 1000000;
1246         env->SetLongField(j_cephstat, cephstat_a_time_fid, time);
1247
1248         env->SetBooleanField(j_cephstat, cephstat_is_file_fid,
1249                         S_ISREG(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
1250
1251         env->SetBooleanField(j_cephstat, cephstat_is_directory_fid,
1252                         S_ISDIR(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
1253
1254         env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid,
1255                         S_ISLNK(stx->stx_mode) ? JNI_TRUE : JNI_FALSE);
1256 }
1257
1258 /*
1259  * Class:     com_ceph_fs_CephMount
1260  * Method:    native_ceph_lstat
1261  * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I
1262  */
1263 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lstat
1264         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat)
1265 {
1266         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1267         CephContext *cct = ceph_get_mount_context(cmount);
1268         const char *c_path;
1269         struct ceph_statx stx;
1270         int ret;
1271
1272         CHECK_ARG_NULL(j_path, "@path is null", -1);
1273         CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
1274         CHECK_MOUNTED(cmount, -1);
1275
1276         c_path = env->GetStringUTFChars(j_path, NULL);
1277         if (!c_path) {
1278                 cephThrowInternal(env, "Failed to pin memory");
1279                 return -1;
1280         }
1281
1282         ldout(cct, 10) << "jni: lstat: path " << c_path << dendl;
1283
1284         ret = ceph_statx(cmount, c_path, &stx, CEPH_J_CEPHSTAT_MASK, AT_SYMLINK_NOFOLLOW);
1285
1286         ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl;
1287
1288         env->ReleaseStringUTFChars(j_path, c_path);
1289
1290         if (ret) {
1291             handle_error(env, ret);
1292             return ret;
1293         }
1294
1295         fill_cephstat(env, j_cephstat, &stx);
1296
1297         return ret;
1298 }
1299
1300 /*
1301  * Class:     com_ceph_fs_CephMount
1302  * Method:    native_ceph_stat
1303  * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I
1304  */
1305 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1stat
1306         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat)
1307 {
1308         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1309         CephContext *cct = ceph_get_mount_context(cmount);
1310         const char *c_path;
1311         struct ceph_statx stx;
1312         int ret;
1313
1314         CHECK_ARG_NULL(j_path, "@path is null", -1);
1315         CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
1316         CHECK_MOUNTED(cmount, -1);
1317
1318         c_path = env->GetStringUTFChars(j_path, NULL);
1319         if (!c_path) {
1320                 cephThrowInternal(env, "Failed to pin memory");
1321                 return -1;
1322         }
1323
1324         ldout(cct, 10) << "jni: lstat: path " << c_path << dendl;
1325
1326         ret = ceph_statx(cmount, c_path, &stx, CEPH_J_CEPHSTAT_MASK, 0);
1327
1328         ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl;
1329
1330         env->ReleaseStringUTFChars(j_path, c_path);
1331
1332         if (ret) {
1333                 handle_error(env, ret);
1334                 return ret;
1335         }
1336
1337         fill_cephstat(env, j_cephstat, &stx);
1338
1339         return ret;
1340 }
1341
1342 /*
1343  * Class:     com_ceph_fs_CephMount
1344  * Method:    native_ceph_setattr
1345  * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;I)I
1346  */
1347 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setattr
1348         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat, jint j_mask)
1349 {
1350         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1351         CephContext *cct = ceph_get_mount_context(cmount);
1352         const char *c_path;
1353         struct ceph_statx stx;
1354         int ret, mask = fixup_attr_mask(j_mask);
1355
1356         CHECK_ARG_NULL(j_path, "@path is null", -1);
1357         CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
1358         CHECK_MOUNTED(cmount, -1);
1359
1360         c_path = env->GetStringUTFChars(j_path, NULL);
1361         if (!c_path) {
1362                 cephThrowInternal(env, "Failed to pin memory");
1363                 return -1;
1364         }
1365
1366         memset(&stx, 0, sizeof(stx));
1367
1368         stx.stx_mode = env->GetIntField(j_cephstat, cephstat_mode_fid);
1369         stx.stx_uid = env->GetIntField(j_cephstat, cephstat_uid_fid);
1370         stx.stx_gid = env->GetIntField(j_cephstat, cephstat_gid_fid);
1371         stx.stx_mtime.tv_sec = env->GetLongField(j_cephstat, cephstat_m_time_fid);
1372         stx.stx_atime.tv_sec = env->GetLongField(j_cephstat, cephstat_a_time_fid);
1373
1374         ldout(cct, 10) << "jni: setattr: path " << c_path << " mask " << mask << dendl;
1375
1376         ret = ceph_setattrx(cmount, c_path, &stx, mask, 0);
1377
1378         ldout(cct, 10) << "jni: setattr: exit ret " << ret << dendl;
1379
1380         env->ReleaseStringUTFChars(j_path, c_path);
1381
1382         if (ret)
1383                 handle_error(env, ret);
1384
1385         return ret;
1386 }
1387
1388 /*
1389  * Class:     com_ceph_fs_CephMount
1390  * Method:    native_ceph_chmod
1391  * Signature: (JLjava/lang/String;I)I
1392  */
1393 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1chmod
1394         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_mode)
1395 {
1396         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1397         CephContext *cct = ceph_get_mount_context(cmount);
1398         const char *c_path;
1399         int ret;
1400
1401         CHECK_ARG_NULL(j_path, "@path is null", -1);
1402         CHECK_MOUNTED(cmount, -1);
1403
1404         c_path = env->GetStringUTFChars(j_path, NULL);
1405         if (!c_path) {
1406                 cephThrowInternal(env, "Failed to pin memory");
1407                 return -1;
1408         }
1409
1410         ldout(cct, 10) << "jni: chmod: path " << c_path << " mode " << (int)j_mode << dendl;
1411
1412         ret = ceph_chmod(cmount, c_path, (int)j_mode);
1413
1414         ldout(cct, 10) << "jni: chmod: exit ret " << ret << dendl;
1415
1416         env->ReleaseStringUTFChars(j_path, c_path);
1417
1418         if (ret)
1419                 handle_error(env, ret);
1420
1421         return ret;
1422 }
1423
1424 /*
1425  * Class:     com_ceph_fs_CephMount
1426  * Method:    native_ceph_fchmod
1427  * Signature: (JII)I
1428  */
1429 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fchmod
1430   (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jint j_mode)
1431 {
1432         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1433         CephContext *cct = ceph_get_mount_context(cmount);
1434         int ret;
1435
1436         CHECK_MOUNTED(cmount, -1);
1437
1438         ldout(cct, 10) << "jni: fchmod: fd " << (int)j_fd << " mode " << (int)j_mode << dendl;
1439
1440         ret = ceph_fchmod(cmount, (int)j_fd, (int)j_mode);
1441
1442         ldout(cct, 10) << "jni: fchmod: exit ret " << ret << dendl;
1443
1444         if (ret)
1445                 handle_error(env, ret);
1446
1447         return ret;
1448 }
1449
1450 /*
1451  * Class:     com_ceph_fs_CephMount
1452  * Method:    native_ceph_truncate
1453  * Signature: (JLjava/lang/String;J)I
1454  */
1455 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1truncate
1456         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jlong j_size)
1457 {
1458         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1459         CephContext *cct = ceph_get_mount_context(cmount);
1460         const char *c_path;
1461         int ret;
1462
1463         CHECK_ARG_NULL(j_path, "@path is null", -1);
1464         CHECK_MOUNTED(cmount, -1);
1465
1466         c_path = env->GetStringUTFChars(j_path, NULL);
1467         if (!c_path) {
1468                 cephThrowInternal(env, "Failed to pin memory");
1469                 return -1;
1470         }
1471
1472         ldout(cct, 10) << "jni: truncate: path " << c_path << " size " << (loff_t)j_size << dendl;
1473
1474         ret = ceph_truncate(cmount, c_path, (loff_t)j_size);
1475
1476         ldout(cct, 10) << "jni: truncate: exit ret " << ret << dendl;
1477
1478         env->ReleaseStringUTFChars(j_path, c_path);
1479
1480         if (ret)
1481                 handle_error(env, ret);
1482
1483         return ret;
1484 }
1485
1486 /*
1487  * Class:     com_ceph_fs_CephMount
1488  * Method:    native_ceph_open
1489  * Signature: (JLjava/lang/String;II)I
1490  */
1491 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open
1492         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode)
1493 {
1494         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1495         CephContext *cct = ceph_get_mount_context(cmount);
1496         const char *c_path;
1497         int ret, flags = fixup_open_flags(j_flags);
1498
1499         CHECK_ARG_NULL(j_path, "@path is null", -1);
1500         CHECK_MOUNTED(cmount, -1);
1501
1502         c_path = env->GetStringUTFChars(j_path, NULL);
1503         if (!c_path) {
1504                 cephThrowInternal(env, "Failed to pin memory");
1505                 return -1;
1506         }
1507
1508         ldout(cct, 10) << "jni: open: path " << c_path << " flags " << flags
1509                 << " mode " << (int)j_mode << dendl;
1510
1511         ret = ceph_open(cmount, c_path, flags, (int)j_mode);
1512
1513         ldout(cct, 10) << "jni: open: exit ret " << ret << dendl;
1514
1515         env->ReleaseStringUTFChars(j_path, c_path);
1516
1517         if (ret < 0)
1518                 handle_error(env, ret);
1519
1520         return ret;
1521 }
1522
1523 /*
1524  * Class:     com_ceph_fs_CephMount
1525  * Method:    native_ceph_open_layout
1526  * Signature: (JLjava/lang/String;IIIIILjava/lang/String;)I
1527  */
1528 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1open_1layout
1529   (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jint j_flags, jint j_mode,
1530    jint stripe_unit, jint stripe_count, jint object_size, jstring j_data_pool)
1531 {
1532         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1533         CephContext *cct = ceph_get_mount_context(cmount);
1534         const char *c_path, *c_data_pool = NULL;
1535         int ret, flags = fixup_open_flags(j_flags);
1536
1537         CHECK_ARG_NULL(j_path, "@path is null", -1);
1538         CHECK_MOUNTED(cmount, -1);
1539
1540         c_path = env->GetStringUTFChars(j_path, NULL);
1541         if (!c_path) {
1542                 cephThrowInternal(env, "Failed to pin memory");
1543                 return -1;
1544         }
1545
1546         if (j_data_pool) {
1547                 c_data_pool = env->GetStringUTFChars(j_data_pool, NULL);
1548                 if (!c_data_pool) {
1549                         env->ReleaseStringUTFChars(j_path, c_path);
1550                         cephThrowInternal(env, "Failed to pin memory");
1551                         return -1;
1552                 }
1553         }
1554
1555         ldout(cct, 10) << "jni: open_layout: path " << c_path << " flags " << flags
1556                 << " mode " << (int)j_mode << " stripe_unit " << stripe_unit
1557                 << " stripe_count " << stripe_count << " object_size " << object_size
1558                 << " data_pool " << (c_data_pool ? c_data_pool : "<NULL>") << dendl;
1559
1560         ret = ceph_open_layout(cmount, c_path, flags, (int)j_mode,
1561                         (int)stripe_unit, (int)stripe_count, (int)object_size, c_data_pool);
1562
1563         ldout(cct, 10) << "jni: open_layout: exit ret " << ret << dendl;
1564
1565         env->ReleaseStringUTFChars(j_path, c_path);
1566         if (j_data_pool)
1567                 env->ReleaseStringUTFChars(j_data_pool, c_data_pool);
1568
1569         if (ret < 0)
1570                 handle_error(env, ret);
1571
1572         return ret;
1573 }
1574
1575 /*
1576  * Class:     com_ceph_fs_CephMount
1577  * Method:    native_ceph_close
1578  * Signature: (JI)I
1579  */
1580 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1close
1581         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
1582 {
1583         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1584         CephContext *cct = ceph_get_mount_context(cmount);
1585         int ret;
1586
1587         CHECK_MOUNTED(cmount, -1);
1588
1589         ldout(cct, 10) << "jni: close: fd " << (int)j_fd << dendl;
1590
1591         ret = ceph_close(cmount, (int)j_fd);
1592
1593         ldout(cct, 10) << "jni: close: ret " << ret << dendl;
1594
1595         if (ret)
1596                 handle_error(env, ret);
1597
1598         return ret;
1599 }
1600
1601 /*
1602  * Class:     com_ceph_fs_CephMount
1603  * Method:    native_ceph_lseek
1604  * Signature: (JIJI)J
1605  */
1606 JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lseek
1607         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_offset, jint j_whence)
1608 {
1609         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1610         CephContext *cct = ceph_get_mount_context(cmount);
1611         int whence;
1612         jlong ret;
1613
1614         CHECK_MOUNTED(cmount, -1);
1615
1616         switch (j_whence) {
1617         case JAVA_SEEK_SET:
1618                 whence = SEEK_SET;
1619                 break;
1620         case JAVA_SEEK_CUR:
1621                 whence = SEEK_CUR;
1622                 break;
1623         case JAVA_SEEK_END:
1624                 whence = SEEK_END;
1625                 break;
1626         default:
1627                 cephThrowIllegalArg(env, "Unknown whence value");
1628                 return -1;
1629         }
1630
1631         ldout(cct, 10) << "jni: lseek: fd " << (int)j_fd << " offset "
1632                 << (long)j_offset << " whence " << whence << dendl;
1633
1634         ret = ceph_lseek(cmount, (int)j_fd, (long)j_offset, whence);
1635
1636         ldout(cct, 10) << "jni: lseek: exit ret " << ret << dendl;
1637
1638         if (ret < 0)
1639                 handle_error(env, ret);
1640
1641         return ret;
1642 }
1643
1644 /*
1645  * Class:     com_ceph_fs_CephMount
1646  * Method:    native_ceph_read
1647  * Signature: (JI[BJJ)J
1648  */
1649 JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1read
1650         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset)
1651 {
1652         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1653         CephContext *cct = ceph_get_mount_context(cmount);
1654         jsize buf_size;
1655         jbyte *c_buf;
1656         long ret;
1657
1658         CHECK_ARG_NULL(j_buf, "@buf is null", -1);
1659         CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
1660         CHECK_MOUNTED(cmount, -1);
1661
1662         buf_size = env->GetArrayLength(j_buf);
1663         CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
1664
1665         c_buf = env->GetByteArrayElements(j_buf, NULL);
1666         if (!c_buf) {
1667                 cephThrowInternal(env, "failed to pin memory");
1668                 return -1;
1669         }
1670
1671         ldout(cct, 10) << "jni: read: fd " << (int)j_fd << " len " << (long)j_size <<
1672                 " offset " << (long)j_offset << dendl;
1673
1674         ret = ceph_read(cmount, (int)j_fd, (char*)c_buf, (long)j_size, (long)j_offset);
1675
1676         ldout(cct, 10) << "jni: read: exit ret " << ret << dendl;
1677
1678         if (ret < 0)
1679                 handle_error(env, (int)ret);
1680         else
1681                 env->ReleaseByteArrayElements(j_buf, c_buf, 0);
1682
1683         return (jlong)ret;
1684 }
1685
1686 /*
1687  * Class:     com_ceph_fs_CephMount
1688  * Method:    native_ceph_write
1689  * Signature: (JI[BJJ)J
1690  */
1691 JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1write
1692         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jbyteArray j_buf, jlong j_size, jlong j_offset)
1693 {
1694         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1695         CephContext *cct = ceph_get_mount_context(cmount);
1696         jsize buf_size;
1697         jbyte *c_buf;
1698         long ret;
1699
1700         CHECK_ARG_NULL(j_buf, "@buf is null", -1);
1701         CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
1702         CHECK_MOUNTED(cmount, -1);
1703
1704         buf_size = env->GetArrayLength(j_buf);
1705         CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
1706
1707         c_buf = env->GetByteArrayElements(j_buf, NULL);
1708         if (!c_buf) {
1709                 cephThrowInternal(env, "failed to pin memory");
1710                 return -1;
1711         }
1712
1713         ldout(cct, 10) << "jni: write: fd " << (int)j_fd << " len " << (long)j_size <<
1714                 " offset " << (long)j_offset << dendl;
1715
1716         ret = ceph_write(cmount, (int)j_fd, (char*)c_buf, (long)j_size, (long)j_offset);
1717
1718         ldout(cct, 10) << "jni: write: exit ret " << ret << dendl;
1719
1720         if (ret < 0)
1721                 handle_error(env, (int)ret);
1722         else
1723                 env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
1724
1725         return ret;
1726 }
1727
1728
1729 /*
1730  * Class:     com_ceph_fs_CephMount
1731  * Method:    native_ceph_ftruncate
1732  * Signature: (JIJ)I
1733  */
1734 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1ftruncate
1735         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jlong j_size)
1736 {
1737         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1738         CephContext *cct = ceph_get_mount_context(cmount);
1739         int ret;
1740
1741         CHECK_MOUNTED(cmount, -1);
1742
1743         ldout(cct, 10) << "jni: ftruncate: fd " << (int)j_fd <<
1744                 " size " << (loff_t)j_size << dendl;
1745
1746         ret = ceph_ftruncate(cmount, (int)j_fd, (loff_t)j_size);
1747
1748         ldout(cct, 10) << "jni: ftruncate: exit ret " << ret << dendl;
1749
1750         if (ret)
1751                 handle_error(env, ret);
1752
1753         return ret;
1754 }
1755
1756 /*
1757  * Class:     com_ceph_fs_CephMount
1758  * Method:    native_ceph_fsync
1759  * Signature: (JIZ)I
1760  */
1761 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fsync
1762         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jboolean j_dataonly)
1763 {
1764         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1765         CephContext *cct = ceph_get_mount_context(cmount);
1766         int ret;
1767
1768         ldout(cct, 10) << "jni: fsync: fd " << (int)j_fd <<
1769                 " dataonly " << (j_dataonly ? 1 : 0) << dendl;
1770
1771         ret = ceph_fsync(cmount, (int)j_fd, j_dataonly ? 1 : 0);
1772
1773         ldout(cct, 10) << "jni: fsync: exit ret " << ret << dendl;
1774
1775         if (ret)
1776                 handle_error(env, ret);
1777
1778         return ret;
1779 }
1780
1781 /*
1782  * Class:     com_ceph_fs_CephMount
1783  * Method:    native_ceph_flock
1784  * Signature: (JIZ)I
1785  */
1786 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1flock
1787         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jint j_operation, jlong j_owner)
1788 {
1789         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1790         CephContext *cct = ceph_get_mount_context(cmount);
1791         int ret;
1792
1793         ldout(cct, 10) << "jni: flock: fd " << (int)j_fd <<
1794                 " operation " << j_operation << " owner " << j_owner << dendl;
1795
1796         int operation = 0;
1797
1798 #define MAP_FLOCK_FLAG(JNI_MASK, NATIVE_MASK) do {      \
1799         if ((j_operation & JNI_MASK) != 0) {            \
1800                 operation |= NATIVE_MASK;               \
1801                 j_operation &= ~JNI_MASK;               \
1802         }                                               \
1803         } while(0)
1804         MAP_FLOCK_FLAG(JAVA_LOCK_SH, LOCK_SH);
1805         MAP_FLOCK_FLAG(JAVA_LOCK_EX, LOCK_EX);
1806         MAP_FLOCK_FLAG(JAVA_LOCK_NB, LOCK_NB);
1807         MAP_FLOCK_FLAG(JAVA_LOCK_UN, LOCK_UN);
1808         if (j_operation != 0) {
1809                 cephThrowIllegalArg(env, "flock flags");
1810                 return -EINVAL;
1811         }
1812 #undef MAP_FLOCK_FLAG
1813
1814         ret = ceph_flock(cmount, (int)j_fd, operation, (uint64_t) j_owner);
1815
1816         ldout(cct, 10) << "jni: flock: exit ret " << ret << dendl;
1817
1818         if (ret)
1819                 handle_error(env, ret);
1820
1821         return ret;
1822 }
1823
1824 /*
1825  * Class:     com_ceph_fs_CephMount
1826  * Method:    native_ceph_fstat
1827  * Signature: (JILcom/ceph/fs/CephStat;)I
1828  */
1829 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1fstat
1830         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd, jobject j_cephstat)
1831 {
1832         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1833         CephContext *cct = ceph_get_mount_context(cmount);
1834         struct ceph_statx stx;
1835         int ret;
1836
1837         CHECK_ARG_NULL(j_cephstat, "@stat is null", -1);
1838         CHECK_MOUNTED(cmount, -1);
1839
1840         ldout(cct, 10) << "jni: fstat: fd " << (int)j_fd << dendl;
1841
1842         ret = ceph_fstatx(cmount, (int)j_fd, &stx, CEPH_J_CEPHSTAT_MASK, 0);
1843
1844         ldout(cct, 10) << "jni: fstat exit ret " << ret << dendl;
1845
1846         if (ret) {
1847                 handle_error(env, ret);
1848                 return ret;
1849         }
1850
1851         fill_cephstat(env, j_cephstat, &stx);
1852
1853         return ret;
1854 }
1855
1856 /*
1857  * Class:     com_ceph_fs_CephMount
1858  * Method:    native_ceph_sync_fs
1859  * Signature: (J)I
1860  */
1861 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1sync_1fs
1862         (JNIEnv *env, jclass clz, jlong j_mntp)
1863 {
1864         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1865         CephContext *cct = ceph_get_mount_context(cmount);
1866         int ret;
1867
1868         ldout(cct, 10) << "jni: sync_fs: enter" << dendl;
1869
1870         ret = ceph_sync_fs(cmount);
1871
1872         ldout(cct, 10) << "jni: sync_fs: exit ret " << ret << dendl;
1873
1874         if (ret)
1875                 handle_error(env, ret);
1876
1877         return ret;
1878 }
1879
1880 /*
1881  * Class:     com_ceph_fs_CephMount
1882  * Method:    native_ceph_getxattr
1883  * Signature: (JLjava/lang/String;Ljava/lang/String;[B)J
1884  */
1885 JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1getxattr
1886         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf)
1887 {
1888         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1889         CephContext *cct = ceph_get_mount_context(cmount);
1890         const char *c_path;
1891         const char *c_name;
1892         jsize buf_size;
1893         jbyte *c_buf = NULL; /* please gcc with goto */
1894         long ret;
1895
1896         CHECK_ARG_NULL(j_path, "@path is null", -1);
1897         CHECK_ARG_NULL(j_name, "@name is null", -1);
1898         CHECK_MOUNTED(cmount, -1);
1899
1900         c_path = env->GetStringUTFChars(j_path, NULL);
1901         if (!c_path) {
1902                 cephThrowInternal(env, "Failed to pin memory");
1903                 return -1;
1904         }
1905
1906         c_name = env->GetStringUTFChars(j_name, NULL);
1907         if (!c_name) {
1908                 env->ReleaseStringUTFChars(j_path, c_path);
1909                 cephThrowInternal(env, "Failed to pin memory");
1910                 return -1;
1911         }
1912
1913         /* just lookup the size if buf is null */
1914         if (!j_buf) {
1915                 buf_size = 0;
1916                 goto do_getxattr;
1917         }
1918
1919         c_buf = env->GetByteArrayElements(j_buf, NULL);
1920         if (!c_buf) {
1921                 env->ReleaseStringUTFChars(j_path, c_path);
1922                 env->ReleaseStringUTFChars(j_name, c_name);
1923                 cephThrowInternal(env, "failed to pin memory");
1924                 return -1;
1925         }
1926
1927         buf_size = env->GetArrayLength(j_buf);
1928
1929 do_getxattr:
1930
1931         ldout(cct, 10) << "jni: getxattr: path " << c_path << " name " << c_name <<
1932                 " len " << buf_size << dendl;
1933
1934         ret = ceph_getxattr(cmount, c_path, c_name, c_buf, buf_size);
1935         if (ret == -ERANGE)
1936                 ret = ceph_getxattr(cmount, c_path, c_name, c_buf, 0);
1937
1938         ldout(cct, 10) << "jni: getxattr: exit ret " << ret << dendl;
1939
1940         env->ReleaseStringUTFChars(j_path, c_path);
1941         env->ReleaseStringUTFChars(j_name, c_name);
1942         if (j_buf)
1943                 env->ReleaseByteArrayElements(j_buf, c_buf, 0);
1944
1945         if (ret < 0)
1946                 handle_error(env, (int)ret);
1947
1948         return (jlong)ret;
1949 }
1950
1951 /*
1952  * Class:     com_ceph_fs_CephMount
1953  * Method:    native_ceph_lgetxattr
1954  * Signature: (JLjava/lang/String;Ljava/lang/String;[B)I
1955  */
1956 JNIEXPORT jlong JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lgetxattr
1957         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name, jbyteArray j_buf)
1958 {
1959         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
1960         CephContext *cct = ceph_get_mount_context(cmount);
1961         const char *c_path;
1962         const char *c_name;
1963         jsize buf_size;
1964         jbyte *c_buf = NULL; /* please gcc with goto */
1965         long ret;
1966
1967         CHECK_ARG_NULL(j_path, "@path is null", -1);
1968         CHECK_ARG_NULL(j_name, "@name is null", -1);
1969         CHECK_MOUNTED(cmount, -1);
1970
1971         c_path = env->GetStringUTFChars(j_path, NULL);
1972         if (!c_path) {
1973                 cephThrowInternal(env, "Failed to pin memory");
1974                 return -1;
1975         }
1976
1977         c_name = env->GetStringUTFChars(j_name, NULL);
1978         if (!c_name) {
1979                 env->ReleaseStringUTFChars(j_path, c_path);
1980                 cephThrowInternal(env, "Failed to pin memory");
1981                 return -1;
1982         }
1983
1984         /* just lookup the size if buf is null */
1985         if (!j_buf) {
1986                 buf_size = 0;
1987                 goto do_lgetxattr;
1988         }
1989
1990         c_buf = env->GetByteArrayElements(j_buf, NULL);
1991         if (!c_buf) {
1992                 env->ReleaseStringUTFChars(j_path, c_path);
1993                 env->ReleaseStringUTFChars(j_name, c_name);
1994                 cephThrowInternal(env, "failed to pin memory");
1995                 return -1;
1996         }
1997
1998         buf_size = env->GetArrayLength(j_buf);
1999
2000 do_lgetxattr:
2001
2002         ldout(cct, 10) << "jni: lgetxattr: path " << c_path << " name " << c_name <<
2003                 " len " << buf_size << dendl;
2004
2005         ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, buf_size);
2006         if (ret == -ERANGE)
2007                 ret = ceph_lgetxattr(cmount, c_path, c_name, c_buf, 0);
2008
2009         ldout(cct, 10) << "jni: lgetxattr: exit ret " << ret << dendl;
2010
2011         env->ReleaseStringUTFChars(j_path, c_path);
2012         env->ReleaseStringUTFChars(j_name, c_name);
2013         if (j_buf)
2014                 env->ReleaseByteArrayElements(j_buf, c_buf, 0);
2015
2016         if (ret < 0)
2017                 handle_error(env, (int)ret);
2018
2019         return (jlong)ret;
2020 }
2021
2022 /*
2023  * Class:     com_ceph_fs_CephMount
2024  * Method:    native_ceph_listxattr
2025  * Signature: (JLjava/lang/String;)[Ljava/lang/String;
2026  */
2027 JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1listxattr
2028         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
2029 {
2030         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2031         CephContext *cct = ceph_get_mount_context(cmount);
2032         jobjectArray xattrlist;
2033         const char *c_path;
2034         string *ent;
2035         jstring name;
2036         list<string>::iterator it;
2037         list<string> contents;
2038         int ret, buflen, bufpos, i;
2039         char *buf;
2040
2041         CHECK_ARG_NULL(j_path, "@path is null", NULL);
2042         CHECK_MOUNTED(cmount, NULL);
2043
2044         c_path = env->GetStringUTFChars(j_path, NULL);
2045         if (!c_path) {
2046                 cephThrowInternal(env, "Failed to pin memory");
2047                 return NULL;
2048         }
2049
2050         buflen = 1024;
2051         buf = new (std::nothrow) char[buflen];
2052         if (!buf) {
2053                 cephThrowOutOfMemory(env, "head allocation failed");
2054                 goto out;
2055         }
2056
2057         while (1) {
2058                 ldout(cct, 10) << "jni: listxattr: path " << c_path << " len " << buflen << dendl;
2059                 ret = ceph_listxattr(cmount, c_path, buf, buflen);
2060                 if (ret == -ERANGE) {
2061                         delete [] buf;
2062                         buflen *= 2;
2063                         buf = new (std::nothrow) char[buflen];
2064                         if (!buf)  {
2065                                 cephThrowOutOfMemory(env, "heap allocation failed");
2066                                 goto out;
2067                         }
2068                         continue;
2069                 }
2070                 break;
2071         }
2072
2073         ldout(cct, 10) << "jni: listxattr: ret " << ret << dendl;
2074
2075         if (ret < 0) {
2076                 delete [] buf;
2077                 handle_error(env, ret);
2078                 goto out;
2079         }
2080
2081         bufpos = 0;
2082         while (bufpos < ret) {
2083                 ent = new (std::nothrow) string(buf + bufpos);
2084                 if (!ent) {
2085                         delete [] buf;
2086                         cephThrowOutOfMemory(env, "heap allocation failed");
2087                         goto out;
2088                 }
2089                 contents.push_back(*ent);
2090                 bufpos += ent->size() + 1;
2091                 delete ent;
2092         }
2093
2094         delete [] buf;
2095
2096         xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
2097         if (!xattrlist)
2098                 goto out;
2099
2100         for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
2101                 name = env->NewStringUTF(it->c_str());
2102                 if (!name)
2103                         goto out;
2104                 env->SetObjectArrayElement(xattrlist, i++, name);
2105                 if (env->ExceptionOccurred())
2106                         goto out;
2107                 env->DeleteLocalRef(name);
2108         }
2109
2110         env->ReleaseStringUTFChars(j_path, c_path);
2111         return xattrlist;
2112
2113 out:
2114         env->ReleaseStringUTFChars(j_path, c_path);
2115         return NULL;
2116 }
2117
2118 /*
2119  * Class:     com_ceph_fs_CephMount
2120  * Method:    native_ceph_llistxattr
2121  * Signature: (JLjava/lang/String;)[Ljava/lang/String;
2122  */
2123 JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1llistxattr
2124         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path)
2125 {
2126         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2127         CephContext *cct = ceph_get_mount_context(cmount);
2128         jobjectArray xattrlist;
2129         const char *c_path;
2130         string *ent;
2131         jstring name;
2132         list<string>::iterator it;
2133         list<string> contents;
2134         int ret, buflen, bufpos, i;
2135         char *buf;
2136
2137         CHECK_ARG_NULL(j_path, "@path is null", NULL);
2138         CHECK_MOUNTED(cmount, NULL);
2139
2140         c_path = env->GetStringUTFChars(j_path, NULL);
2141         if (!c_path) {
2142                 cephThrowInternal(env, "Failed to pin memory");
2143                 return NULL;
2144         }
2145
2146         buflen = 1024;
2147         buf = new (std::nothrow) char[buflen];
2148         if (!buf) {
2149                 cephThrowOutOfMemory(env, "head allocation failed");
2150                 goto out;
2151         }
2152
2153         while (1) {
2154                 ldout(cct, 10) << "jni: llistxattr: path " << c_path << " len " << buflen << dendl;
2155                 ret = ceph_llistxattr(cmount, c_path, buf, buflen);
2156                 if (ret == -ERANGE) {
2157                         delete [] buf;
2158                         buflen *= 2;
2159                         buf = new (std::nothrow) char[buflen];
2160                         if (!buf)  {
2161                                 cephThrowOutOfMemory(env, "heap allocation failed");
2162                                 goto out;
2163                         }
2164                         continue;
2165                 }
2166                 break;
2167         }
2168
2169         ldout(cct, 10) << "jni: llistxattr: ret " << ret << dendl;
2170
2171         if (ret < 0) {
2172                 delete [] buf;
2173                 handle_error(env, ret);
2174                 goto out;
2175         }
2176
2177         bufpos = 0;
2178         while (bufpos < ret) {
2179                 ent = new (std::nothrow) string(buf + bufpos);
2180                 if (!ent) {
2181                         delete [] buf;
2182                         cephThrowOutOfMemory(env, "heap allocation failed");
2183                         goto out;
2184                 }
2185                 contents.push_back(*ent);
2186                 bufpos += ent->size() + 1;
2187                 delete ent;
2188         }
2189
2190         delete [] buf;
2191
2192         xattrlist = env->NewObjectArray(contents.size(), env->FindClass("java/lang/String"), NULL);
2193         if (!xattrlist)
2194                 goto out;
2195
2196         for (i = 0, it = contents.begin(); it != contents.end(); ++it) {
2197                 name = env->NewStringUTF(it->c_str());
2198                 if (!name)
2199                         goto out;
2200                 env->SetObjectArrayElement(xattrlist, i++, name);
2201                 if (env->ExceptionOccurred())
2202                         goto out;
2203                 env->DeleteLocalRef(name);
2204         }
2205
2206         env->ReleaseStringUTFChars(j_path, c_path);
2207         return xattrlist;
2208
2209 out:
2210         env->ReleaseStringUTFChars(j_path, c_path);
2211         return NULL;
2212 }
2213
2214 /*
2215  * Class:     com_ceph_fs_CephMount
2216  * Method:    native_ceph_removexattr
2217  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
2218  */
2219 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1removexattr
2220         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name)
2221 {
2222         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2223         CephContext *cct = ceph_get_mount_context(cmount);
2224         const char *c_path;
2225         const char *c_name;
2226         int ret;
2227
2228         CHECK_ARG_NULL(j_path, "@path is null", -1);
2229         CHECK_ARG_NULL(j_name, "@name is null", -1);
2230         CHECK_MOUNTED(cmount, -1);
2231
2232         c_path = env->GetStringUTFChars(j_path, NULL);
2233         if (!c_path) {
2234                 cephThrowInternal(env, "Failed to pin memory");
2235                 return -1;
2236         }
2237
2238         c_name = env->GetStringUTFChars(j_name, NULL);
2239         if (!c_name) {
2240                 env->ReleaseStringUTFChars(j_path, c_path);
2241                 cephThrowInternal(env, "Failed to pin memory");
2242                 return -1;
2243         }
2244
2245         ldout(cct, 10) << "jni: removexattr: path " << c_path << " name " << c_name << dendl;
2246
2247         ret = ceph_removexattr(cmount, c_path, c_name);
2248
2249         ldout(cct, 10) << "jni: removexattr: exit ret " << ret << dendl;
2250
2251         env->ReleaseStringUTFChars(j_path, c_path);
2252         env->ReleaseStringUTFChars(j_name, c_name);
2253
2254         if (ret)
2255                 handle_error(env, ret);
2256
2257         return ret;
2258 }
2259
2260 /*
2261  * Class:     com_ceph_fs_CephMount
2262  * Method:    native_ceph_lremovexattr
2263  * Signature: (JLjava/lang/String;Ljava/lang/String;)I
2264  */
2265 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lremovexattr
2266         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name)
2267 {
2268         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2269         CephContext *cct = ceph_get_mount_context(cmount);
2270         const char *c_path;
2271         const char *c_name;
2272         int ret;
2273
2274         CHECK_ARG_NULL(j_path, "@path is null", -1);
2275         CHECK_ARG_NULL(j_name, "@name is null", -1);
2276         CHECK_MOUNTED(cmount, -1);
2277
2278         c_path = env->GetStringUTFChars(j_path, NULL);
2279         if (!c_path) {
2280                 cephThrowInternal(env, "Failed to pin memory");
2281                 return -1;
2282         }
2283
2284         c_name = env->GetStringUTFChars(j_name, NULL);
2285         if (!c_name) {
2286                 env->ReleaseStringUTFChars(j_path, c_path);
2287                 cephThrowInternal(env, "Failed to pin memory");
2288                 return -1;
2289         }
2290
2291         ldout(cct, 10) << "jni: lremovexattr: path " << c_path << " name " << c_name << dendl;
2292
2293         ret = ceph_lremovexattr(cmount, c_path, c_name);
2294
2295         ldout(cct, 10) << "jni: lremovexattr: exit ret " << ret << dendl;
2296
2297         env->ReleaseStringUTFChars(j_path, c_path);
2298         env->ReleaseStringUTFChars(j_name, c_name);
2299
2300         if (ret)
2301                 handle_error(env, ret);
2302
2303         return ret;
2304 }
2305
2306 /*
2307  * Class:     com_ceph_fs_CephMount
2308  * Method:    native_ceph_setxattr
2309  * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I
2310  */
2311 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1setxattr
2312         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name,
2313          jbyteArray j_buf, jlong j_size, jint j_flags)
2314 {
2315         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2316         CephContext *cct = ceph_get_mount_context(cmount);
2317         const char *c_path;
2318         const char *c_name;
2319         jsize buf_size;
2320         jbyte *c_buf;
2321         int ret, flags;
2322
2323         CHECK_ARG_NULL(j_path, "@path is null", -1);
2324         CHECK_ARG_NULL(j_name, "@name is null", -1);
2325         CHECK_ARG_NULL(j_buf, "@buf is null", -1);
2326         CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
2327         CHECK_MOUNTED(cmount, -1);
2328
2329         buf_size = env->GetArrayLength(j_buf);
2330         CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
2331
2332         c_path = env->GetStringUTFChars(j_path, NULL);
2333         if (!c_path) {
2334                 cephThrowInternal(env, "Failed to pin memory");
2335                 return -1;
2336         }
2337
2338         c_name = env->GetStringUTFChars(j_name, NULL);
2339         if (!c_name) {
2340                 env->ReleaseStringUTFChars(j_path, c_path);
2341                 cephThrowInternal(env, "Failed to pin memory");
2342                 return -1;
2343         }
2344
2345         c_buf = env->GetByteArrayElements(j_buf, NULL);
2346         if (!c_buf) {
2347                 env->ReleaseStringUTFChars(j_path, c_path);
2348                 env->ReleaseStringUTFChars(j_name, c_name);
2349                 cephThrowInternal(env, "failed to pin memory");
2350                 return -1;
2351         }
2352
2353         switch (j_flags) {
2354         case JAVA_XATTR_CREATE:
2355                 flags = CEPH_XATTR_CREATE;
2356                 break;
2357         case JAVA_XATTR_REPLACE:
2358                 flags = CEPH_XATTR_REPLACE;
2359                 break;
2360         case JAVA_XATTR_NONE:
2361                 flags = 0;
2362                 break;
2363         default:
2364                 env->ReleaseStringUTFChars(j_path, c_path);
2365                 env->ReleaseStringUTFChars(j_name, c_name);
2366                 env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
2367                 cephThrowIllegalArg(env, "setxattr flag");
2368                 return -1;
2369         }
2370
2371         ldout(cct, 10) << "jni: setxattr: path " << c_path << " name " << c_name
2372                 << " len " << j_size << " flags " << flags << dendl;
2373
2374         ret = ceph_setxattr(cmount, c_path, c_name, c_buf, j_size, flags);
2375
2376         ldout(cct, 10) << "jni: setxattr: exit ret " << ret << dendl;
2377
2378         env->ReleaseStringUTFChars(j_path, c_path);
2379         env->ReleaseStringUTFChars(j_name, c_name);
2380         env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
2381
2382         if (ret)
2383                 handle_error(env, ret);
2384
2385         return ret;
2386 }
2387
2388 /*
2389  * Class:     com_ceph_fs_CephMount
2390  * Method:    native_ceph_lsetxattr
2391  * Signature: (JLjava/lang/String;Ljava/lang/String;[BJI)I
2392  */
2393 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lsetxattr
2394         (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jstring j_name,
2395          jbyteArray j_buf, jlong j_size, jint j_flags)
2396 {
2397         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2398         CephContext *cct = ceph_get_mount_context(cmount);
2399         const char *c_path;
2400         const char *c_name;
2401         jsize buf_size;
2402         jbyte *c_buf;
2403         int ret, flags;
2404
2405         CHECK_ARG_NULL(j_path, "@path is null", -1);
2406         CHECK_ARG_NULL(j_name, "@name is null", -1);
2407         CHECK_ARG_NULL(j_buf, "@buf is null", -1);
2408         CHECK_ARG_BOUNDS(j_size < 0, "@size is negative", -1);
2409         CHECK_MOUNTED(cmount, -1);
2410
2411         buf_size = env->GetArrayLength(j_buf);
2412         CHECK_ARG_BOUNDS(j_size > buf_size, "@size > @buf.length", -1);
2413
2414         c_path = env->GetStringUTFChars(j_path, NULL);
2415         if (!c_path) {
2416                 cephThrowInternal(env, "Failed to pin memory");
2417                 return -1;
2418         }
2419
2420         c_name = env->GetStringUTFChars(j_name, NULL);
2421         if (!c_name) {
2422                 env->ReleaseStringUTFChars(j_path, c_path);
2423                 cephThrowInternal(env, "Failed to pin memory");
2424                 return -1;
2425         }
2426
2427         c_buf = env->GetByteArrayElements(j_buf, NULL);
2428         if (!c_buf) {
2429                 env->ReleaseStringUTFChars(j_path, c_path);
2430                 env->ReleaseStringUTFChars(j_name, c_name);
2431                 cephThrowInternal(env, "failed to pin memory");
2432                 return -1;
2433         }
2434
2435         switch (j_flags) {
2436         case JAVA_XATTR_CREATE:
2437                 flags = CEPH_XATTR_CREATE;
2438                 break;
2439         case JAVA_XATTR_REPLACE:
2440                 flags = CEPH_XATTR_REPLACE;
2441                 break;
2442         case JAVA_XATTR_NONE:
2443                 flags = 0;
2444                 break;
2445         default:
2446                 env->ReleaseStringUTFChars(j_path, c_path);
2447                 env->ReleaseStringUTFChars(j_name, c_name);
2448                 env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
2449                 cephThrowIllegalArg(env, "lsetxattr flag");
2450                 return -1;
2451         }
2452
2453         ldout(cct, 10) << "jni: lsetxattr: path " << c_path << " name " << c_name
2454                 << " len " << j_size << " flags " << flags << dendl;
2455
2456         ret = ceph_lsetxattr(cmount, c_path, c_name, c_buf, j_size, flags);
2457
2458         ldout(cct, 10) << "jni: lsetxattr: exit ret " << ret << dendl;
2459
2460         env->ReleaseStringUTFChars(j_path, c_path);
2461         env->ReleaseStringUTFChars(j_name, c_name);
2462         env->ReleaseByteArrayElements(j_buf, c_buf, JNI_ABORT);
2463
2464         if (ret)
2465                 handle_error(env, ret);
2466
2467         return ret;
2468 }
2469
2470 /*
2471  * Class:     com_ceph_fs_CephMount
2472  * Method:    native_ceph_get_file_stripe_unit
2473  * Signature: (JI)I
2474  */
2475 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1stripe_1unit
2476         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
2477 {
2478         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2479         CephContext *cct = ceph_get_mount_context(cmount);
2480         int ret;
2481
2482         CHECK_MOUNTED(cmount, -1);
2483
2484         ldout(cct, 10) << "jni: get_file_stripe_unit: fd " << (int)j_fd << dendl;
2485
2486         ret = ceph_get_file_stripe_unit(cmount, (int)j_fd);
2487
2488         ldout(cct, 10) << "jni: get_file_stripe_unit: exit ret " << ret << dendl;
2489
2490         if (ret < 0)
2491                 handle_error(env, ret);
2492
2493         return ret;
2494 }
2495
2496 /*
2497  * Class:     com_ceph_fs_CephMount
2498  * Method:    native_ceph_get_file_replication
2499  * Signature: (JI)I
2500  */
2501 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1replication
2502         (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
2503 {
2504         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2505         CephContext *cct = ceph_get_mount_context(cmount);
2506         int ret;
2507
2508         CHECK_MOUNTED(cmount, -1);
2509
2510         ldout(cct, 10) << "jni: get_file_replication: fd " << (int)j_fd << dendl;
2511
2512         ret = ceph_get_file_replication(cmount, (int)j_fd);
2513
2514         ldout(cct, 10) << "jni: get_file_replication: exit ret " << ret << dendl;
2515
2516         if (ret < 0)
2517                 handle_error(env, ret);
2518
2519         return ret;
2520 }
2521
2522 /*
2523  * Class:     com_ceph_fs_CephMount
2524  * Method:    native_ceph_get_file_pool_name
2525  * Signature: (JI)Ljava/lang/String;
2526  */
2527 JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1pool_1name
2528   (JNIEnv *env, jclass clz, jlong j_mntp, jint j_fd)
2529 {
2530         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2531         CephContext *cct = ceph_get_mount_context(cmount);
2532         jstring pool = NULL;
2533         int ret, buflen = 0;
2534         char *buf = NULL;
2535
2536         CHECK_MOUNTED(cmount, NULL);
2537
2538         ldout(cct, 10) << "jni: get_file_pool_name: fd " << (int)j_fd << dendl;
2539
2540         for (;;) {
2541                 /* get pool name length (len==0) */
2542                 ret = ceph_get_file_pool_name(cmount, (int)j_fd, NULL, 0);
2543                 if (ret < 0)
2544                         break;
2545
2546                 /* allocate buffer */
2547                 if (buf)
2548                         delete [] buf;
2549                 buflen = ret;
2550                 buf = new (std::nothrow) char[buflen+1]; /* +1 for '\0' */
2551                 if (!buf) {
2552                         cephThrowOutOfMemory(env, "head allocation failed");
2553                         goto out;
2554                 }
2555                 memset(buf, 0, (buflen+1)*sizeof(*buf));
2556
2557                 /* handle zero-length pool name!? */
2558                 if (buflen == 0)
2559                         break;
2560
2561                 /* fill buffer */
2562                 ret = ceph_get_file_pool_name(cmount, (int)j_fd, buf, buflen);
2563                 if (ret == -ERANGE) /* size changed! */
2564                         continue;
2565                 else
2566                         break;
2567         }
2568
2569         ldout(cct, 10) << "jni: get_file_pool_name: ret " << ret << dendl;
2570
2571         if (ret < 0)
2572                 handle_error(env, ret);
2573         else
2574                 pool = env->NewStringUTF(buf);
2575
2576 out:
2577         if (buf)
2578         delete [] buf;
2579
2580         return pool;
2581 }
2582
2583 /**
2584  * Class: com_ceph_fs_CephMount
2585  * Method: native_ceph_get_default_data_pool_name
2586  * Signature: (J)Ljava/lang/String;
2587  */
2588 JNIEXPORT jstring JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1default_1data_1pool_1name
2589   (JNIEnv *env, jclass clz, jlong j_mntp)
2590 {
2591         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2592         CephContext *cct = ceph_get_mount_context(cmount);
2593         jstring pool = NULL;
2594         int ret, buflen = 0;
2595         char *buf = NULL;
2596         
2597         CHECK_MOUNTED(cmount, NULL);
2598          
2599         ldout(cct, 10) << "jni: get_default_data_pool_name" << dendl;
2600
2601         ret = ceph_get_default_data_pool_name(cmount, NULL, 0);
2602         if (ret < 0)
2603                 goto out;
2604         buflen = ret;
2605         buf = new (std::nothrow) char[buflen+1]; /* +1 for '\0' */
2606         if (!buf) {
2607                 cephThrowOutOfMemory(env, "head allocation failed");
2608                 goto out;
2609         }
2610         memset(buf, 0, (buflen+1)*sizeof(*buf));
2611         ret = ceph_get_default_data_pool_name(cmount, buf, buflen);
2612         
2613         ldout(cct, 10) << "jni: get_default_data_pool_name: ret " << ret << dendl;
2614         
2615         if (ret < 0)
2616                 handle_error(env, ret);
2617         else
2618                 pool = env->NewStringUTF(buf);
2619
2620 out:
2621         if (buf)
2622         delete [] buf;
2623
2624         return pool;        
2625 }
2626
2627
2628 /*
2629  * Class:     com_ceph_fs_CephMount
2630  * Method:    native_ceph_localize_reads
2631  * Signature: (JZ)I
2632  */
2633 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1localize_1reads
2634         (JNIEnv *env, jclass clz, jlong j_mntp, jboolean j_on)
2635 {
2636         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2637         CephContext *cct = ceph_get_mount_context(cmount);
2638         int ret, val = j_on ? 1 : 0;
2639
2640         CHECK_MOUNTED(cmount, -1);
2641
2642         ldout(cct, 10) << "jni: localize_reads: val " << val << dendl;
2643
2644         ret = ceph_localize_reads(cmount, val);
2645
2646         ldout(cct, 10) << "jni: localize_reads: exit ret " << ret << dendl;
2647
2648         if (ret)
2649                 handle_error(env, ret);
2650
2651         return ret;
2652 }
2653
2654 /*
2655  * Class:     com_ceph_fs_CephMount
2656  * Method:    native_ceph_get_stripe_unit_granularity
2657  * Signature: (J)I
2658  */
2659 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1stripe_1unit_1granularity
2660         (JNIEnv *env, jclass clz, jlong j_mntp)
2661 {
2662         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2663         CephContext *cct = ceph_get_mount_context(cmount);
2664         int ret;
2665
2666         CHECK_MOUNTED(cmount, -1);
2667
2668         ldout(cct, 10) << "jni: get_stripe_unit_granularity" << dendl;
2669
2670         ret = ceph_get_stripe_unit_granularity(cmount);
2671
2672         ldout(cct, 10) << "jni: get_stripe_unit_granularity: exit ret " << ret << dendl;
2673
2674         if (ret < 0)
2675                 handle_error(env, ret);
2676
2677         return ret;
2678 }
2679
2680 /*
2681  * Class:     com_ceph_fs_CephMount
2682  * Method:    native_ceph_get_pool_id
2683  * Signature: (JLjava/lang/String;)I
2684  */
2685 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1id
2686   (JNIEnv *env, jclass clz, jlong j_mntp, jstring jname)
2687 {
2688         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2689         CephContext *cct = ceph_get_mount_context(cmount);
2690         const char *c_name;
2691         int ret;
2692
2693         CHECK_MOUNTED(cmount, -1);
2694         CHECK_ARG_NULL(jname, "@name is null", -1);
2695
2696         c_name = env->GetStringUTFChars(jname, NULL);
2697         if (!c_name) {
2698                 cephThrowInternal(env, "failed to pin memory");
2699                 return -1;
2700         }
2701
2702         ldout(cct, 10) << "jni: get_pool_id: name " << c_name << dendl;
2703
2704         ret = ceph_get_pool_id(cmount, c_name);
2705         if (ret < 0)
2706                 handle_error(env, ret);
2707
2708         ldout(cct, 10) << "jni: get_pool_id: ret " << ret << dendl;
2709
2710         env->ReleaseStringUTFChars(jname, c_name);
2711
2712         return ret;
2713 }
2714
2715 /*
2716  * Class:     com_ceph_fs_CephMount
2717  * Method:    native_ceph_get_pool_replication
2718  * Signature: (JI)I
2719  */
2720 JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1pool_1replication
2721   (JNIEnv *env, jclass clz, jlong j_mntp, jint jpoolid)
2722 {
2723         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2724         CephContext *cct = ceph_get_mount_context(cmount);
2725         int ret;
2726
2727         CHECK_MOUNTED(cmount, -1);
2728
2729         ldout(cct, 10) << "jni: get_pool_replication: poolid " << jpoolid << dendl;
2730
2731         ret = ceph_get_pool_replication(cmount, jpoolid);
2732         if (ret < 0)
2733                 handle_error(env, ret);
2734
2735         ldout(cct, 10) << "jni: get_pool_replication: ret " << ret << dendl;
2736
2737         return ret;
2738 }
2739
2740 /*
2741  * Class:     com_ceph_fs_CephMount
2742  * Method:    native_ceph_get_file_extent_osds
2743  * Signature: (JIJ)Lcom/ceph/fs/CephFileExtent;
2744  */
2745 JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1file_1extent_1osds
2746   (JNIEnv *env, jclass clz, jlong mntp, jint fd, jlong off)
2747 {
2748   struct ceph_mount_info *cmount = get_ceph_mount(mntp);
2749   CephContext *cct = ceph_get_mount_context(cmount);
2750   jobject extent = NULL;
2751   int ret, nosds, *osds = NULL;
2752   jintArray osd_array;
2753   loff_t len;
2754
2755         CHECK_MOUNTED(cmount, NULL);
2756
2757         ldout(cct, 10) << "jni: get_file_extent_osds: fd " << fd << " off " << off << dendl;
2758
2759   for (;;) {
2760     /* get pg size */
2761     ret = ceph_get_file_extent_osds(cmount, fd, off, NULL, NULL, 0);
2762     if (ret < 0)
2763       break;
2764
2765     /* alloc osd id array */
2766     if (osds)
2767       delete [] osds;
2768     nosds = ret;
2769     osds = new int[nosds];
2770
2771     /* get osd ids */
2772     ret = ceph_get_file_extent_osds(cmount, fd, off, &len, osds, nosds);
2773     if (ret == -ERANGE)
2774       continue;
2775     else
2776       break;
2777   }
2778
2779         ldout(cct, 10) << "jni: get_file_extent_osds: ret " << ret << dendl;
2780
2781   if (ret < 0) {
2782     handle_error(env, ret);
2783     goto out;
2784   }
2785
2786   nosds = ret;
2787
2788   osd_array = env->NewIntArray(nosds);
2789   if (!osd_array)
2790     goto out;
2791
2792   env->SetIntArrayRegion(osd_array, 0, nosds, osds);
2793   if (env->ExceptionOccurred())
2794     goto out;
2795
2796   extent = env->NewObject(cephfileextent_cls, cephfileextent_ctor_fid, off, len, osd_array);
2797   if (!extent)
2798     goto out;
2799
2800 out:
2801   if (osds)
2802     delete [] osds;
2803
2804   return extent;
2805 }
2806
2807 /*
2808  * Class:     com_ceph_fs_CephMount
2809  * Method:    native_ceph_get_osd_crush_location
2810  * Signature: (JI)[Ljava/lang/String;
2811  */
2812 JNIEXPORT jobjectArray JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1crush_1location
2813   (JNIEnv *env, jclass clz, jlong j_mntp, jint osdid)
2814 {
2815         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
2816         CephContext *cct = ceph_get_mount_context(cmount);
2817   jobjectArray path = NULL;
2818   vector<string> str_path;
2819         int ret, bufpos, buflen = 0;
2820   char *buf = NULL;
2821
2822         CHECK_MOUNTED(cmount, NULL);
2823
2824   ldout(cct, 10) << "jni: osd loc: osd " << osdid << dendl;
2825
2826   for (;;) {
2827     /* get length of the location path */
2828     ret = ceph_get_osd_crush_location(cmount, osdid, NULL, 0);
2829     if (ret < 0)
2830       break;
2831
2832     /* alloc path buffer */
2833     if (buf)
2834       delete [] buf;
2835     buflen = ret;
2836     buf = new char[buflen+1];
2837     memset(buf, 0, buflen*sizeof(*buf));
2838
2839     /* empty path */
2840     if (buflen == 0)
2841       break;
2842
2843     /* get the path */
2844     ret = ceph_get_osd_crush_location(cmount, osdid, buf, buflen);
2845     if (ret == -ERANGE)
2846       continue;
2847     else
2848       break;
2849   }
2850
2851   ldout(cct, 10) << "jni: osd loc: osd " << osdid << " ret " << ret << dendl;
2852
2853   if (ret < 0) {
2854     handle_error(env, ret);
2855     goto out;
2856   }
2857
2858   bufpos = 0;
2859   while (bufpos < ret) {
2860     string type(buf + bufpos);
2861     bufpos += type.size() + 1;
2862     string name(buf + bufpos);
2863     bufpos += name.size() + 1;
2864     str_path.push_back(type);
2865     str_path.push_back(name);
2866   }
2867
2868   path = env->NewObjectArray(str_path.size(), env->FindClass("java/lang/String"), NULL);
2869   if (!path)
2870     goto out;
2871
2872   for (unsigned i = 0; i < str_path.size(); i++) {
2873     jstring ent = env->NewStringUTF(str_path[i].c_str());
2874     if (!ent)
2875       goto out;
2876     env->SetObjectArrayElement(path, i, ent);
2877     if (env->ExceptionOccurred())
2878       goto out;
2879     env->DeleteLocalRef(ent);
2880   }
2881
2882 out:
2883   if (buf)
2884     delete [] buf;
2885
2886   return path;
2887 }
2888
2889 /*
2890  * sockaddrToInetAddress uses with the following license, and is adapted for
2891  * use in this project by using Ceph JNI exception utilities.
2892  *
2893  * ----
2894  *
2895  * Copyright (C) 2010 The Android Open Source Project
2896  *
2897  * Licensed under the Apache License, Version 2.0 (the "License");
2898  * you may not use this file except in compliance with the License.
2899  * You may obtain a copy of the License at
2900  *
2901  *      http://www.apache.org/licenses/LICENSE-2.0
2902  *
2903  * Unless required by applicable law or agreed to in writing, software
2904  * distributed under the License is distributed on an "AS IS" BASIS,
2905  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2906  * See the License for the specific language governing permissions and
2907  * limitations under the License.
2908  */
2909 jobject sockaddrToInetAddress(JNIEnv* env, const sockaddr_storage& ss, jint* port) {
2910     // Convert IPv4-mapped IPv6 addresses to IPv4 addresses.
2911     // The RI states "Java will never return an IPv4-mapped address".
2912     const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
2913     if (ss.ss_family == AF_INET6 && IN6_IS_ADDR_V4MAPPED(&sin6.sin6_addr)) {
2914         // Copy the IPv6 address into the temporary sockaddr_storage.
2915         sockaddr_storage tmp;
2916         memset(&tmp, 0, sizeof(tmp));
2917         memcpy(&tmp, &ss, sizeof(sockaddr_in6));
2918         // Unmap it into an IPv4 address.
2919         sockaddr_in& sin = reinterpret_cast<sockaddr_in&>(tmp);
2920         sin.sin_family = AF_INET;
2921         sin.sin_port = sin6.sin6_port;
2922         memcpy(&sin.sin_addr.s_addr, &sin6.sin6_addr.s6_addr[12], 4);
2923         // Do the regular conversion using the unmapped address.
2924         return sockaddrToInetAddress(env, tmp, port);
2925     }
2926
2927     const void* rawAddress;
2928     size_t addressLength;
2929     int sin_port = 0;
2930     int scope_id = 0;
2931     if (ss.ss_family == AF_INET) {
2932         const sockaddr_in& sin = reinterpret_cast<const sockaddr_in&>(ss);
2933         rawAddress = &sin.sin_addr.s_addr;
2934         addressLength = 4;
2935         sin_port = ntohs(sin.sin_port);
2936     } else if (ss.ss_family == AF_INET6) {
2937         const sockaddr_in6& sin6 = reinterpret_cast<const sockaddr_in6&>(ss);
2938         rawAddress = &sin6.sin6_addr.s6_addr;
2939         addressLength = 16;
2940         sin_port = ntohs(sin6.sin6_port);
2941         scope_id = sin6.sin6_scope_id;
2942     } else if (ss.ss_family == AF_UNIX) {
2943         const sockaddr_un& sun = reinterpret_cast<const sockaddr_un&>(ss);
2944         rawAddress = &sun.sun_path;
2945         addressLength = strlen(sun.sun_path);
2946     } else {
2947         // We can't throw SocketException. We aren't meant to see bad addresses, so seeing one
2948         // really does imply an internal error.
2949         //jniThrowExceptionFmt(env, "java/lang/IllegalArgumentException",
2950         //                     "sockaddrToInetAddress unsupported ss_family: %i", ss.ss_family);
2951         cephThrowIllegalArg(env, "sockaddrToInetAddress unsupposed ss_family");
2952         return NULL;
2953     }
2954     if (port != NULL) {
2955         *port = sin_port;
2956     }
2957
2958     ScopedLocalRef<jbyteArray> byteArray(env, env->NewByteArray(addressLength));
2959     if (byteArray.get() == NULL) {
2960         return NULL;
2961     }
2962     env->SetByteArrayRegion(byteArray.get(), 0, addressLength,
2963                             reinterpret_cast<jbyte*>(const_cast<void*>(rawAddress)));
2964
2965     if (ss.ss_family == AF_UNIX) {
2966         // Note that we get here for AF_UNIX sockets on accept(2). The unix(7) man page claims
2967         // that the peer's sun_path will contain the path, but in practice it doesn't, and the
2968         // peer length is returned as 2 (meaning only the sun_family field was set).
2969         //
2970         // Ceph Note: this isn't supported. inetUnixAddress appears to just be
2971         // something in Dalvik/Android stuff.
2972         cephThrowInternal(env, "OSD address should never be a UNIX socket");
2973         return NULL;
2974         //static jmethodID ctor = env->GetMethodID(JniConstants::inetUnixAddressClass, "<init>", "([B)V");
2975         //return env->NewObject(JniConstants::inetUnixAddressClass, ctor, byteArray.get());
2976     }
2977
2978     if (addressLength == 4) {
2979       static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inetAddressClass,
2980           "getByAddress", "(Ljava/lang/String;[B)Ljava/net/InetAddress;");
2981       if (getByAddressMethod == NULL) {
2982         return NULL;
2983       }
2984       return env->CallStaticObjectMethod(JniConstants::inetAddressClass, getByAddressMethod,
2985           NULL, byteArray.get());
2986     } else if (addressLength == 16) {
2987       static jmethodID getByAddressMethod = env->GetStaticMethodID(JniConstants::inet6AddressClass,
2988           "getByAddress", "(Ljava/lang/String;[BI)Ljava/net/Inet6Address;");
2989       if (getByAddressMethod == NULL) {
2990         return NULL;
2991       }
2992       return env->CallStaticObjectMethod(JniConstants::inet6AddressClass, getByAddressMethod,
2993           NULL, byteArray.get(), scope_id);
2994     } else {
2995       abort();
2996       return NULL;
2997     }
2998 }
2999
3000 /*
3001  * Class:     com_ceph_fs_CephMount
3002  * Method:    native_ceph_get_osd_addr
3003  * Signature: (JI)Ljava/net/InetAddress;
3004  */
3005 JNIEXPORT jobject JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1get_1osd_1addr
3006   (JNIEnv *env, jclass clz, jlong j_mntp, jint osd)
3007 {
3008         struct ceph_mount_info *cmount = get_ceph_mount(j_mntp);
3009         CephContext *cct = ceph_get_mount_context(cmount);
3010   struct sockaddr_storage addr;
3011   int ret;
3012
3013         CHECK_MOUNTED(cmount, NULL);
3014
3015   ldout(cct, 10) << "jni: get_osd_addr: osd " << osd << dendl;
3016
3017   ret = ceph_get_osd_addr(cmount, osd, &addr);
3018
3019   ldout(cct, 10) << "jni: get_osd_addr: ret " << ret << dendl;
3020
3021   if (ret < 0) {
3022     handle_error(env, ret);
3023     return NULL;
3024   }
3025
3026   return sockaddrToInetAddress(env, addr, NULL);
3027 }