LCOV - code coverage report
Current view: top level - vm - suck.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 104 143 72.7 %
Date: 2017-07-14 10:03:36 Functions: 6 10 60.0 %

          Line data    Source code
       1             : /* src/vm/suck.cpp - functions to read LE ordered types from a buffer
       2             : 
       3             :    Copyright (C) 1996-2012
       4             :    CACAOVM - Verein zur Foerderung der freien virtuellen Maschine CACAO
       5             : 
       6             :    This file is part of CACAO.
       7             : 
       8             :    This program is free software; you can redistribute it and/or
       9             :    modify it under the terms of the GNU General Public License as
      10             :    published by the Free Software Foundation; either version 2, or (at
      11             :    your option) any later version.
      12             : 
      13             :    This program is distributed in the hope that it will be useful, but
      14             :    WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16             :    General Public License for more details.
      17             : 
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program; if not, write to the Free Software
      20             :    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
      21             :    02110-1301, USA.
      22             : 
      23             : */
      24             : 
      25             : 
      26             : #include "config.h"
      27             : 
      28             : #include <cassert>
      29             : #include <cstdlib>
      30             : 
      31             : #include "vm/types.hpp"
      32             : 
      33             : #include "mm/memory.hpp"
      34             : 
      35             : #include "threads/mutex.hpp"
      36             : 
      37             : #include "toolbox/buffer.hpp"
      38             : #include "toolbox/endianess.hpp"
      39             : #include "toolbox/hashtable.hpp"
      40             : #include "toolbox/list.hpp"
      41             : #include "toolbox/logging.hpp"
      42             : 
      43             : #include "vm/exceptions.hpp"
      44             : #include "vm/loader.hpp"
      45             : #include "vm/options.hpp"
      46             : #include "vm/os.hpp"
      47             : #include "vm/properties.hpp"
      48             : #include "vm/suck.hpp"
      49             : #include "vm/vm.hpp"
      50             : #include "vm/zip.hpp"
      51             : 
      52             : using namespace cacao;
      53             : 
      54             : 
      55             : /* scandir_filter **************************************************************
      56             : 
      57             :    Filters for zip/jar files.
      58             : 
      59             : *******************************************************************************/
      60             : 
      61           0 : static int scandir_filter(const struct dirent *a)
      62             : {
      63             :         s4 namlen;
      64             : 
      65             : #if defined(_DIRENT_HAVE_D_NAMLEN)
      66             :         namlen = a->d_namlen;
      67             : #else
      68           0 :         namlen = strlen(a->d_name);
      69             : #endif
      70             : 
      71           0 :         if ((strncasecmp(a->d_name + namlen - 4, ".zip", 4) == 0) ||
      72             :                 (strncasecmp(a->d_name + namlen - 4, ".jar", 4) == 0))
      73           0 :                 return 1;
      74             : 
      75           0 :         return 0;
      76             : }
      77             : 
      78             : 
      79             : /**
      80             :  * Adds a classpath to the global classpath entries list.
      81             :  */
      82         163 : void SuckClasspath::add(char *classpath)
      83             : {
      84             :         char                 *start;
      85             :         char                 *end;
      86             :         char                 *cwd;
      87             :         s4                    cwdlen;
      88             : 
      89             :         /* parse the classpath string */
      90             : 
      91         653 :         for (start = classpath; (*start) != '\0'; ) {
      92             : 
      93             :                 /* search for ':' delimiter to get the end of the current entry */
      94         327 :                 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
      95             : 
      96         327 :                 if (start != end) {
      97         327 :                         bool   is_zip      = false;
      98         327 :                         size_t filenamelen = end - start;
      99             : 
     100         327 :                         if (filenamelen > 4) {
     101         327 :                                 if ((strncasecmp(end - 4, ".zip", 4) == 0) ||
     102             :                                         (strncasecmp(end - 4, ".jar", 4) == 0)) {
     103         164 :                                         is_zip = true;
     104             :                                 }
     105             :                         }
     106             : 
     107             :                         /* save classpath entries as absolute pathnames */
     108             : 
     109         327 :                         cwd = NULL;
     110         327 :                         cwdlen = 0;
     111             : 
     112         327 :                         if (*start != '/') {                      /* XXX fix me for win32 */
     113         164 :                                 cwd = os::getcwd();
     114         164 :                                 cwdlen = strlen(cwd) + strlen("/");
     115             :                         }
     116             : 
     117             :                         /* allocate memory for filename and fill it */
     118             : 
     119         327 :                         char *filename = MNEW(char, filenamelen + cwdlen + strlen("/") + strlen("0"));
     120             : 
     121         327 :                         if (cwd) {
     122         164 :                                 strcpy(filename, cwd);
     123         164 :                                 strcat(filename, "/");
     124         164 :                                 strncat(filename, start, filenamelen);
     125             : 
     126             :                                 /* add cwd length to file length */
     127         164 :                                 filenamelen += cwdlen;
     128             : 
     129             :                         } else {
     130         163 :                                 strncpy(filename, start, filenamelen);
     131         163 :                                 filename[filenamelen] = '\0';
     132             :                         }
     133             : 
     134         327 :                         if (is_zip) {
     135             : #if defined(ENABLE_ZLIB)
     136         164 :                                 if (ZipFile *zip = ZipFile::open(filename)) {
     137         164 :                                         list_classpath_entry *lce = NEW(list_classpath_entry);
     138             : 
     139         164 :                                         lce->type    = CLASSPATH_ARCHIVE;
     140         164 :                                         lce->zip     = zip;
     141         164 :                                         lce->path    = filename;
     142         164 :                                         lce->pathlen = filenamelen;
     143             : 
     144             :                                         /* SUN compatible -verbose:class output */
     145             : 
     146         164 :                                         if (opt_verboseclass)
     147           0 :                                                 printf("[Opened %s]\n", filename);
     148             : 
     149         164 :                                         push_back(lce);
     150             :                                 }
     151             : #else
     152             :                                 os::abort("suck_add: zip/jar files not supported");
     153             : #endif
     154             :                         }
     155             :                         else {
     156         163 :                                 if (filename[filenamelen - 1] != '/') {/* XXX fixme for win32 */
     157         163 :                                         filename[filenamelen] = '/';
     158         163 :                                         filename[filenamelen + 1] = '\0';
     159         163 :                                         filenamelen++;
     160             :                                 }
     161             : 
     162         163 :                                 list_classpath_entry *lce = NEW(list_classpath_entry);
     163             : 
     164         163 :                                 lce->type    = CLASSPATH_PATH;
     165         163 :                                 lce->path    = filename;
     166         163 :                                 lce->pathlen = filenamelen;
     167             : 
     168         163 :                                 push_back(lce);
     169             :                         }
     170             :                 }
     171             : 
     172             :                 /* goto next classpath entry, skip ':' delimiter */
     173             : 
     174         327 :                 if ((*end) == ':')
     175         164 :                         start = end + 1;
     176             :                 else
     177         163 :                         start = end;
     178             :         }
     179         163 : }
     180             : 
     181             : 
     182             : /**
     183             :  * Adds a classpath form a property entry to the global classpath
     184             :  * entries list.
     185             :  */
     186         163 : void SuckClasspath::add_from_property(const char *key)
     187             : {
     188             :         const char     *value;
     189             :         const char     *start;
     190             :         const char     *end;
     191             :         s4              pathlen;
     192             :         struct dirent **namelist;
     193             :         s4              n;
     194             :         s4              i;
     195             :         s4              namlen;
     196             :         char           *p;
     197         163 :         char* boot_class_path = NULL;
     198             : 
     199             :         // Get the property value.
     200         163 :         Properties& properties = VM::get_current()->get_properties();
     201         163 :         value = properties.get(key);
     202             : 
     203         163 :         if (value == NULL)
     204           0 :                 return;
     205             : 
     206             :         /* get the directory entries of the property */
     207             : 
     208         489 :         for (start = value; (*start) != '\0'; ) {
     209             : 
     210             :                 /* search for ':' delimiter to get the end of the current entry */
     211             : 
     212         163 :                 for (end = start; ((*end) != '\0') && ((*end) != ':'); end++);
     213             : 
     214             :                 /* found an entry */
     215             : 
     216         163 :                 if (start != end) {
     217             :                         /* allocate memory for the path entry */
     218             : 
     219         163 :                         pathlen = end - start;
     220         163 :                         char* path = MNEW(char, pathlen + strlen("0"));
     221             : 
     222             :                         /* copy and terminate the string */
     223             : 
     224         163 :                         strncpy(path, start, pathlen);
     225         163 :                         path[pathlen] = '\0';
     226             : 
     227             :                         /* Reset namelist to NULL for the freeing in an error case
     228             :                            (see below). */
     229             : 
     230         163 :                         namelist = NULL;
     231             : 
     232             :                         /* scan the directory found for zip/jar files */
     233             : 
     234         163 :                         n = os::scandir((const char*) path, &namelist, &scandir_filter, (int (*)(const void*, const void*)) &alphasort);
     235             : 
     236             :                         /* On error, just continue, this should be ok. */
     237             : 
     238         163 :                         if (n > 0) {
     239           0 :                                 for (i = 0; i < n; i++) {
     240             : #if defined(_DIRENT_HAVE_D_NAMLEN)
     241             :                                         namlen = namelist[i]->d_namlen;
     242             : #else
     243           0 :                                         namlen = strlen(namelist[i]->d_name);
     244             : #endif
     245             : 
     246           0 :                                         if (boot_class_path == NULL) {
     247             :                                                 /* Allocate memory for bootclasspath. */
     248             :                                                 p = MNEW(char,
     249             :                                                                  pathlen + strlen("/") + namlen +
     250           0 :                                                                  strlen("0"));
     251             : 
     252           0 :                                                 strcpy(p, path);
     253           0 :                                                 strcat(p, "/");
     254           0 :                                                 strcat(p, namelist[i]->d_name);
     255             : 
     256             :                                         } else {
     257             :                                                 /* Allocate memory for bootclasspath. */
     258             :                                                 p = MNEW(char,
     259             :                                                                  pathlen + strlen("/") + namlen +
     260             :                                                                  strlen(":") +
     261             :                                                                  strlen(boot_class_path) +
     262           0 :                                                                  strlen("0"));
     263             : 
     264             :                                                 /* Append the file found to the bootclasspath. */
     265             : 
     266           0 :                                                 strcpy(p, boot_class_path);
     267           0 :                                                 strcat(p, ":");
     268           0 :                                                 strcat(p, path);
     269           0 :                                                 strcat(p, "/");
     270           0 :                                                 strcat(p, namelist[i]->d_name);
     271             : 
     272           0 :                                                 MFREE(boot_class_path, char, strlen(boot_class_path));
     273             :                                         }
     274             : 
     275           0 :                                         boot_class_path = p;
     276             : 
     277             :                                         /* free the memory allocated by scandir */
     278             :                                         /* (We use `free` as the memory came from the C library.) */
     279             : 
     280           0 :                                         free(namelist[i]);
     281             :                                 }
     282             :                         }
     283             : 
     284             :                         /* On some systems (like Linux) when n == 0, then namelist
     285             :                            returned from scnadir is NULL, thus we don't have to
     286             :                            free it.
     287             :                            (Use `free` as the memory came from the C library.) */
     288             : 
     289         163 :                         if (namelist != NULL)
     290           0 :                                 free(namelist);
     291             : 
     292         163 :                         MFREE(path, char, pathlen + strlen("0"));
     293             :                 }
     294             : 
     295             :                 /* goto next entry, skip ':' delimiter */
     296             : 
     297         163 :                 if ((*end) == ':')
     298           0 :                         start = end + 1;
     299             :                 else
     300         163 :                         start = end;
     301             :         }
     302             : 
     303         163 :         if (boot_class_path != NULL) {
     304             :                 // only update if something has changed
     305             : 
     306             :                 // FIXME Make boot_class_path const char*.
     307           0 :                 char* old_boot_class_path = (char*) properties.get("sun.boot.class.path");
     308             : 
     309             :                 p = MNEW(char,
     310             :                                  strlen(boot_class_path) +
     311             :                                  strlen(":") +
     312             :                                  strlen(old_boot_class_path) +
     313           0 :                                  strlen("0"));
     314             : 
     315             :                 /* Prepend the file found to the bootclasspath. */
     316             : 
     317           0 :                 strcpy(p, boot_class_path);
     318           0 :                 strcat(p, ":");
     319           0 :                 strcat(p, old_boot_class_path);
     320             : 
     321           0 :                 MFREE(boot_class_path, char, strlen(boot_class_path));
     322           0 :                 MFREE(old_boot_class_path, char, strlen(old_boot_class_path));
     323             : 
     324             :                 /* Prepend the file found to the bootclasspath. */
     325           0 :                 properties.put("sun.boot.class.path", p);
     326           0 :                 properties.put("java.boot.class.path", p);
     327             :         }
     328             : 
     329             : }
     330             : 
     331             : 
     332       71705 : inline void ClassBuffer::init(classinfo *clazz, uint8_t *data, size_t sz, const char *path) {
     333       71705 :         this->clazz = clazz;
     334       71705 :         this->data  = data;
     335       71705 :         this->pos   = data;
     336       71705 :         this->end   = data + sz;
     337       71705 :         this->path  = path;
     338       71705 : }
     339             : 
     340         644 : ClassBuffer::ClassBuffer(classinfo *clazz, uint8_t *data, size_t sz, const char *path) {
     341         644 :         init(clazz, data, sz, path);
     342         644 : }
     343             : 
     344           0 : ClassFileVersion ClassBuffer::version() const { return clazz->version; }
     345             : 
     346             : /***
     347             :  *      Loads class file corresponding to given classinfo into new ClassBuffer.
     348             :  *      All directories of the searchpath are used to find the classfile (<classname>.class).
     349             :  *    Use operator bool to check if initialization was successfull.
     350             :  */
     351       35915 : ClassBuffer::ClassBuffer(classinfo *c) {
     352       35915 :         init(NULL, NULL, 0, NULL);
     353             : 
     354             :         // get the classname as char string 
     355             :         // (do it here for the warning at the end of the function)
     356             : 
     357       35915 :         size_t filenamelen = c->name.size() + strlen(".class") + strlen("0");
     358             : 
     359       35915 :         Buffer<> filename(filenamelen);
     360       35915 :         Buffer<> path;
     361             : 
     362             :         filename.write(c->name)
     363       35915 :                 .write(".class");
     364             : 
     365             :         // Get current list of classpath entries.
     366       35915 :         SuckClasspath& suckclasspath = VM::get_current()->get_suckclasspath();
     367             : 
     368             :         // walk through all classpath entries
     369             : 
     370       70178 :         for (SuckClasspath::iterator it = suckclasspath.begin(); it != suckclasspath.end(); it++) {
     371       69409 :                 list_classpath_entry *lce = *it;
     372             : 
     373             : #if defined(ENABLE_ZLIB)
     374       69409 :                 if (lce->type == CLASSPATH_ARCHIVE) {
     375             : 
     376             :                         // enter a monitor on zip/jar archives
     377       33494 :                         MutexLocker lock(*lce->mutex);
     378             : 
     379             :                         // try to get the file in current archive
     380       33494 :                         if (ZipFile::EntryRef zip = lce->zip->find(c->name)) {
     381             :                                 // found class, fill in classbuffer
     382       32723 :                                 size_t   size = zip->uncompressedsize;
     383       32723 :                                 uint8_t *data = MNEW(uint8_t, size);
     384             : 
     385       32723 :                                 zip->get(data);
     386             : 
     387       32723 :                                 init(c, data, size, lce->path);
     388             :                                 return;
     389           0 :                         }
     390             :                 } else {
     391             : #endif /* defined(ENABLE_ZLIB) */
     392       35915 :                         path.reset();
     393             : 
     394             :                         path.write(lce->path)
     395       35915 :                             .write(filename);
     396             : 
     397       35915 :                         if (FILE *classfile = os::fopen(path.c_str(), "r")) {
     398             :                                 struct stat stat_buffer;
     399             : 
     400        2423 :                                 if (os::stat(path.c_str(), &stat_buffer) == -1)
     401           0 :                                         continue;
     402             : 
     403        2423 :                                 size_t   size = stat_buffer.st_size;
     404        2423 :                                 uint8_t *data = MNEW(u1, size);
     405             : 
     406             :                                 // read class data
     407        2423 :                                 size_t bytes_read = os::fread(data, 1, size, classfile);
     408        2423 :                                 os::fclose(classfile);
     409             : 
     410        2423 :                                 if (bytes_read != size) {
     411           0 :                                         free();
     412             :                                         return;
     413             :                                 }
     414             : 
     415        2423 :                                 init(c, data, size, lce->path);
     416             :                                 return;
     417             :                         }
     418             : #if defined(ENABLE_ZLIB)
     419             :                 }
     420             : #endif
     421             :         }
     422             : 
     423             :         // if we get here, we could not find the file
     424         769 :         if (opt_verbose)
     425           0 :                 dolog("Warning: Can not open class file '%s'", filename.c_str());
     426             : }
     427             : 
     428             : 
     429             : /* suck_stop *******************************************************************
     430             : 
     431             :    Frees memory for buffer with classfile data.
     432             : 
     433             :    CAUTION: This function may only be called if buffer has been
     434             :    allocated by suck_start with reading a file.
     435             :         
     436             : *******************************************************************************/
     437             : 
     438       35146 : void ClassBuffer::free() {
     439             :         // free memory
     440             : 
     441       35146 :         MFREE(data, u1, end - data);
     442       35146 : }
     443             : 
     444             : 
     445             : /*
     446             :  * These are local overrides for various environment variables in Emacs.
     447             :  * Please do not remove this and leave it at the end of the file, where
     448             :  * Emacs will automagically detect them.
     449             :  * ---------------------------------------------------------------------
     450             :  * Local variables:
     451             :  * mode: c++
     452             :  * indent-tabs-mode: t
     453             :  * c-basic-offset: 4
     454             :  * tab-width: 4
     455             :  * End:
     456             :  * vim:noexpandtab:sw=4:ts=4:
     457             :  */

Generated by: LCOV version 1.11