Permalink
Browse files

[PLXCOMP-156] Poor performance in DirectoryArchiver due to unnecessar…

…y native chmod calls.

use dynamically if available file permission mode with jvm 1.6 methods in File
  • Loading branch information...
1 parent 04af56c commit aa74285f7a0cc87054e0ce2b0920916bda18299d olamy committed Sep 24, 2010
@@ -1,19 +1,21 @@
package org.codehaus.plexus.archiver.util;
+import java.io.File;
+import java.lang.reflect.Method;
+
import org.codehaus.plexus.archiver.ArchiverException;
import org.codehaus.plexus.logging.Logger;
import org.codehaus.plexus.util.Os;
import org.codehaus.plexus.util.cli.CommandLineException;
import org.codehaus.plexus.util.cli.CommandLineUtils;
import org.codehaus.plexus.util.cli.Commandline;
-import java.io.File;
-
public final class ArchiveEntryUtils
{
private ArchiveEntryUtils()
{
+ // no op
}
public static void chmod( File file, int mode, Logger logger )
@@ -26,12 +28,21 @@ public static void chmod( File file, int mode, Logger logger )
String m = Integer.toOctalString( mode & 0xfff );
+
+ if ( isJvmFilePermAvailable() )
+ {
+ applyPermissionsWithJvm( file, m, logger );
+ return;
+ }
+
try
{
Commandline commandline = new Commandline();
commandline.setWorkingDirectory( file.getParentFile().getAbsolutePath() );
+ logger.info( "mode " + mode + ", chmod " + m );
+
commandline.setExecutable( "chmod" );
commandline.createArg().setValue( m );
@@ -70,5 +81,54 @@ public static void chmod( File file, int mode, Logger logger )
throw new ArchiverException( "Error while executing chmod.", e );
}
}
+
+ /**
+ *
+ * @return true if file permissions for JVM are available ie is 1.6
+ */
+ private static boolean isJvmFilePermAvailable()
+ {
+ try
+ {
+ return File.class.getMethod( "setReadable", new Class[] { Boolean.class } ) != null;
+ }
+ catch ( Exception e )
+ {
+ return false;
+ }
+ }
+
+ private static void applyPermissionsWithJvm( File file, String mode, Logger logger )
+ {
+ FilePermission filePermission = FilePermissionUtils.getFilePermissionFromMode( mode, logger );
+
+ Method method;
+ try
+ {
+ method = File.class.getMethod( "setReadable", new Class[] { Boolean.class, Boolean.class } );
+
+ method.invoke( file,
+ new Object[] {
+ Boolean.valueOf( filePermission.isReadable() ),
+ Boolean.valueOf( filePermission.isOwnerOnlyReadable() ) } );
+
+ method = File.class.getMethod( "setExecutable", new Class[] { Boolean.class, Boolean.class } );
+ method.invoke( file,
+ new Object[] {
+ Boolean.valueOf( filePermission.isExecutable() ),
+ Boolean.valueOf( filePermission.isOwnerOnlyExecutable() ) } );
+
+ method = File.class.getMethod( "setWritable", new Class[] { Boolean.class, Boolean.class } );
+ method.invoke( file,
+ new Object[] {
+ Boolean.valueOf( filePermission.isWritable() ),
+ Boolean.valueOf( filePermission.isOwnerOnlyWritable() ) } );
+ }
+ catch ( Exception e )
+ {
+ logger.error( "error calling dynamically file permissons with jvm " + e.getMessage(), e );
+ throw new RuntimeException( "error calling dynamically file permissons with jvm " + e.getMessage(), e );
+ }
+ }
}
@@ -0,0 +1,120 @@
+package org.codehaus.plexus.archiver.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+/**
+ * @author Olivier Lamy
+ * @since 1.0.1
+ *
+ */
+public class FilePermission
+{
+
+ private boolean executable;
+
+ private boolean ownerOnlyExecutable;
+
+ private boolean ownerOnlyReadable;
+
+ private boolean readable;
+
+ private boolean ownerOnlyWritable;
+
+ private boolean writable;
+
+ public FilePermission( boolean executable, boolean ownerOnlyExecutable, boolean ownerOnlyReadable,
+ boolean readable, boolean ownerOnlyWritable, boolean writable )
+ {
+ this.executable = executable;
+ this.ownerOnlyExecutable = ownerOnlyExecutable;
+ this.ownerOnlyReadable = ownerOnlyReadable;
+ this.readable = readable;
+ this.ownerOnlyWritable = ownerOnlyWritable;
+ this.writable = writable;
+ }
+
+ public boolean isExecutable()
+ {
+ return executable;
+ }
+
+ public void setExecutable( boolean executable )
+ {
+ this.executable = executable;
+ }
+
+ public boolean isOwnerOnlyExecutable()
+ {
+ return ownerOnlyExecutable;
+ }
+
+ public void setOwnerOnlyExecutable( boolean ownerOnlyExecutable )
+ {
+ this.ownerOnlyExecutable = ownerOnlyExecutable;
+ }
+
+ public boolean isOwnerOnlyReadable()
+ {
+ return ownerOnlyReadable;
+ }
+
+ public void setOwnerOnlyReadable( boolean ownerOnlyReadable )
+ {
+ this.ownerOnlyReadable = ownerOnlyReadable;
+ }
+
+ public boolean isReadable()
+ {
+ return readable;
+ }
+
+ public void setReadable( boolean readable )
+ {
+ this.readable = readable;
+ }
+
+ public boolean isOwnerOnlyWritable()
+ {
+ return ownerOnlyWritable;
+ }
+
+ public void setOwnerOnlyWritable( boolean ownerOnlyWritable )
+ {
+ this.ownerOnlyWritable = ownerOnlyWritable;
+ }
+
+ public boolean isWritable()
+ {
+ return writable;
+ }
+
+ public void setWritable( boolean writable )
+ {
+ this.writable = writable;
+ }
+
+ public String toString()
+ {
+ return "FilePermission [executable=" + executable + ", ownerOnlyExecutable=" + ownerOnlyExecutable
+ + ", ownerOnlyReadable=" + ownerOnlyReadable + ", readable=" + readable + ", ownerOnlyWritable="
+ + ownerOnlyWritable + ", writable=" + writable + "]";
+ }
+
+}
@@ -0,0 +1,163 @@
+package org.codehaus.plexus.archiver.util;
+
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.codehaus.plexus.logging.Logger;
+import org.codehaus.plexus.util.StringUtils;
+
+
+
+/**
+ * @author Olivier Lamy
+ * @since 1.0.1
+ *
+ */
+public class FilePermissionUtils
+{
+ private FilePermissionUtils()
+ {
+ // no op
+ }
+
+ /**
+ * @param mode file mode "a la" unix ie 664, 440, etc
+ * @return FilePermission associated to the mode (group permission are ignored here)
+ */
+ public static FilePermission getFilePermissionFromMode( String mode, Logger logger )
+ {
+ if ( StringUtils.isBlank( mode ) )
+ {
+ throw new IllegalArgumentException( " file mode cannot be empty" );
+ }
+ // 4 characters works on some unix (ie solaris)
+ if ( mode.length() != 3 && mode.length() != 4 )
+ {
+ throw new IllegalArgumentException( " file mode must be 3 or 4 characters" );
+ }
+
+
+
+ List modes = new ArrayList(mode.length());
+ for (int i = 0,size = mode.length();i<size;i++)
+ {
+ modes.add( String.valueOf( mode.charAt( i ) ) );
+ }
+
+ boolean executable = false, ownerOnlyExecutable = true, ownerOnlyReadable = true, readable = false, ownerOnlyWritable = true, writable = false;
+
+ // handle user perm
+ try
+ {
+ int userMode = Integer.valueOf( (String) modes.get( mode.length() == 4 ? 1 : 0 ) ).intValue();
+ switch ( userMode )
+ {
+ case 0 :
+ break;
+ case 1:
+ executable = true;
+ break;
+ case 2:
+ writable = true;
+ break;
+ case 3:
+ writable = true;
+ executable = true;
+ break;
+ case 4:
+ readable = true;
+ break;
+ case 5:
+ readable = true;
+ executable = true;
+ break;
+
+ case 7:
+ writable = true;
+ readable = true;
+ executable = true;
+ break;
+ default:
+ logger.warn( "ignore file mode " + userMode );
+ }
+ }
+ catch ( NumberFormatException e )
+ {
+ throw new IllegalArgumentException( " file mode must contains only number " + mode );
+ }
+
+
+ // handle all perm
+ try
+ {
+ int allMode = Integer.valueOf( (String) modes.get( mode.length() == 4 ? 3 : 2 ) ).intValue();
+ switch ( allMode )
+ {
+ case 0 :
+ break;
+ case 1:
+ executable = true;
+ ownerOnlyExecutable = false;
+ break;
+ case 2:
+ writable = true;
+ ownerOnlyWritable = false;
+ break;
+ case 3:
+ writable = true;
+ executable = true;
+ ownerOnlyExecutable = false;
+ ownerOnlyWritable = false;
+ break;
+ case 4:
+ readable = true;
+ ownerOnlyReadable = false;
+ break;
+ case 5:
+ readable = true;
+ executable = true;
+ ownerOnlyReadable = false;
+ ownerOnlyExecutable = false;
+ break;
+
+ case 7:
+ writable = true;
+ readable = true;
+ executable = true;
+ ownerOnlyReadable = false;
+ ownerOnlyExecutable = false;
+ ownerOnlyWritable = false;
+ break;
+ default:
+ logger.warn( "ignore file mode " + allMode );
+ }
+ }
+ catch ( NumberFormatException e )
+ {
+ throw new IllegalArgumentException( " file mode must contains only number " + mode );
+ }
+
+ return new FilePermission( executable, ownerOnlyExecutable, ownerOnlyReadable, readable, ownerOnlyWritable,
+ writable );
+ }
+
+}
Oops, something went wrong.

0 comments on commit aa74285

Please sign in to comment.