diff --git a/libjava/ChangeLog b/libjava/ChangeLog index f6fede309c0..c019eaeb803 100644 --- a/libjava/ChangeLog +++ b/libjava/ChangeLog @@ -1,13 +1,42 @@ +Sun Aug 20 21:02:48 2000 Anthony Green + + * java/lang/natSystem.cc (init_properties): Change sourceware + reference to sources.redhat.com. + + * include/java-props.h: Add _Jv_Jar_Class_Path. + * prims.cc: Ditto. Set it from `gij -jar file' option. + + * java/lang/natSystem.cc (init_properties): Set java.class.path + from + {gij -jar file}:{CLASSPATH variable}:{-Djava.class.path= or .} + + * java/util/PropertyPermission.java: Import from GNU Classpath. + * Makefile.in: Rebuilt. + * Makefile.am: Add java/util/PropertyPermission.java. + * java/lang/System.java: Add setProperty method. + + * gij.cc (main): Add -jar option to execute jar files. + (help): Describe -jar option. + * prims.cc (_Jv_RunMain): Add support for jar execution mode. + * gnu/gcj/tools/Gij.java: New file. + * include/jvm.h: Add is_jar argument to _Jv_RunMain. + * gnu/gcj/runtime/FirstThread.java (main): New method. + + * java/util/jar/Attributes.java: Correct comment spelling. + 2000-08-20 Mark Wielaard * java/util/zip/Adler32.java: Make private variables really private * java/util/zip/CRC32.java: Make private variables really private - * java/util/zip/CheckedInputStream.java: skip() could skip to much bytes - * java/util/zip/InflaterInputStream.java: skip() could skip to much bytes + * java/util/zip/CheckedInputStream.java: skip() could skip to much + bytes + * java/util/zip/InflaterInputStream.java: skip() could skip to + much bytes * java/util/zip/ZipEntry.java: setCompressedSize() didn't check input * java/util/zip/ZipFile.java: size() new 1.2 method - * java/util/zip/ZipInputStream.java: Use createZipEntry not new ZipEntry. - since 1.2 available() always returns just 1 or 0 when closed + * java/util/zip/ZipInputStream.java: Use createZipEntry not new + ZipEntry. since 1.2 available() always returns just 1 or 0 when + closed Sun Aug 20 12:33:43 2000 Anthony Green diff --git a/libjava/Makefile.am b/libjava/Makefile.am index 8c04f661da5..900987854b9 100644 --- a/libjava/Makefile.am +++ b/libjava/Makefile.am @@ -1057,6 +1057,7 @@ java/util/NoSuchElementException.java \ java/util/Observable.java \ java/util/Observer.java \ java/util/Properties.java \ +java/util/PropertyPermission.java \ java/util/PropertyResourceBundle.java \ java/util/Random.java \ java/util/ResourceBundle.java \ diff --git a/libjava/Makefile.in b/libjava/Makefile.in index f35fab45dbf..33aca70afbd 100644 --- a/libjava/Makefile.in +++ b/libjava/Makefile.in @@ -827,6 +827,7 @@ java/util/NoSuchElementException.java \ java/util/Observable.java \ java/util/Observer.java \ java/util/Properties.java \ +java/util/PropertyPermission.java \ java/util/PropertyResourceBundle.java \ java/util/Random.java \ java/util/ResourceBundle.java \ @@ -1443,6 +1444,7 @@ DEP_FILES = .deps/$(srcdir)/$(CONVERT_DIR)/gen-from-JIS.P \ .deps/java/util/MissingResourceException.P \ .deps/java/util/NoSuchElementException.P .deps/java/util/Observable.P \ .deps/java/util/Observer.P .deps/java/util/Properties.P \ +.deps/java/util/PropertyPermission.P \ .deps/java/util/PropertyResourceBundle.P .deps/java/util/Random.P \ .deps/java/util/ResourceBundle.P .deps/java/util/Set.P \ .deps/java/util/SimpleTimeZone.P .deps/java/util/Stack.P \ diff --git a/libjava/gij.cc b/libjava/gij.cc index 54674a9d2c8..7d53beb2abb 100644 --- a/libjava/gij.cc +++ b/libjava/gij.cc @@ -24,8 +24,10 @@ details. */ static void help () { - printf ("Usage: gij [OPTION] ... CLASS [ARGS] ...\n\n"); - printf ("Interpret Java bytecodes\n\n"); + printf ("Usage: gij [OPTION] ... CLASS [ARGS] ...\n"); + printf (" to interpret Java bytecodes, or\n"); + printf (" gij -jar [OPTION] ... JARFILE [ARGS] ...\n"); + printf (" to execute a jar file\n\n"); printf (" -DVAR=VAL define property VAR with value VAL\n"); printf (" --help print this help, then exit\n"); printf (" --ms=NUMBER set initial heap size\n"); @@ -51,6 +53,7 @@ main (int argc, const char **argv) /* We rearrange ARGV so that all the -D options appear near the beginning. */ int last_D_option = 0; + bool jar_mode = false; int i; for (i = 1; i < argc; ++i) @@ -73,6 +76,12 @@ main (int argc, const char **argv) continue; } + if (! strcmp (arg, "-jar")) + { + jar_mode = true; + continue; + } + /* Allow both single or double hyphen for all remaining options. */ if (arg[1] == '-') @@ -120,9 +129,12 @@ main (int argc, const char **argv) if (argc - i < 1) { fprintf (stderr, "Usage: gij [OPTION] ... CLASS [ARGS] ...\n"); + fprintf (stderr, " to interpret Java bytecodes, or\n"); + fprintf (stderr, " gij -jar [OPTION] ... JARFILE [ARGS] ...\n"); + fprintf (stderr, " to execute a jar file\n"); fprintf (stderr, "Try `gij --help' for more information.\n"); exit (1); } - _Jv_RunMain (argv[i], argc - i, argv + i); + _Jv_RunMain (argv[i], argc - i, argv + i, jar_mode); } diff --git a/libjava/gnu/gcj/runtime/FirstThread.java b/libjava/gnu/gcj/runtime/FirstThread.java index c7f521c5fc9..21022250713 100644 --- a/libjava/gnu/gcj/runtime/FirstThread.java +++ b/libjava/gnu/gcj/runtime/FirstThread.java @@ -10,6 +10,8 @@ details. */ package gnu.gcj.runtime; +import java.util.jar.*; + /** * @author Tom Tromey * @date August 24, 1998 @@ -43,6 +45,27 @@ final class FirstThread extends Thread System.exit(1); } + public static void main (String[] args) + { + try { + + JarFile j = new JarFile (args[0]); + + Attributes a = j.getManifest().getMainAttributes(); + + jarMainClassName = a.getValue(Attributes.Name.MAIN_CLASS); + + } catch (Exception e) { + + System.err.println ("Failed to load Main-Class manifest attribute from\n" + args[0]); + + } + } + + // If interpreter is invoked with -jar, the main class name is recorded + // here. + public static String jarMainClassName; + // Private data. private Class klass; private String klass_name; diff --git a/libjava/include/java-props.h b/libjava/include/java-props.h index f7e6d36f82a..9be30996ebc 100644 --- a/libjava/include/java-props.h +++ b/libjava/include/java-props.h @@ -22,6 +22,9 @@ typedef struct // Set to NULL-terminated list of properties set at compile time. extern const char **_Jv_Compiler_Properties; +// The JAR file to add to the beginning of java.class.path. +extern const char *_Jv_Jar_Class_Path; + // Properties taken from the user's environment. extern property_pair *_Jv_Environment_Properties; diff --git a/libjava/include/jvm.h b/libjava/include/jvm.h index 5d5e0b9b24b..65178851085 100644 --- a/libjava/include/jvm.h +++ b/libjava/include/jvm.h @@ -157,7 +157,7 @@ void _Jv_SetMaximumHeapSize (const char *arg); void *_Jv_AllocBytesChecked (jsize size) __attribute__((__malloc__)); extern "C" void JvRunMain (jclass klass, int argc, const char **argv); -void _Jv_RunMain (const char* name, int argc, const char **argv); +void _Jv_RunMain (const char* name, int argc, const char **argv, bool is_jar); // This function is used to determine the hash code of an object. inline jint diff --git a/libjava/java/lang/System.java b/libjava/java/lang/System.java index b94c259195b..52dbe75988e 100644 --- a/libjava/java/lang/System.java +++ b/libjava/java/lang/System.java @@ -19,6 +19,7 @@ import java.io.PrintStream; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.util.Properties; +import java.util.PropertyPermission; /** * @author Tom Tromey @@ -132,8 +133,12 @@ public final class System properties = props; } - // TODO 1.2. - // public static String setProperty (String key, String value); + public static String setProperty (String key, String value) + { + if (secman != null) + secman.checkPermission (new PropertyPermission (key, "write")); + return (String) properties.setProperty (key, value); + } // TODO 1.2. // public static String mapLibraryName (String libname); diff --git a/libjava/java/lang/natSystem.cc b/libjava/java/lang/natSystem.cc index 2d82c896a07..81f7860dad0 100644 --- a/libjava/java/lang/natSystem.cc +++ b/libjava/java/lang/natSystem.cc @@ -32,6 +32,7 @@ details. */ #include #include #include +#include #include #include #include @@ -216,7 +217,7 @@ java::lang::System::init_properties (void) // (introduced in 1.2), and earlier versioning properties. SET ("java.version", VERSION); SET ("java.vendor", "Free Software Foundation"); - SET ("java.vendor.url", "http://sourceware.cygnus.com/java/"); + SET ("java.vendor.url", "http://sources.redhat.com/java/"); SET ("java.class.version", GCJVERSION); SET ("java.vm.specification.version", "1.1"); SET ("java.vm.specification.name", "Java(tm) Virtual Machine Specification"); @@ -263,13 +264,6 @@ java::lang::System::init_properties (void) } #endif /* HAVE_UNAME */ - char *classpath = ::getenv("CLASSPATH"); - // FIXME: find libgcj.zip and append its path? - if (classpath != NULL) - SET ("java.class.path", classpath); - else - SET ("java.class.path", "."); - #ifndef NO_GETUID #ifdef HAVE_PWD_H uid_t user_id = getuid (); @@ -353,4 +347,35 @@ java::lang::System::init_properties (void) i++; } } + + // FIXME: find libgcj.zip and append its path? + char *classpath = ::getenv("CLASSPATH"); + jstring cp = properties->getProperty (JvNewStringLatin1("java.class.path")); + java::lang::StringBuffer *sb = new java::lang::StringBuffer (); + + if (_Jv_Jar_Class_Path) + { + sb->append (JvNewStringLatin1 (_Jv_Jar_Class_Path)); +#ifdef WIN32 + sb->append ((jchar) ';'); +#else + sb->append ((jchar) ':'); +#endif; + } + if (classpath) + { + sb->append (JvNewStringLatin1 (classpath)); +#ifdef WIN32 + sb->append ((jchar) ';'); +#else + sb->append ((jchar) ':'); +#endif; + } + if (cp != NULL) + sb->append (cp); + else + sb->append ((jchar) '.'); + + properties->put(JvNewStringLatin1 ("java.class.path"), + sb->toString ()); } diff --git a/libjava/java/util/PropertyPermission.java b/libjava/java/util/PropertyPermission.java new file mode 100644 index 00000000000..8d004c0b352 --- /dev/null +++ b/libjava/java/util/PropertyPermission.java @@ -0,0 +1,238 @@ +/* java.util.PropertyPermission + Copyright (C) 1999 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +As a special exception, if you link this library with other files to +produce an executable, this library does not by itself cause the +resulting executable to be covered by the GNU General Public License. +This exception does not however invalidate any other reasons why the +executable file might be covered by the GNU General Public License. */ + + +package java.util; +import java.security.Permission; +import java.security.BasicPermission; +import java.security.PermissionCollection; +import java.io.ObjectStreamField; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.IOException; + +/** + * This class represents the permission to access and modify a property.
+ * + * The name is the name of the property, e.g. xxx. You can also + * use an asterisk "*" as described in BasicPermission
+ * + * The action string is a comma-separated list if keywords. There are + * two possible actions: + *
+ *
read
+ *
Allows to read the property via System.getProperty.
+ *
write
+ *
Allows to write the property via System.setProperty.
+ *
+ * + * The action string is case insensitive (it is converted to lower case). + * + * @see Permission + * @see BasicPermission + * @author Jochen Hoenicke + */ +public final class PropertyPermission extends BasicPermission +{ + /** + * @serialField action String + * The action string. + */ + private static final ObjectStreamField[] serialPersistentFields = + { + new ObjectStreamField("action", String.class) + }; + + private static final long serialVersionUID = 885438825399942851L; + + private static final int READ = 1; + private static final int WRITE = 2; + private transient int actions; + + private static String actionStrings[] = + { + "", "read", "write", "read,write" + }; + + /** + * Constructs a PropertyPermission witha he specified property. Possible + * actions are read and write. + * @param name the name of the property. + * @param actions the action string. + * @exception IllegalArgumentException if name string contains an + * illegal wildcard or actions string contains an illegal action + */ + public PropertyPermission(String name, String actions) + { + super(name); + setActions(actions.toLowerCase()); + } + + /** + * Parse the action string and convert actions from external to internal + * form. This will set the internal actions field. + * @param actions the action string. + * @exception IllegalArgumentException if actions string contains an + * illegal action */ + private void setActions(String actions) + { + this.actions = 0; + StringTokenizer actionTokenizer = new StringTokenizer(actions, ","); + while (actionTokenizer.hasMoreElements()) + { + String anAction = actionTokenizer.nextToken(); + if ("read".equals(anAction)) + this.actions |= READ; + else if ("write".equals(anAction)) + this.actions |= WRITE; + else + throw new IllegalArgumentException("illegal action "+anAction); + } + } + + /** + * Check if this permission implies p. This returns true iff all of + * the following conditions are true: + *
    + *
  • p is a PropertyPermission
  • + *
  • this.getName() implies p.getName(), + * e.g. java.* implies java.home
  • + *
  • this.getActions is a subset of p.getActions
  • + *
+ */ + public boolean implies(Permission p) + { + if (!(p instanceof PropertyPermission)) + return false; + + // We have to check the actions. + PropertyPermission pp = (PropertyPermission) p; + if ((pp.actions & ~actions) != 0) + return false; + + // BasicPermission checks for name. + if (!super.implies(p)) + return false; + + return true; + } + + /** + * Returns the action string. Note that this may differ from the string + * given at the constructor: The actions are converted to lowercase and + * may be reordered. + */ + public String getActions() + { + return actionStrings[actions]; + } + + /** + * Reads an object from the stream. This converts the external to the + * internal representation. + */ + private void readObject(ObjectInputStream s) + throws IOException, ClassNotFoundException + { + ObjectInputStream.GetField fields = s.readFields(); + setActions((String) fields.get("actions", null)); + } + + /** + * Writes an object to the stream. This converts the internal to the + * external representation. + */ + private void writeObject(ObjectOutputStream s) + throws IOException + { + ObjectOutputStream.PutField fields = s.putFields(); + fields.put("actions", getActions()); + s.writeFields(); + } + + /** + * Returns a permission collection suitable to take + * PropertyPermission objects. + * @return a new empty PermissionCollection. + */ + public PermissionCollection newPermissionCollection() + { + return new PermissionCollection() + { + Hashtable permissions = new Hashtable(); + int allActions = 0; + + public void add(Permission permission) + { + if (isReadOnly()) + throw new IllegalStateException("readonly"); + + // also check that permission is of correct type. + PropertyPermission pp = (PropertyPermission) permission; + String name = pp.getName(); + if (name.equals("*")) + allActions |= pp.actions; + permissions.put(name, pp); + } + + public boolean implies(Permission permission) + { + if (!(permission instanceof PropertyPermission)) + return false; + + PropertyPermission toImply = (PropertyPermission) permission; + if ((toImply.actions & ~allActions) == 0) + return true; + + String name = toImply.getName(); + if (name.equals("*")) + return false; + + int prefixLength = name.length(); + if (name.endsWith("*")) + prefixLength -= 2; + + while (true) { + PropertyPermission forName = + (PropertyPermission) permissions.get(name); + if (forName != null + && (toImply.actions & ~forName.actions) == 0) + return true; + + prefixLength = name.lastIndexOf('.', prefixLength); + if (prefixLength < 0) + return false; + name = name.substring(0, prefixLength + 1) + '*'; + } + } + + public Enumeration elements() + { + return permissions.elements(); + } + }; + } +} diff --git a/libjava/java/util/jar/Attributes.java b/libjava/java/util/jar/Attributes.java index 587f4a1d130..6a01be57a19 100644 --- a/libjava/java/util/jar/Attributes.java +++ b/libjava/java/util/jar/Attributes.java @@ -460,7 +460,7 @@ public class Attributes implements Cloneable, Map { } /** - * Gives a Set of atrribute name and values pairs as MapEntries. + * Gives a Set of attribute name and values pairs as MapEntries. * @see java.util.Map.Entry * @see java.util.Map#entrySet() * diff --git a/libjava/prims.cc b/libjava/prims.cc index 817b0a8a46a..38714b300d9 100644 --- a/libjava/prims.cc +++ b/libjava/prims.cc @@ -79,6 +79,9 @@ static java::lang::OutOfMemoryError *no_memory; // Properties set at compile time. const char **_Jv_Compiler_Properties; +// The JAR file to add to the beginning of java.class.path. +const char *_Jv_Jar_Class_Path; + #ifndef DISABLE_GETENV_PROPERTIES // Property key/value pairs. property_pair *_Jv_Environment_Properties; @@ -888,8 +891,9 @@ JvRunMain (jclass klass, int argc, const char **argv) } void -_Jv_RunMain (const char *class_name, int argc, const char **argv) +_Jv_RunMain (const char *name, int argc, const char **argv, bool is_jar) { + jstring class_name; PROCESS_GCJ_PROPERTIES; main_init (); @@ -900,12 +904,31 @@ _Jv_RunMain (const char *class_name, int argc, const char **argv) _Jv_ThisExecutable (exec_name); #endif - arg_vec = JvConvertArgv (argc - 1, argv + 1); - main_thread = new gnu::gcj::runtime::FirstThread (JvNewStringLatin1 (class_name), - arg_vec); - main_thread->start(); - _Jv_ThreadWait (); + if (is_jar) + { + _Jv_Jar_Class_Path = strdup (name); + arg_vec = JvConvertArgv (1, &_Jv_Jar_Class_Path); + main_thread = + new gnu::gcj::runtime::FirstThread (&_CL_Q43gnu3gcj7runtime11FirstThread, + arg_vec); + main_thread->start(); + _Jv_ThreadWait (); + + class_name = gnu::gcj::runtime::FirstThread::jarMainClassName; + } + else + class_name = JvNewStringLatin1 (name); + + arg_vec = JvConvertArgv (argc - 1, argv + 1); + + if (class_name) + { + main_thread = new gnu::gcj::runtime::FirstThread (class_name, arg_vec); + main_thread->start(); + _Jv_ThreadWait (); + } + java::lang::Runtime::getRuntime ()->exit (0); }