diff --git a/CHANGES.txt b/CHANGES.txt index eba3b6f39cc..74d4265a974 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -266,6 +266,8 @@ Release 0.22.0 - Unreleased HADOOP-6056. Use java.net.preferIPv4Stack to force IPv4. (Michele Catasta via shv) + HADOOP-7110. Implement chmod with JNI. (todd) + OPTIMIZATIONS HADOOP-6884. Add LOG.isDebugEnabled() guard for each LOG.debug(..). diff --git a/src/java/org/apache/hadoop/fs/RawLocalFileSystem.java b/src/java/org/apache/hadoop/fs/RawLocalFileSystem.java index 053fd392def..0ecdd6241e0 100644 --- a/src/java/org/apache/hadoop/fs/RawLocalFileSystem.java +++ b/src/java/org/apache/hadoop/fs/RawLocalFileSystem.java @@ -36,6 +36,7 @@ import org.apache.hadoop.classification.InterfaceStability; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.permission.FsPermission; +import org.apache.hadoop.io.nativeio.NativeIO; import org.apache.hadoop.util.Progressable; import org.apache.hadoop.util.Shell; import org.apache.hadoop.util.StringUtils; @@ -554,8 +555,13 @@ public void setOwner(Path p, String username, String groupname) @Override public void setPermission(Path p, FsPermission permission) throws IOException { - execCommand(pathToFile(p), Shell.SET_PERMISSION_COMMAND, - String.format("%05o", permission.toShort())); + if (NativeIO.isAvailable()) { + NativeIO.chmod(pathToFile(p).getCanonicalPath(), + permission.toShort()); + } else { + execCommand(pathToFile(p), Shell.SET_PERMISSION_COMMAND, + String.format("%05o", permission.toShort())); + } } private static String execCommand(File f, String... cmd) throws IOException { diff --git a/src/java/org/apache/hadoop/io/nativeio/NativeIO.java b/src/java/org/apache/hadoop/io/nativeio/NativeIO.java index 6e16c73fb93..db4512562f8 100644 --- a/src/java/org/apache/hadoop/io/nativeio/NativeIO.java +++ b/src/java/org/apache/hadoop/io/nativeio/NativeIO.java @@ -74,6 +74,9 @@ public static boolean isAvailable() { public static native FileDescriptor open(String path, int flags, int mode) throws IOException; /** Wrapper around fstat(2) */ public static native Stat fstat(FileDescriptor fd) throws IOException; + /** Wrapper around chmod(2) */ + public static native void chmod(String path, int mode) throws IOException; + /** Initialize the JNI method ID and class ID cache */ private static native void initNative(); diff --git a/src/native/config.h.in b/src/native/config.h.in index 26f8b0fcfb2..18f5da8462b 100644 --- a/src/native/config.h.in +++ b/src/native/config.h.in @@ -82,6 +82,9 @@ /* Define to the one symbol short name of this package. */ #undef PACKAGE_TARNAME +/* Define to the home page for this package. */ +#undef PACKAGE_URL + /* Define to the version of this package. */ #undef PACKAGE_VERSION diff --git a/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c b/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c index 1c1a9896274..d55072099db 100644 --- a/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c +++ b/src/native/src/org/apache/hadoop/io/nativeio/NativeIO.c @@ -221,6 +221,25 @@ cleanup: return ret; } +/** + * public static native void chmod(String path, int mode) throws IOException; + */ +JNIEXPORT void JNICALL +Java_org_apache_hadoop_io_nativeio_NativeIO_chmod( + JNIEnv *env, jclass clazz, jstring j_path, + jint mode) +{ + const char *path = (*env)->GetStringUTFChars(env, j_path, NULL); + if (path == NULL) return; // JVM throws Exception for us + + if (chmod(path, mode) != 0) { + throw_ioe(env, errno); + } + + (*env)->ReleaseStringUTFChars(env, j_path, path); +} + + /* * Throw a java.IO.IOException, generating the message from errno. */ diff --git a/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java b/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java index 972c9fc25c8..06e02294f69 100644 --- a/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java +++ b/src/test/core/org/apache/hadoop/io/nativeio/TestNativeIO.java @@ -28,7 +28,11 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.fs.FileUtil; +import org.apache.hadoop.fs.FileSystem; +import org.apache.hadoop.fs.Path; +import org.apache.hadoop.fs.permission.FsPermission; import org.apache.hadoop.util.NativeCodeLoader; public class TestNativeIO { @@ -134,4 +138,34 @@ public void testFDDoesntLeak() throws IOException { } } + /** + * Test basic chmod operation + */ + @Test + public void testChmod() throws Exception { + try { + NativeIO.chmod("/this/file/doesnt/exist", 777); + fail("Chmod of non-existent file didn't fail"); + } catch (NativeIOException nioe) { + assertEquals(Errno.ENOENT, nioe.getErrno()); + } + + File toChmod = new File(TEST_DIR, "testChmod"); + assertTrue("Create test subject", + toChmod.exists() || toChmod.mkdir()); + NativeIO.chmod(toChmod.getAbsolutePath(), 0777); + assertPermissions(toChmod, 0777); + NativeIO.chmod(toChmod.getAbsolutePath(), 0000); + assertPermissions(toChmod, 0000); + NativeIO.chmod(toChmod.getAbsolutePath(), 0644); + assertPermissions(toChmod, 0644); + } + + private void assertPermissions(File f, int expected) throws IOException { + FileSystem localfs = FileSystem.getLocal(new Configuration()); + FsPermission perms = localfs.getFileStatus( + new Path(f.getAbsolutePath())).getPermission(); + assertEquals(expected, perms.toShort()); + } + }