From 4b3bcb9226f1fb27b7d36e6032c94f3196b244f6 Mon Sep 17 00:00:00 2001 From: Noah Watkins Date: Sun, 23 Dec 2012 15:32:56 -0800 Subject: [PATCH] java: support stat() Signed-off-by: Noah Watkins --- src/java/java/com/ceph/fs/CephMount.java | 17 ++++ src/java/native/libcephfs_jni.cc | 89 ++++++++++++++----- src/java/test/com/ceph/fs/CephMountTest.java | 36 +++++++- .../test/com/ceph/fs/CephUnmountedTest.java | 6 ++ 4 files changed, 126 insertions(+), 22 deletions(-) diff --git a/src/java/java/com/ceph/fs/CephMount.java b/src/java/java/com/ceph/fs/CephMount.java index 10036f6c76882..76b4dab12c345 100644 --- a/src/java/java/com/ceph/fs/CephMount.java +++ b/src/java/java/com/ceph/fs/CephMount.java @@ -432,6 +432,23 @@ public class CephMount { * @param path Path of file to stat. * @param stat CephStat structure to hold file status. */ + public void stat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException { + rlock.lock(); + try { + native_ceph_stat(instance_ptr, path, stat); + } finally { + rlock.unlock(); + } + } + + private static native int native_ceph_stat(long mountp, String path, CephStat stat); + + /** + * Get file status, without following symlinks. + * + * @param path Path of file to stat. + * @param stat CephStat structure to hold file status. + */ public void lstat(String path, CephStat stat) throws FileNotFoundException, CephNotDirectoryException { rlock.lock(); try { diff --git a/src/java/native/libcephfs_jni.cc b/src/java/native/libcephfs_jni.cc index 2fef171a976a2..2b9c9cee84791 100644 --- a/src/java/native/libcephfs_jni.cc +++ b/src/java/native/libcephfs_jni.cc @@ -1189,6 +1189,35 @@ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1symlink return ret; } +static void fill_cephstat(JNIEnv *env, jobject j_cephstat, struct stat *st) +{ + env->SetIntField(j_cephstat, cephstat_mode_fid, st->st_mode); + env->SetIntField(j_cephstat, cephstat_uid_fid, st->st_uid); + env->SetIntField(j_cephstat, cephstat_gid_fid, st->st_gid); + env->SetLongField(j_cephstat, cephstat_size_fid, st->st_size); + env->SetLongField(j_cephstat, cephstat_blksize_fid, st->st_blksize); + env->SetLongField(j_cephstat, cephstat_blocks_fid, st->st_blocks); + + long long time = st->st_mtim.tv_sec; + time *= 1000; + time += st->st_mtim.tv_nsec / 1000000; + env->SetLongField(j_cephstat, cephstat_m_time_fid, time); + + time = st->st_atim.tv_sec; + time *= 1000; + time += st->st_atim.tv_nsec / 1000000; + env->SetLongField(j_cephstat, cephstat_a_time_fid, time); + + env->SetBooleanField(j_cephstat, cephstat_is_file_fid, + S_ISREG(st->st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_cephstat, cephstat_is_directory_fid, + S_ISDIR(st->st_mode) ? JNI_TRUE : JNI_FALSE); + + env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid, + S_ISLNK(st->st_mode) ? JNI_TRUE : JNI_FALSE); +} + /* * Class: com_ceph_fs_CephMount * Method: native_ceph_lstat @@ -1200,7 +1229,6 @@ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lstat struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); CephContext *cct = ceph_get_mount_context(cmount); const char *c_path; - long long time; struct stat st; int ret; @@ -1227,35 +1255,54 @@ JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1lstat return ret; } - env->SetIntField(j_cephstat, cephstat_mode_fid, st.st_mode); - env->SetIntField(j_cephstat, cephstat_uid_fid, st.st_uid); - env->SetIntField(j_cephstat, cephstat_gid_fid, st.st_gid); - env->SetLongField(j_cephstat, cephstat_size_fid, st.st_size); - env->SetLongField(j_cephstat, cephstat_blksize_fid, st.st_blksize); - env->SetLongField(j_cephstat, cephstat_blocks_fid, st.st_blocks); + fill_cephstat(env, j_cephstat, &st); - time = st.st_mtim.tv_sec; - time *= 1000; - time += st.st_mtim.tv_nsec / 1000000; - env->SetLongField(j_cephstat, cephstat_m_time_fid, time); + return ret; +} - time = st.st_atim.tv_sec; - time *= 1000; - time += st.st_atim.tv_nsec / 1000000; - env->SetLongField(j_cephstat, cephstat_a_time_fid, time); +/* + * Class: com_ceph_fs_CephMount + * Method: native_ceph_stat + * Signature: (JLjava/lang/String;Lcom/ceph/fs/CephStat;)I + */ +JNIEXPORT jint JNICALL Java_com_ceph_fs_CephMount_native_1ceph_1stat + (JNIEnv *env, jclass clz, jlong j_mntp, jstring j_path, jobject j_cephstat) +{ + struct ceph_mount_info *cmount = get_ceph_mount(j_mntp); + CephContext *cct = ceph_get_mount_context(cmount); + const char *c_path; + struct stat st; + int ret; - env->SetBooleanField(j_cephstat, cephstat_is_file_fid, - S_ISREG(st.st_mode) ? JNI_TRUE : JNI_FALSE); + CHECK_ARG_NULL(j_path, "@path is null", -1); + CHECK_ARG_NULL(j_cephstat, "@stat is null", -1); + CHECK_MOUNTED(cmount, -1); - env->SetBooleanField(j_cephstat, cephstat_is_directory_fid, - S_ISDIR(st.st_mode) ? JNI_TRUE : JNI_FALSE); + c_path = env->GetStringUTFChars(j_path, NULL); + if (!c_path) { + cephThrowInternal(env, "Failed to pin memory"); + return -1; + } - env->SetBooleanField(j_cephstat, cephstat_is_symlink_fid, - S_ISLNK(st.st_mode) ? JNI_TRUE : JNI_FALSE); + ldout(cct, 10) << "jni: lstat: path " << c_path << dendl; + + ret = ceph_stat(cmount, c_path, &st); + + ldout(cct, 10) << "jni: lstat exit ret " << ret << dendl; + + env->ReleaseStringUTFChars(j_path, c_path); + + if (ret) { + handle_error(env, ret); + return ret; + } + + fill_cephstat(env, j_cephstat, &st); return ret; } + /* * Class: com_ceph_fs_CephMount * Method: native_ceph_setattr diff --git a/src/java/test/com/ceph/fs/CephMountTest.java b/src/java/test/com/ceph/fs/CephMountTest.java index 984c2cb737755..cc351cc792f90 100644 --- a/src/java/test/com/ceph/fs/CephMountTest.java +++ b/src/java/test/com/ceph/fs/CephMountTest.java @@ -451,7 +451,9 @@ public class CephMountTest { } /* - * test_stat covers lstat and fstat + * test_stat covers lstat and fstat and stat. + * + * TODO: create test that for lstat vs stat with symlink follow/nofollow. */ @Test @@ -469,6 +471,10 @@ public class CephMountTest { assertTrue(orig_st.blksize > 0); assertTrue(orig_st.blocks > 0); + /* now try stat */ + CephStat stat_st = new CephStat(); + mount.stat(path, stat_st); + /* now try fstat */ CephStat other_st = new CephStat(); fd = mount.open(path, CephMount.O_RDWR, 0); @@ -477,12 +483,40 @@ public class CephMountTest { mount.unlink(path); + /* compare to fstat results */ assertTrue(orig_st.mode == other_st.mode); assertTrue(orig_st.uid == other_st.uid); assertTrue(orig_st.gid == other_st.gid); assertTrue(orig_st.size == other_st.size); assertTrue(orig_st.blksize == other_st.blksize); assertTrue(orig_st.blocks == other_st.blocks); + + /* compare to stat results */ + assertTrue(orig_st.mode == stat_st.mode); + assertTrue(orig_st.uid == stat_st.uid); + assertTrue(orig_st.gid == stat_st.gid); + assertTrue(orig_st.size == stat_st.size); + assertTrue(orig_st.blksize == stat_st.blksize); + assertTrue(orig_st.blocks == stat_st.blocks); + } + + /* + * stat + */ + + @Test(expected=NullPointerException.class) + public void test_stat_null_path() throws Exception { + mount.stat(null, new CephStat()); + } + + @Test(expected=NullPointerException.class) + public void test_stat_null_stat() throws Exception { + mount.stat("/path", null); + } + + @Test(expected=FileNotFoundException.class) + public void test_stat_null_dne() throws Exception { + mount.stat("/path/does/not/exist", new CephStat()); } @Test(expected=CephNotDirectoryException.class) diff --git a/src/java/test/com/ceph/fs/CephUnmountedTest.java b/src/java/test/com/ceph/fs/CephUnmountedTest.java index ae4d41e1e984b..602bd5ad4d664 100644 --- a/src/java/test/com/ceph/fs/CephUnmountedTest.java +++ b/src/java/test/com/ceph/fs/CephUnmountedTest.java @@ -77,6 +77,12 @@ public class CephUnmountedTest { mount.rmdir("/a/path"); } + @Test(expected=CephNotMountedException.class) + public void test_stat() throws Exception { + CephStat stat = new CephStat(); + mount.stat("/a/path", stat); + } + @Test(expected=CephNotMountedException.class) public void test_lstat() throws Exception { CephStat stat = new CephStat(); -- 2.39.5